You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 705a4f1
Browse filesBrowse the repository at this point in the historyBrowse files
settings-as-code-release
committed
feat(cli): github-settings-as-code and gsac commands over the library
The npm package gains a command line built by tsdown from src/cli.ts to lib/pkg/cli.js, with the bin names github-settings-as-code and gsac. It is a second consumer of the public entry: the new cli layer in architecture.yml has the action's one edge, src/index.ts.
check, apply, and merge mirror the action's modes: the subcommand is the mode input and every other input the mode reads is a --kebab-case flag generated from INPUT_DECLS, so the help text and the inputs reference share one declaration. The read port is built from commander's parsed options and handed to the library's parseConfig, and test/cli/inputs.test.ts pins argv-to-config equal to a record-backed port shaped like the runner's, over every RunConfig arm and the rejections. validate and permissions read a settings file alone; snapshot and init name the snapshot mode this library build does not carry and exit 1.
The Io over consola prints annotations to stderr as level: message, log lines to stdout, outputs as name=value lines or one JSON object under --json, and appends the summary to --summary's file; every channel is masked, and the token is registered before anything can echo it.
Packaging: bin in package.json, the three runtime dependencies pinned, a second tsdown entry, the package smoke running the installed gsac --help and validate under Node, and the changed-sections selector listing the cli paths. The smoke's consumers read validateSettings as the Result it returns on this base.
Docs: docs/start/cli.md, a CLI section in the library reference, the README paragraph and table row, and the AGENTS.md bullet for the layer.
- `lib/settings.schema.json` is the COMMITTED JSON Schema for settings.yml, generated from the zod slices in `src/sections/<key>/schema.ts` as composed into the settings document by `src/schema.ts`. Each slice is ONE declaration that produces its config type (z.infer), the section's tolerant runtime shape (the section module derives `loosen(<slice>)` itself; the factory-minted families - secrets, variables, the two setup sections, and the list sections on `listSection` - get it from their shared factory in `src/sections/shared/`, which does that derivation once), and its part of the published schema (`.meta({id})` names its definitions; the descriptions come from the `schema:` map in the section's `<key>.docs.yml`, keyed `Definition.field`, which the generator attaches and fails on when a site or a key is unmatched); `src/schema.ts` adds only the document-level wrappers and pins each property to its slice with a lockstep type. Regenerate the schema with `bun run build:schema` after a schema-affecting `src/` change - CI's schema-check job fails when it drifts. `lib/index.js`, the bundled entrypoint the action runs (node24), is NOT committed on main: every workflow that executes the action builds it first (`bun run build:bundle`), the e2e runner builds it to a temp path, and a release builds and commits it on a packaged child of the release commit, which is what every `vX.Y.Z` tag and the moving major point at (main itself stays source-only). `lib/` is exempt from the typography check (third-party unicode in the bundle; the schema descriptions are checked at source) and excluded from [biome](https://biomejs.dev).
38
38
- `lib/pkg/` is the npm library build: `bun run build:lib` (tsdown, configured in `tsdown.config.ts`) bundles `src/index.ts` into one ESM `index.js` plus one `index.d.ts` with the runtime dependencies external; like `lib/index.js` it is built, never committed. `package.json` publishes it as `@vivswan/github-settings-as-code` through its `exports` map (`.` to the build, `./settings.schema.json` to the committed schema, `./package.json` to itself; `files` ships only those plus LICENSE.md and README.md), and `test/package-json.test.ts` pins the manifest's field set and holds its `version` equal to `.release-please-manifest.json` (release-please's json extra-file rewrites it). The package-smoke job in `checks.yml` (`bun .github/scripts/package-smoke.ts`) builds the library, runs publint and attw, installs the packed tarball into a fresh consumer, and imports it under Node and under tsc with skipLibCheck off, so a declaration that leaks a devDependency type or a type the emitter cannot name fails there; a type a section module exposes must therefore be exported from its home module. The library reference is docs/reference/library.md.
39
+
-`src/cli.ts` and `src/cli/` are the command line, a second CONSUMER of the public entry with the action's one edge, `../index.js`:
40
+
a capability the CLI needs is exported from `src/index.ts` first, and `test/cli/inputs.test.ts` pins its argv-to-config equal to the action's env-to-config. Guide: docs/start/cli.md.
39
41
- The import layering of `src/` is declared in `architecture.yml` and enforced by `bun run lint:arch`, so a new cross-layer import is a deliberate edit to that file; the module map in `docs/reference/architecture.md` is generated from it.
40
42
- The apply/check engine layout: `src/main.ts` is the thin bundled entrypoint; `src/index.ts` is the public entry (declaration-only re-exports, pinned by test/library/public-surface.test.ts); `src/action/` is the GitHub Actions layer and a CONSUMER of that entry: its only import outside itself is `../index.js`, the one edge `architecture.yml` grants it; `src/flows/` holds the run flows the action and a library caller share (single, multi, merge, delivery, redaction); `src/io.ts` is the import-free Io output port; `src/types.ts` holds the leaf type vocabulary; `src/engine/` is the per-repo pipeline (orchestrate, validate, merge, diff, secret references); `src/github/` is the REST client, pagination, and repo-file fetch; `src/discovery/` resolves multi-repo targets; `src/report/` composes and delivers the private report. Under `src/sections/`, each settings section is one self-contained DIRECTORY `src/sections/<key>/`: `index.ts` (the `SectionModule` - key, PAT grant advice, the loose shape derived from the slice, handler), `schema.ts` (the zod slice), `mock.ts` (the e2e mock fragment), `generators.ts` (the fuzz fragment; the secret and variable factory families share theirs in `test/e2e/generators.ts` instead), `<key>.test.ts` (absent where a shared factory's suite under `test/sections/` covers the section), and `scenarios/`. Beside the section directories sit `contract/` (the layered section contract: permissions/endpoints/graphql/module/errors/requests/live), `shared/` (the cross-section engines and factories, plus the schema helpers), and `registry.ts` (the single registration point). All GitHub API list calls must go through `listAll()` (bare-array endpoints) or `listAllEnveloped()` (endpoints that wrap the list in a `{total_count, <key>: []}` envelope), both backed by the single page loop in `src/github/paginate.ts`; errors through `call()`/`throwFor()` so the permission policy (`on-missing-permission`, `required-sections`) works.
41
43
- Adding a section: create `src/sections/<key>/` with the six pieces above plus its `<key>.docs.yml` (the Sections table cells for docs/reference/sections.md, the COVERAGE.md prose, and the schema descriptions the generators render; the docs loader fails without it), compose the `SettingsFile` property from the slice and add the key to `SECTION_KEYS` in `src/schema.ts`, and add one line in `src/sections/registry.ts` - the compiler flags each forgotten step (the registry's mapped type, the mock fragment registration, the slice composition pin, and the generator aggregation are all keyed by SectionKey).
Copy file name to clipboardExpand all lines: README.md
+3Lines changed: 3 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -63,6 +63,8 @@ The [getting started guide](docs/start/getting-started.md) walks the same steps
63
63
64
64
The same engine is the npm package `@vivswan/github-settings-as-code` (ESM, Node 22.14 or newer): validate, merge, check, and apply from your own code. It is built from this repository with `bun run build:lib`; the [library reference](docs/reference/library.md) has the API by group.
65
65
66
+
The package is also a command: `npx @vivswan/github-settings-as-code@next check --repository o/r --settings-file .github/settings.yml`runs the action's check from a terminal; the [command line guide](docs/start/cli.md) has every command.
67
+
66
68
## Docs
67
69
68
70
| Goal | Read |
@@ -85,6 +87,7 @@ The same engine is the npm package `@vivswan/github-settings-as-code` (ESM, Node
85
87
| Move a pin to a new major | [Upgrading](docs/upgrading/README.md) |
86
88
| See how the code is laid out | [Architecture](docs/reference/architecture.md) |
87
89
| Use the engine from your own code | [Library](docs/reference/library.md) |
90
+
| Run check, apply, or validate from a terminal | [Command line](docs/start/cli.md) |
Copy file name to clipboardExpand all lines: docs/README.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -19,6 +19,7 @@ The documentation for GitHub Settings as Code, in five groups. Start here if the
19
19
| Predict what an apply or a check will do |[reference/semantics.md](reference/semantics.md)|
20
20
| See how the action works, module by module |[reference/architecture.md](reference/architecture.md)|
21
21
| Use the engine from your own code |[reference/library.md](reference/library.md)|
22
+
| Run check, apply, or validate from a terminal |[start/cli.md](start/cli.md)|
22
23
| Detect drift on a schedule |[operate/check-mode.md](operate/check-mode.md)|
23
24
| Fold several settings files into one |[operate/layering.md](operate/layering.md)|
24
25
| Manage a fleet from one repository |[operate/multi-repo.md](operate/multi-repo.md)|
@@ -32,6 +33,7 @@ The documentation for GitHub Settings as Code, in five groups. Start here if the
32
33
-[Getting started](start/getting-started.md): create the PAT, add the workflow, run your first check, and read the drift output.
33
34
-[Migrating from the Probot Settings app](start/migrating-from-probot.md): the step-by-step move, including the parts that changed on purpose and an org-scale shadow run.
34
35
-[Examples](start/examples.md): a settings.yml cookbook, from a minimal file to a full-featured one, including what `null` means where it is meaningful.
36
+
-[Command line](start/cli.md): the `github-settings-as-code` and `gsac` commands in the npm package, one per action mode plus `validate` and `permissions`, their flags, outputs, and exit codes.
The package's `bin` entries, `github-settings-as-code` and `gsac`, run the same flows from a terminal: `check`, `apply`, and `merge` take the action's inputs as `--flags`,
152
+
and `validate` and `permissions` read a settings file alone. The [command line guide](../start/cli.md) has every command, the flag rule, and the exit codes.
153
+
149
154
## Versioning
150
155
151
156
The package and the action share one version, the one in `.release-please-manifest.json` (release-please rewrites `package.json` from it), so a settings file that validates on the library validates on the action of the same version.
0 commit comments