@grimoire-rs/indexer 0.2.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +59 -18
  2. package/dist/ci.d.ts +149 -0
  3. package/dist/ci.d.ts.map +1 -0
  4. package/dist/ci.js +338 -0
  5. package/dist/ci.js.map +1 -0
  6. package/dist/cli/build.d.ts.map +1 -1
  7. package/dist/cli/build.js +3 -9
  8. package/dist/cli/build.js.map +1 -1
  9. package/dist/cli/ci.d.ts +6 -0
  10. package/dist/cli/ci.d.ts.map +1 -0
  11. package/dist/cli/ci.js +43 -0
  12. package/dist/cli/ci.js.map +1 -0
  13. package/dist/cli/dev.d.ts +7 -0
  14. package/dist/cli/dev.d.ts.map +1 -0
  15. package/dist/cli/dev.js +57 -0
  16. package/dist/cli/dev.js.map +1 -0
  17. package/dist/cli/init.d.ts +18 -2
  18. package/dist/cli/init.d.ts.map +1 -1
  19. package/dist/cli/init.js +584 -100
  20. package/dist/cli/init.js.map +1 -1
  21. package/dist/cli/main.d.ts.map +1 -1
  22. package/dist/cli/main.js +71 -10
  23. package/dist/cli/main.js.map +1 -1
  24. package/dist/cli/out_dir.d.ts +11 -0
  25. package/dist/cli/out_dir.d.ts.map +1 -0
  26. package/dist/cli/out_dir.js +30 -0
  27. package/dist/cli/out_dir.js.map +1 -0
  28. package/dist/cli/validate.d.ts +1 -0
  29. package/dist/cli/validate.d.ts.map +1 -1
  30. package/dist/cli/validate.js +47 -1
  31. package/dist/cli/validate.js.map +1 -1
  32. package/dist/renderer/astro/components/BrandMark.js +0 -1
  33. package/dist/renderer/astro/components/Catalog.js +0 -1
  34. package/dist/renderer/astro/lib/base.js +0 -1
  35. package/dist/renderer/astro/lib/catalog.js +0 -1
  36. package/dist/renderer/astro/lib/code.js +0 -1
  37. package/dist/renderer/astro/lib/data.js +0 -1
  38. package/dist/renderer/index.d.ts.map +1 -1
  39. package/dist/renderer/index.js +16 -0
  40. package/dist/renderer/index.js.map +1 -1
  41. package/dist/templates.d.ts +12 -0
  42. package/dist/templates.d.ts.map +1 -0
  43. package/dist/templates.js +40 -0
  44. package/dist/templates.js.map +1 -0
  45. package/dist/validate/adapters/files.d.ts.map +1 -1
  46. package/dist/validate/adapters/files.js +13 -3
  47. package/dist/validate/adapters/files.js.map +1 -1
  48. package/dist/validate/index.js +17 -2
  49. package/dist/validate/index.js.map +1 -1
  50. package/package.json +2 -2
  51. package/templates/README.md +115 -19
  52. package/templates/ci/github-automerge.yml +36 -0
  53. package/templates/ci/github-enrich.yml +27 -0
  54. package/templates/ci/github-pages.yml +64 -0
  55. package/templates/ci/github-publish.yml +89 -0
  56. package/templates/ci/github-validate.yml +157 -0
  57. package/templates/ci/github-verify-ci.yml +47 -0
  58. package/templates/ci/gitlab-ci.yml +149 -0
  59. package/templates/ci/gitlab-enrich.sh +26 -0
  60. package/templates/ci/gitlab-publish.yml +50 -0
  61. package/templates/ci/gitlab-verify.yml +16 -0
  62. package/templates/ci/header.txt +19 -0
  63. package/templates/gitattributes +4 -0
  64. package/templates/gitignore +7 -2
  65. package/templates/package.json +18 -0
  66. package/templates/publish.toml +2 -2
  67. package/dist/renderer/astro/components/BrandMark.d.ts.map +0 -1
  68. package/dist/renderer/astro/components/BrandMark.js.map +0 -1
  69. package/dist/renderer/astro/components/Catalog.d.ts.map +0 -1
  70. package/dist/renderer/astro/components/Catalog.js.map +0 -1
  71. package/dist/renderer/astro/lib/base.d.ts.map +0 -1
  72. package/dist/renderer/astro/lib/base.js.map +0 -1
  73. package/dist/renderer/astro/lib/catalog.d.ts.map +0 -1
  74. package/dist/renderer/astro/lib/catalog.js.map +0 -1
  75. package/dist/renderer/astro/lib/code.d.ts.map +0 -1
  76. package/dist/renderer/astro/lib/code.js.map +0 -1
  77. package/dist/renderer/astro/lib/data.d.ts.map +0 -1
  78. package/dist/renderer/astro/lib/data.js.map +0 -1
  79. package/templates/github-pages.yml +0 -24
  80. package/templates/github-validate.yml +0 -51
  81. package/templates/gitlab-ci.yml +0 -13
  82. package/templates/reusable/gitlab-index-ci.yml +0 -125
package/README.md CHANGED
@@ -6,20 +6,33 @@ servers, and bundles available in one or more OCI registries.
6
6
 
7
7
  ## Subcommands
8
8
 
9
- - `grim-indexer init` — scaffold a new index repo (`index/**` content
10
- tree, Astro site config, CI workflow).
9
+ - `grim-indexer init` — scaffold a new index repo: the `index/**` content
10
+ tree, site config, a `package.json` that pins this package, and the CI
11
+ its forge runs.
12
+ - `grim-indexer dev` — serve the index locally, through the same renderer
13
+ `build` uses. The review loop for an entry or a branding change.
11
14
  - `grim-indexer enrich` — refresh `enrich/**` from the registry: READMEs,
12
15
  changelogs, logos, versions and tag lists. The only step that goes
13
16
  online, and the only one that needs `grim` on `PATH`.
14
17
  - `grim-indexer build` — render `index/**` into a static site.
15
18
  - `grim-indexer validate` — CI gate for contribution PRs/MRs against an
16
19
  index repo.
20
+ - `grim-indexer ci` — render the index repo's workflows from the `ci`
21
+ block of its `index.config.json`; `--check` verifies the committed ones
22
+ still match and exits 65 on drift.
23
+
24
+ A scaffolded index owns its CI: the workflow files are committed in that
25
+ repository and run `npm ci` against its own lockfile, so nothing is
26
+ fetched from here at run time and the version that builds an index is the
27
+ one that repo has locked. The generated `verify-ci` job re-renders and
28
+ diffs on every push, which is what keeps a hand-edit from silently
29
+ forking the pipeline.
17
30
 
18
31
  An index stores nothing but pointers — a ref and who owns it. Everything a
19
32
  reader looks at lives in the registry, so an index that never runs `enrich`
20
33
  renders a catalogue of names with *No README available* on every page. The
21
- scaffolded CI runs it before each build; set `enrich: false` (GitHub) or
22
- `GRIM_INDEXER_ENRICH: "false"` (GitLab) for a pointers-only site.
34
+ scaffolded CI runs it before each build; set `"enrich": false` in the `ci`
35
+ block for a pointers-only site.
23
36
 
24
37
  ## Install
25
38
 
@@ -30,10 +43,24 @@ npm install --save-dev @grimoire-rs/indexer
30
43
  ## Usage
31
44
 
32
45
  ```sh
33
- npx @grimoire-rs/indexer init
34
- npx @grimoire-rs/indexer enrich # needs `grim` on PATH
35
- npx @grimoire-rs/indexer build
36
- npx @grimoire-rs/indexer validate
46
+ npx @grimoire-rs/indexer init # scaffold; writes package.json + lockfile
47
+ ```
48
+
49
+ Or start from [`grimoire-rs/index-template`](https://github.com/grimoire-rs/index-template):
50
+ "Use this template", clone, then `npm install && npm run setup` — which is
51
+ `init` run in place, so it reads your `origin` remote and already knows the
52
+ forge and the Pages URL.
53
+
54
+ Everything after that runs through the scaffolded repo's own scripts, so it
55
+ uses the version that repo locked:
56
+
57
+ ```sh
58
+ npm run dev # local preview
59
+ npm run build # index/** -> dist/
60
+ npm run enrich # needs `grim` on PATH
61
+ npm run validate # the contribution gate
62
+ npm run ci # re-render CI after editing index.config.json
63
+ npm run ci:check # fail on drift (what the verify-ci job runs)
37
64
  ```
38
65
 
39
66
  As an Astro integration:
@@ -60,9 +87,11 @@ unreachable OCI ref, unowned namespace).
60
87
 
61
88
  Two things that trial settled, both worth knowing before you scaffold:
62
89
 
63
- - **Requiring the gate needs the check named `validate / validate`**, not
64
- `validate`. Requiring a context that never reports blocks every PR
65
- forever and looks exactly like the gate rejecting your contribution.
90
+ - **Require the check named `validate`.** It was `validate / validate`
91
+ while the scaffold emitted thin callers of reusable workflows; the
92
+ workflow is now committed in the index repo, so the context is just the
93
+ job key. Requiring a context that never reports blocks every PR forever
94
+ and looks exactly like the gate rejecting your contribution.
66
95
  - **In the combined (`--with-skills`) layout the gate does not cover your
67
96
  own CI's announce.** GitHub runs no workflows on a PR opened with
68
97
  `secrets.GITHUB_TOKEN`, so that PR arrives ungated — review it by hand.
@@ -70,8 +99,8 @@ Two things that trial settled, both worth knowing before you scaffold:
70
99
  requests" enabled, which is off by default and which also lets
71
100
  workflows approve PRs.
72
101
 
73
- Not yet proven live: the GitLab leg (hermetic tests only; the
74
- `include: remote:` URL is verified to resolve), and the cross-repository
102
+ Not yet proven live: the GitLab leg (hermetic unit tests only - no live
103
+ GitLab pipeline has run the rendered CI), and the cross-repository
75
104
  announce, which needs a credential beyond the CI token.
76
105
 
77
106
  Two things are frozen and safe to build on: the published URL layout
@@ -83,13 +112,25 @@ is deliberately no component-override API yet — publishing one would
83
112
  freeze a prop contract per slot, and that is not a promise worth making
84
113
  this early.
85
114
 
86
- > **Use `0.1.4` or later.** `0.1.0` installs without an executable npm
115
+ > **Use `0.1.4` or later.** `0.1.0` installs without an executable - npm
87
116
  > silently stripped its `bin` entry at publish time. `0.1.1` and `0.1.2`
88
117
  > scaffold CI that points at reusable workflows those tags do not contain,
89
- > so the first push to a scaffolded index fails before any job runs. An
90
- > index already scaffolded against `0.1.1`/`0.1.2` is fixed by bumping the
91
- > `@v0.1.x` refs in `.github/workflows/{pages,validate}.yml` no
92
- > re-scaffold needed.
118
+ > so the first push to a scaffolded index fails before any job runs.
119
+ >
120
+ > An index already scaffolded against a reusable-workflow version keeps
121
+ > working as long as its pinned `uses:`/`include:` refs stay on an existing
122
+ > tag - old tags are not deleted, so that resolution does not break on its
123
+ > own. It breaks the moment something bumps the pinned ref, because `main`
124
+ > no longer defines any reusable workflow or remote include for it to
125
+ > resolve to: a Renovate update of an `@grimoire-rs/indexer` action ref
126
+ > will now fail hard. Fix it before that happens by adding a `package.json`
127
+ > pinning this package (if the old scaffold has none) and running
128
+ > `npm run ci`, which re-renders the workflow files and nothing else.
129
+ > **Not `init --force`**: that rewrites the whole scaffold from its
130
+ > templates, discarding the added scripts in `package.json`, your
131
+ > `.gitignore` rules, your `README.md`, and any `uses:` pin Renovate has
132
+ > bumped since - `npm run ci` keeps all four. `publish.toml` and
133
+ > `index-policy.json` are never rewritten, by `--force` or anything else.
93
134
  >
94
135
  > Through `0.1.3`, `init --with-skills` wrote a `publish.toml` with no
95
136
  > `[announce]` table, so `grim publish --announce` in a combined-layout
package/dist/ci.d.ts ADDED
@@ -0,0 +1,149 @@
1
+ import { CliError } from "./cli/exit.js";
2
+ /**
3
+ * Forges CI can be rendered for. One repository is hosted on one forge, so
4
+ * this is a choice rather than a set — rendering both left every index with a
5
+ * pipeline it would never run, and a second gate to keep honest for nothing.
6
+ */
7
+ export type Forge = "github" | "gitlab";
8
+ export declare const FORGES: readonly Forge[];
9
+ /**
10
+ * When the combined layout publishes its own packages.
11
+ *
12
+ * `never` is the default and the only correct answer for a plain index, which
13
+ * holds pointers and owns no packages to push. The other two are the two
14
+ * release habits: cut a tag when a version is ready, or treat every merge to
15
+ * the default branch as a release and let skip-existing make the re-run a
16
+ * no-op.
17
+ */
18
+ export type PublishTrigger = "never" | "tag" | "default-branch";
19
+ export declare const PUBLISH_TRIGGERS: readonly PublishTrigger[];
20
+ /**
21
+ * The `ci` block of `index.config.json` — everything that varies the
22
+ * generated pipeline. Every key is optional; [`resolveCi`] fills the gaps.
23
+ */
24
+ export interface CiConfig {
25
+ /** Which forge's CI to render. Default `github`. */
26
+ forge?: Forge;
27
+ /**
28
+ * The branch the pipeline treats as the trunk — what deploys Pages, and what
29
+ * `publish: "default-branch"` releases from. Default `main`, which is what
30
+ * `init` creates and what every generated GitHub workflow assumed before
31
+ * this key existed.
32
+ *
33
+ * GitHub has no expression for it in an `on:` trigger, so it has to be a
34
+ * literal; a repository whose trunk is `master` had no way to say so and
35
+ * silently got workflows that never fired. GitLab reads `$CI_DEFAULT_BRANCH`
36
+ * at run time and ignores this.
37
+ */
38
+ defaultBranch?: string;
39
+ /**
40
+ * Publish this repository's own packages from CI, and announce them into the
41
+ * index beside them — the combined layout that `init --with-skills`
42
+ * scaffolds. Default `never`: a plain index owns no packages.
43
+ *
44
+ * `tag` fires on `v*` tags, `default-branch` on every push to the trunk.
45
+ * Either way `grim publish` skips versions the registry already has, so a
46
+ * re-run over unchanged packages pushes nothing.
47
+ */
48
+ publish?: PublishTrigger;
49
+ /** Node.js the jobs run on — `setup-node` version, and the GitLab image tag. Default `22`. */
50
+ nodeVersion?: string;
51
+ /**
52
+ * Refresh READMEs, changelogs, logos and version lists from the registry
53
+ * before building. `false` renders the enrichment steps away entirely, for
54
+ * a pointers-only site whose build never leaves the runner. Default `true`.
55
+ */
56
+ enrich?: boolean;
57
+ /** grim release the enrichment step reads the registry with — `latest` or a tag. Default `latest`. */
58
+ grimVersion?: string;
59
+ /**
60
+ * Squash-merge a pull request the gate passed, then deploy. Default `false`:
61
+ * merging an untrusted contribution unattended is a policy this package will
62
+ * not assume on a repository's behalf.
63
+ *
64
+ * GitHub only, and deliberately. GitHub always runs the base branch's copy
65
+ * of a `pull_request_target` workflow, so the gate a pull request faces is
66
+ * one it cannot edit. GitLab has no equivalent — the merge request supplies
67
+ * its own `.gitlab-ci.yml`, and a fork's pipeline runs in the fork — so an
68
+ * auto-merge there would act on a verdict the contributor could write.
69
+ */
70
+ autoMerge?: boolean;
71
+ /**
72
+ * Own these files by hand. The `verify-ci` drift guard is then not emitted,
73
+ * `ci --check` is the only thing left that would notice an edit, and CI
74
+ * fixes stop arriving by re-render. Discouraged, and deliberately not the
75
+ * default — but it is the repository's CI, so it is the repository's call.
76
+ */
77
+ allowManualEdits?: boolean;
78
+ }
79
+ export type ResolvedCiConfig = Required<CiConfig>;
80
+ /** Fill every gap from the defaults documented on [`CiConfig`]. */
81
+ export declare function resolveCi(ci: CiConfig | undefined): ResolvedCiConfig;
82
+ /** Validate the `ci` block of an already-parsed config object. */
83
+ export declare function validateCi(raw: unknown): CiConfig;
84
+ /** Read the `ci` block out of `index.config.json`. A missing file means defaults. */
85
+ export declare function loadCiConfig(root: string): Promise<CiConfig>;
86
+ /**
87
+ * First line of every file this renderer writes. Stale detection keys on it,
88
+ * so a repository's hand-written workflows are never mistaken for ours.
89
+ *
90
+ * Deliberately carries no version stamp. The version that renders these files
91
+ * is the one in the repository's own `package-lock.json`; stamping it here too
92
+ * would be a second copy that goes stale, and every dependency bump would red
93
+ * the drift guard until somebody re-rendered a file whose content had not
94
+ * changed.
95
+ */
96
+ export declare const GENERATED_HEADER = "# Generated by @grimoire-rs/indexer";
97
+ /**
98
+ * Render the complete CI file set. Nothing touches disk — the caller writes
99
+ * it or diffs it against what is committed.
100
+ */
101
+ export declare function renderCi(ci: ResolvedCiConfig): Map<string, string>;
102
+ /**
103
+ * Canonicalize a generated file for drift comparison.
104
+ *
105
+ * The index repository owns the *pin* on every `uses:` action reference —
106
+ * its own Renovate or Dependabot will bump `uses: owner/action@<ref> # vX`,
107
+ * and the guard must not read that as a hand-edit. Only the `@<ref>` suffix
108
+ * and any trailing version comment are stripped; `owner/action` survives, so
109
+ * swapping in a different action still trips drift.
110
+ */
111
+ export declare function normalizeForDrift(content: string): string;
112
+ /**
113
+ * Files on disk that carry our header but that the current config no longer
114
+ * renders — a `forge` narrowed from `both`, or `allowManualEdits` turned on
115
+ * after a guard was already committed. Reported, never deleted: removing a
116
+ * file from somebody's repository is their call, not the renderer's.
117
+ */
118
+ export declare function staleCi(root: string, files: Map<string, string>): Promise<string[]>;
119
+ export interface CiOutcome {
120
+ path: string;
121
+ /** `written` on a render; `drift`/`stale`/`ok` on a check. */
122
+ status: "written" | "unchanged" | "ok" | "drift" | "stale";
123
+ }
124
+ /**
125
+ * Write the rendered set, overwriting whatever is there.
126
+ *
127
+ * "Whatever is there" is judged through [`normalizeForDrift`], the same lens
128
+ * the guard uses — not raw bytes. Otherwise the two disagreed: `ci --check`
129
+ * deliberately tolerates a bumped `uses: owner/action@<ref>`, while a plain
130
+ * `npm run ci` rewrote it back to the pin baked into this package, silently
131
+ * undoing every Renovate bump the repository is told it may make. The repo
132
+ * owns its pins; a render must not take them back.
133
+ */
134
+ export declare function writeCi(root: string, files: Map<string, string>): Promise<CiOutcome[]>;
135
+ /**
136
+ * Compare the rendered set against what is committed. Missing counts as
137
+ * drift; a generated file the config no longer renders counts as stale.
138
+ * Hints are path-only — the contents of a repository's CI never go to stderr.
139
+ */
140
+ export declare function checkCi(root: string, files: Map<string, string>): Promise<CiOutcome[]>;
141
+ /**
142
+ * The re-render command a drift message tells the reader to run. It is the
143
+ * repository's own npm script, so it runs the renderer the lock pins rather
144
+ * than whatever `npx` would fetch today.
145
+ */
146
+ export declare const RE_RENDER_COMMAND = "npm run ci";
147
+ /** Turn a failed check into the error the CLI exits on. */
148
+ export declare function driftError(outcomes: CiOutcome[]): CliError;
149
+ //# sourceMappingURL=ci.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci.d.ts","sourceRoot":"","sources":["../src/ci.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,QAAQ,EAAQ,MAAM,eAAe,CAAC;AAI/C;;;;GAIG;AACH,MAAM,MAAM,KAAK,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAExC,eAAO,MAAM,MAAM,EAAE,SAAS,KAAK,EAAyB,CAAC;AAE7D;;;;;;;;GAQG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,KAAK,GAAG,gBAAgB,CAAC;AAEhE,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAAuC,CAAC;AAU9F;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,oDAAoD;IACpD,KAAK,CAAC,EAAE,KAAK,CAAC;IACd;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,8FAA8F;IAC9F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sGAAsG;IACtG,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAElD,mEAAmE;AACnE,wBAAgB,SAAS,CAAC,EAAE,EAAE,QAAQ,GAAG,SAAS,GAAG,gBAAgB,CAWpE;AAMD,kEAAkE;AAClE,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,QAAQ,CA+CjD;AAED,qFAAqF;AACrF,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkBlE;AAID;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,wCAAwC,CAAC;AA4CtE;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAmElE;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CASzD;AAED;;;;;GAKG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoBzF;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,8DAA8D;IAC9D,MAAM,EAAE,SAAS,GAAG,WAAW,GAAG,IAAI,GAAG,OAAO,GAAG,OAAO,CAAC;CAC5D;AAED;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAc5F;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAW5F;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,eAAe,CAAC;AAE9C,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,QAAQ,EAAE,SAAS,EAAE,GAAG,QAAQ,CAO1D"}
package/dist/ci.js ADDED
@@ -0,0 +1,338 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright 2026 The Grimoire Authors
3
+ // The CI renderer: `index.config.json`'s `ci` block in, complete workflow
4
+ // files out. The index repository owns and commits what it runs — there is no
5
+ // reusable workflow to call, no remote include to fetch, and nothing about the
6
+ // pipeline that lives anywhere but in the repository being pushed.
7
+ //
8
+ // The trade that buys is the drift guard: because the files are generated,
9
+ // `grim-indexer ci --check` can re-render and diff, and the generated
10
+ // `verify-ci` job runs exactly that on every push and pull request. So a
11
+ // hand-edit is caught rather than silently forked, while the repository keeps
12
+ // full ownership of its own CI — set `allowManualEdits` and the guard is not
13
+ // emitted at all.
14
+ import fs from "node:fs/promises";
15
+ import path from "node:path";
16
+ import { CliError, EXIT } from "./cli/exit.js";
17
+ import { CONFIG_FILE, SiteConfigError } from "./config.js";
18
+ import { fromTemplate } from "./templates.js";
19
+ export const FORGES = ["github", "gitlab"];
20
+ export const PUBLISH_TRIGGERS = ["never", "tag", "default-branch"];
21
+ /**
22
+ * Branch names are a permissive set — anything git accepts minus its own
23
+ * rules — but this one lands unquoted inside a YAML flow sequence, so it is
24
+ * bounded to what cannot restructure the document. Every real branch name
25
+ * fits; `refs/heads/` prefixes and quoting do not, which is the point.
26
+ */
27
+ const BRANCH = /^[A-Za-z0-9][\w./-]*$/;
28
+ /** Fill every gap from the defaults documented on [`CiConfig`]. */
29
+ export function resolveCi(ci) {
30
+ return {
31
+ forge: ci?.forge ?? "github",
32
+ defaultBranch: ci?.defaultBranch ?? "main",
33
+ nodeVersion: ci?.nodeVersion ?? "22",
34
+ enrich: ci?.enrich ?? true,
35
+ grimVersion: ci?.grimVersion ?? "latest",
36
+ allowManualEdits: ci?.allowManualEdits ?? false,
37
+ autoMerge: ci?.autoMerge ?? false,
38
+ publish: ci?.publish ?? "never",
39
+ };
40
+ }
41
+ function fail(msg) {
42
+ throw new SiteConfigError(`${CONFIG_FILE}: ci.${msg}`);
43
+ }
44
+ /** Validate the `ci` block of an already-parsed config object. */
45
+ export function validateCi(raw) {
46
+ if (raw === undefined || raw === null)
47
+ return {};
48
+ if (typeof raw !== "object" || Array.isArray(raw)) {
49
+ throw new SiteConfigError(`${CONFIG_FILE}: ci must be an object`);
50
+ }
51
+ const ci = raw;
52
+ if (ci.forge !== undefined && !FORGES.includes(ci.forge)) {
53
+ fail(`forge must be one of ${FORGES.join(", ")}`);
54
+ }
55
+ // These land inside a double-quoted shell word or a docker image tag in the
56
+ // generated YAML. The repository owner writes this file, so it is a paste
57
+ // guard rather than a trust boundary — but a value carrying a quote or a `$`
58
+ // would rewrite the command around it, and no version string needs either.
59
+ for (const key of ["nodeVersion", "grimVersion"]) {
60
+ const value = ci[key];
61
+ if (value !== undefined && typeof value !== "string")
62
+ fail(`${key} must be a string`);
63
+ if (typeof value === "string" && !/^[\w.@^~><=* +-]+$/.test(value)) {
64
+ fail(`${key} must be a plain version or range`);
65
+ }
66
+ }
67
+ for (const key of ["enrich", "allowManualEdits", "autoMerge"]) {
68
+ if (ci[key] !== undefined && typeof ci[key] !== "boolean")
69
+ fail(`${key} must be a boolean`);
70
+ }
71
+ if (ci.publish !== undefined && !PUBLISH_TRIGGERS.includes(ci.publish)) {
72
+ fail(`publish must be one of ${PUBLISH_TRIGGERS.join(", ")}`);
73
+ }
74
+ if (ci.defaultBranch !== undefined) {
75
+ if (typeof ci.defaultBranch !== "string")
76
+ fail("defaultBranch must be a string");
77
+ if (!BRANCH.test(ci.defaultBranch))
78
+ fail("defaultBranch must be a plain branch name");
79
+ // Slashes are legal in a branch name, so the charset check cannot catch
80
+ // this one. GitHub's `branches:` matches the short name; a full ref there
81
+ // is accepted by the YAML, matches nothing, and the workflow simply never
82
+ // fires — a silent failure worth one explicit line.
83
+ if (ci.defaultBranch.startsWith("refs/")) {
84
+ fail("defaultBranch must be the short branch name, not a full ref");
85
+ }
86
+ }
87
+ // Refused rather than ignored. Rendering GitLab CI while the config asks for
88
+ // auto-merge would leave a repository believing contributions land by
89
+ // themselves, and the honest answer is that they cannot be made to safely
90
+ // there — see the field's doc comment.
91
+ if (ci.autoMerge === true && ci.forge === "gitlab") {
92
+ fail("autoMerge is github-only - the GitLab gate cannot be made tamper-proof");
93
+ }
94
+ return ci;
95
+ }
96
+ /** Read the `ci` block out of `index.config.json`. A missing file means defaults. */
97
+ export async function loadCiConfig(root) {
98
+ let text;
99
+ try {
100
+ text = await fs.readFile(path.join(root, CONFIG_FILE), "utf8");
101
+ }
102
+ catch (err) {
103
+ if (err.code === "ENOENT")
104
+ return {};
105
+ throw err;
106
+ }
107
+ let parsed;
108
+ try {
109
+ parsed = JSON.parse(text);
110
+ }
111
+ catch (err) {
112
+ throw new SiteConfigError(`${CONFIG_FILE}: ${err.message}`);
113
+ }
114
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
115
+ throw new SiteConfigError(`${CONFIG_FILE}: must contain a JSON object`);
116
+ }
117
+ return validateCi(parsed.ci);
118
+ }
119
+ // ── Rendering ────────────────────────────────────────────────────────────────
120
+ /**
121
+ * First line of every file this renderer writes. Stale detection keys on it,
122
+ * so a repository's hand-written workflows are never mistaken for ours.
123
+ *
124
+ * Deliberately carries no version stamp. The version that renders these files
125
+ * is the one in the repository's own `package-lock.json`; stamping it here too
126
+ * would be a second copy that goes stale, and every dependency bump would red
127
+ * the drift guard until somebody re-rendered a file whose content had not
128
+ * changed.
129
+ */
130
+ export const GENERATED_HEADER = "# Generated by @grimoire-rs/indexer";
131
+ /**
132
+ * What CI scaffolded by a pre-header release (<= 0.2.2) looks like: a thin
133
+ * caller pointing back at this package's reusable workflow, or a GitLab
134
+ * remote include of the same. Those files carry no generated header, so
135
+ * without this the reaper was blind to exactly the repositories that most
136
+ * need telling — an index scaffolded with the old `--forge both` resolves to
137
+ * `forge: "github"` today (its config has no `ci` block at all) and would
138
+ * keep serving an orphaned `.gitlab-ci.yml` with nothing to say so.
139
+ */
140
+ const LEGACY_SIGNATURE = /uses:\s*grimoire-rs\/indexer\/\.github\/workflows\/|raw\.githubusercontent\.com\/grimoire-rs\/indexer\//;
141
+ /** Where each forge's files land. */
142
+ const GITHUB_FILES = {
143
+ pages: ".github/workflows/pages.yml",
144
+ validate: ".github/workflows/validate.yml",
145
+ verify: ".github/workflows/verify-ci.yml",
146
+ publish: ".github/workflows/publish.yml",
147
+ };
148
+ const GITLAB_FILE = ".gitlab-ci.yml";
149
+ /**
150
+ * Where the grim release tarball is fetched from. `latest` has its own URL
151
+ * shape on GitHub releases; anything else is a tag. Resolving it here rather
152
+ * than in the generated shell is the point of rendering CI from config: a
153
+ * value that is fixed at render time should not be a branch at run time.
154
+ */
155
+ function grimReleaseBase(grimVersion) {
156
+ const releases = "https://github.com/grimoire-rs/grimoire/releases";
157
+ return grimVersion === "latest"
158
+ ? `${releases}/latest/download`
159
+ : `${releases}/download/${grimVersion}`;
160
+ }
161
+ /**
162
+ * `paths:` entries that must re-run the drift guard — every file it renders,
163
+ * plus the config they are rendered from. `package-lock.json` is in there
164
+ * because the lock is what decides which renderer produces them.
165
+ */
166
+ const VERIFY_PATHS = [CONFIG_FILE, "package.json", "package-lock.json", ".github/workflows/**"];
167
+ /**
168
+ * Render the complete CI file set. Nothing touches disk — the caller writes
169
+ * it or diffs it against what is committed.
170
+ */
171
+ export function renderCi(ci) {
172
+ const base = {
173
+ nodeVersion: ci.nodeVersion,
174
+ defaultBranch: ci.defaultBranch,
175
+ grimVersion: ci.grimVersion,
176
+ grimReleaseBase: grimReleaseBase(ci.grimVersion),
177
+ };
178
+ // Rendered first: `render` is single-pass, so a block handed in as a value
179
+ // must already have its own placeholders resolved. The trailing newline is
180
+ // trimmed because the template supplies one on the placeholder's own line —
181
+ // keeping both would leave a stray blank line, or an empty block would not.
182
+ const block = (rel) => fromTemplate(rel, base).replace(/\n$/, "");
183
+ const vars = {
184
+ ...base,
185
+ header: fromTemplate("ci/header.txt", base),
186
+ githubEnrichSteps: ci.enrich ? block("ci/github-enrich.yml") : "",
187
+ gitlabEnrichScript: ci.enrich ? block("ci/gitlab-enrich.sh") : "",
188
+ verifyPaths: VERIFY_PATHS.map((entry) => ` - ${entry}`).join("\n"),
189
+ gitlabVerifyJob: ci.allowManualEdits ? "" : block("ci/gitlab-verify.yml"),
190
+ // GitHub only — `validateCi` refuses the GitLab combination outright, so
191
+ // there is no silently-inert case to render around here.
192
+ githubAutoMergeJob: ci.autoMerge ? block("ci/github-automerge.yml") : "",
193
+ // Two forges, one decision. Each spells "on a v-tag" and "on the trunk"
194
+ // its own way, and neither can express the other's — GitHub needs a
195
+ // literal branch in `on:` (hence `ci.defaultBranch`), GitLab reads
196
+ // `$CI_DEFAULT_BRANCH` at run time and needs no such key.
197
+ publishTrigger: ci.publish === "tag"
198
+ ? ' push:\n tags: ["v*"]'
199
+ : ` push:\n branches: [${ci.defaultBranch}]`,
200
+ // Rendered with its own rule already substituted: `render` is single-pass,
201
+ // so a placeholder inside a block handed in as a value never resolves.
202
+ gitlabPublishJob: ci.publish === "never"
203
+ ? ""
204
+ : fromTemplate("ci/gitlab-publish.yml", {
205
+ ...base,
206
+ gitlabPublishRule: ci.publish === "tag"
207
+ ? " - if: $CI_COMMIT_TAG =~ /^v/"
208
+ : " - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH",
209
+ }).replace(/\n$/, ""),
210
+ };
211
+ // Exactly one trailing newline, whatever the placeholders resolved to. An
212
+ // optional block that renders empty at the end of a file otherwise leaves
213
+ // its own blank line behind, so the same config produced two shapes.
214
+ const file = (rel) => fromTemplate(rel, vars).replace(/\n*$/, "\n");
215
+ const files = new Map();
216
+ if (ci.forge === "github") {
217
+ files.set(GITHUB_FILES.pages, file("ci/github-pages.yml"));
218
+ files.set(GITHUB_FILES.validate, file("ci/github-validate.yml"));
219
+ if (!ci.allowManualEdits) {
220
+ files.set(GITHUB_FILES.verify, file("ci/github-verify-ci.yml"));
221
+ }
222
+ // Its own file rather than a job in `pages.yml`: it runs on a different
223
+ // trigger, and an index that publishes nothing should carry no publish
224
+ // workflow at all — `staleCi` then reports the leftover if the key is
225
+ // turned back off.
226
+ if (ci.publish !== "never") {
227
+ files.set(GITHUB_FILES.publish, file("ci/github-publish.yml"));
228
+ }
229
+ }
230
+ else {
231
+ files.set(GITLAB_FILE, file("ci/gitlab-ci.yml"));
232
+ }
233
+ return files;
234
+ }
235
+ /**
236
+ * Canonicalize a generated file for drift comparison.
237
+ *
238
+ * The index repository owns the *pin* on every `uses:` action reference —
239
+ * its own Renovate or Dependabot will bump `uses: owner/action@<ref> # vX`,
240
+ * and the guard must not read that as a hand-edit. Only the `@<ref>` suffix
241
+ * and any trailing version comment are stripped; `owner/action` survives, so
242
+ * swapping in a different action still trips drift.
243
+ */
244
+ export function normalizeForDrift(content) {
245
+ // Line endings first. Git for Windows installs with `core.autocrlf=true` by
246
+ // default, so an untouched clone has CRLF on disk while the renderer emits
247
+ // LF — every generated file read as drift, and `npm run ci` could not clear
248
+ // it because the rewrite was LF too. The scaffold ships a `.gitattributes`
249
+ // that prevents it; this unsticks the checkouts that already have it.
250
+ return content
251
+ .replace(/\r\n/g, "\n")
252
+ .replace(/^([ \t]*(?:-[ \t]+)?uses:[ \t]*[^@\s]+)@[^\s#]+(?:[ \t]*#[^\n]*)?$/gm, "$1");
253
+ }
254
+ /**
255
+ * Files on disk that carry our header but that the current config no longer
256
+ * renders — a `forge` narrowed from `both`, or `allowManualEdits` turned on
257
+ * after a guard was already committed. Reported, never deleted: removing a
258
+ * file from somebody's repository is their call, not the renderer's.
259
+ */
260
+ export async function staleCi(root, files) {
261
+ const candidates = [GITLAB_FILE];
262
+ try {
263
+ for (const entry of await fs.readdir(path.join(root, ".github/workflows"))) {
264
+ if (/\.ya?ml$/.test(entry))
265
+ candidates.push(`.github/workflows/${entry}`);
266
+ }
267
+ }
268
+ catch {
269
+ /* no workflows directory — nothing of ours can be stale in it */
270
+ }
271
+ const stale = [];
272
+ for (const relative of candidates) {
273
+ if (files.has(relative))
274
+ continue;
275
+ const content = await fs.readFile(path.join(root, relative), "utf8").catch(() => null);
276
+ if (content === null)
277
+ continue;
278
+ if (content.startsWith(GENERATED_HEADER) || LEGACY_SIGNATURE.test(content)) {
279
+ stale.push(relative);
280
+ }
281
+ }
282
+ return stale.sort();
283
+ }
284
+ /**
285
+ * Write the rendered set, overwriting whatever is there.
286
+ *
287
+ * "Whatever is there" is judged through [`normalizeForDrift`], the same lens
288
+ * the guard uses — not raw bytes. Otherwise the two disagreed: `ci --check`
289
+ * deliberately tolerates a bumped `uses: owner/action@<ref>`, while a plain
290
+ * `npm run ci` rewrote it back to the pin baked into this package, silently
291
+ * undoing every Renovate bump the repository is told it may make. The repo
292
+ * owns its pins; a render must not take them back.
293
+ */
294
+ export async function writeCi(root, files) {
295
+ const outcomes = [];
296
+ for (const [relative, content] of files) {
297
+ const abs = path.join(root, relative);
298
+ const current = await fs.readFile(abs, "utf8").catch(() => null);
299
+ if (current !== null && normalizeForDrift(current) === normalizeForDrift(content)) {
300
+ outcomes.push({ path: relative, status: "unchanged" });
301
+ continue;
302
+ }
303
+ await fs.mkdir(path.dirname(abs), { recursive: true });
304
+ await fs.writeFile(abs, content);
305
+ outcomes.push({ path: relative, status: "written" });
306
+ }
307
+ return outcomes;
308
+ }
309
+ /**
310
+ * Compare the rendered set against what is committed. Missing counts as
311
+ * drift; a generated file the config no longer renders counts as stale.
312
+ * Hints are path-only — the contents of a repository's CI never go to stderr.
313
+ */
314
+ export async function checkCi(root, files) {
315
+ const outcomes = [];
316
+ for (const [relative, expected] of files) {
317
+ const actual = await fs.readFile(path.join(root, relative), "utf8").catch(() => null);
318
+ const same = actual !== null && normalizeForDrift(actual) === normalizeForDrift(expected);
319
+ outcomes.push({ path: relative, status: same ? "ok" : "drift" });
320
+ }
321
+ for (const relative of await staleCi(root, files)) {
322
+ outcomes.push({ path: relative, status: "stale" });
323
+ }
324
+ return outcomes;
325
+ }
326
+ /**
327
+ * The re-render command a drift message tells the reader to run. It is the
328
+ * repository's own npm script, so it runs the renderer the lock pins rather
329
+ * than whatever `npx` would fetch today.
330
+ */
331
+ export const RE_RENDER_COMMAND = "npm run ci";
332
+ /** Turn a failed check into the error the CLI exits on. */
333
+ export function driftError(outcomes) {
334
+ const bad = outcomes.filter((outcome) => outcome.status !== "ok");
335
+ return new CliError(`${bad.length} generated CI file(s) do not match ${CONFIG_FILE} — ` +
336
+ `re-run \`${RE_RENDER_COMMAND}\` and commit the result`, EXIT.data);
337
+ }
338
+ //# sourceMappingURL=ci.js.map
package/dist/ci.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci.js","sourceRoot":"","sources":["../src/ci.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAQA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6B9E"}
1
+ {"version":3,"file":"build.d.ts","sourceRoot":"","sources":["../../src/cli/build.ts"],"names":[],"mappings":"AAQA,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGhD,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAsB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAkB9E"}