@grimoire-rs/indexer 0.2.1 → 0.3.0

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 (62) hide show
  1. package/README.md +51 -18
  2. package/dist/ci.d.ts +115 -0
  3. package/dist/ci.d.ts.map +1 -0
  4. package/dist/ci.js +286 -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 +6 -1
  18. package/dist/cli/init.d.ts.map +1 -1
  19. package/dist/cli/init.js +298 -74
  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 +61 -8
  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/config.d.ts.map +1 -1
  33. package/dist/config.js +12 -2
  34. package/dist/config.js.map +1 -1
  35. package/dist/templates.d.ts +12 -0
  36. package/dist/templates.d.ts.map +1 -0
  37. package/dist/templates.js +40 -0
  38. package/dist/templates.js.map +1 -0
  39. package/dist/validate/adapters/files.d.ts.map +1 -1
  40. package/dist/validate/adapters/files.js +13 -3
  41. package/dist/validate/adapters/files.js.map +1 -1
  42. package/dist/validate/index.js +17 -2
  43. package/dist/validate/index.js.map +1 -1
  44. package/package.json +1 -1
  45. package/templates/README.md +115 -19
  46. package/templates/ci/github-automerge.yml +36 -0
  47. package/templates/ci/github-enrich.yml +27 -0
  48. package/templates/ci/github-pages.yml +64 -0
  49. package/templates/ci/github-validate.yml +157 -0
  50. package/templates/ci/github-verify-ci.yml +47 -0
  51. package/templates/ci/gitlab-ci.yml +148 -0
  52. package/templates/ci/gitlab-enrich.sh +26 -0
  53. package/templates/ci/gitlab-verify.yml +16 -0
  54. package/templates/ci/header.txt +19 -0
  55. package/templates/gitattributes +4 -0
  56. package/templates/gitignore +7 -2
  57. package/templates/package.json +18 -0
  58. package/templates/publish.toml +2 -2
  59. package/templates/github-pages.yml +0 -24
  60. package/templates/github-validate.yml +0 -51
  61. package/templates/gitlab-ci.yml +0 -13
  62. package/templates/reusable/gitlab-index-ci.yml +0 -125
@@ -0,0 +1,148 @@
1
+ {{header}}
2
+ # Builds this index for GitLab Pages and gates merge requests.
3
+
4
+ stages:
5
+ - test
6
+ - deploy
7
+
8
+ # `npm ci` installs exactly package-lock.json, so which renderer runs is a
9
+ # reviewed fact in this repository rather than a resolution on the runner.
10
+ default:
11
+ image: node:{{nodeVersion}}-alpine
12
+ cache:
13
+ key:
14
+ files:
15
+ - package-lock.json
16
+ paths:
17
+ - .npm/
18
+ - .npm-gate/
19
+
20
+ # Contribution gate. Exit 0 = eligible for auto-merge, non-zero = manual
21
+ # review required, so this job's status IS the gate.
22
+ #
23
+ # The gate must judge the change against the COMMITTED policy, not the policy
24
+ # the merge request proposes - otherwise a contributor allowlists their own
25
+ # registry host in the same merge request. So the target branch is checked out
26
+ # into a sibling worktree and passed as `--root`, with the merge-request head
27
+ # passed as `--pr-tree` and read as data only.
28
+ #
29
+ # The gate installs and runs from `../.gate-base`, the target branch's worktree -
30
+ # never from the merge request's own checkout. Otherwise the contributor
31
+ # supplies the lockfile that decides which validator judges them, and
32
+ # `--ignore-scripts` alone does not fix that: the package it installs is still
33
+ # theirs to choose. `--ignore-scripts` stays anyway, one layer further in.
34
+ #
35
+ # RESIDUAL, and it is not fixable from this file. Two ways, both structural:
36
+ #
37
+ # 1. The merge request supplies its own `.gitlab-ci.yml`, so a contributor
38
+ # can delete this job outright.
39
+ # 2. GitLab runs a FORK merge request's pipeline in the source project, so
40
+ # `origin` is the fork. `origin/<target>` is then the fork's copy of the
41
+ # target branch, which means `../.gate-base` - and the `index-policy.json` and
42
+ # `package-lock.json` read from it - are contributor-controlled for a
43
+ # fork merge request. The `../.gate-base` install above is therefore defence in
44
+ # depth for same-project branches, not a trust boundary for forks.
45
+ #
46
+ # Enforce it instance-side - a compliance pipeline, a required merge check, or
47
+ # protected-branch approval rules - or treat the GitLab gate as advisory. The
48
+ # GitHub gate has no equivalent gap: `pull_request_target` always runs the base
49
+ # branch's copy of the workflow, against the base checkout.
50
+ grim-indexer:validate:
51
+ stage: test
52
+ variables:
53
+ GIT_DEPTH: 0
54
+ rules:
55
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
56
+ # The job image is picked for npm, and `node:*-alpine` ships no git - but
57
+ # this job diffs the merge request against its target branch, so git is not
58
+ # optional. GitLab's runner clones with a separate helper image, so nothing
59
+ # else puts git in here. Install it for whichever package manager the image
60
+ # has.
61
+ #
62
+ # The trailing check is the load-bearing part: the gate's contract is
63
+ # "exit 0 = eligible for auto-merge", so a missing or failed-to-install tool
64
+ # must fail the job, never silently skip validation.
65
+ before_script:
66
+ - |
67
+ set -eu
68
+ if ! command -v git >/dev/null 2>&1; then
69
+ if command -v apk >/dev/null 2>&1; then
70
+ apk add --no-cache git
71
+ elif command -v apt-get >/dev/null 2>&1; then
72
+ apt-get update -qq && apt-get install -y -qq --no-install-recommends git
73
+ fi
74
+ fi
75
+ command -v git >/dev/null 2>&1 || {
76
+ echo "grim-indexer: the gate needs git, and this image has none" >&2
77
+ exit 1
78
+ }
79
+ script:
80
+ - |
81
+ set -eu
82
+ git fetch --quiet origin "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
83
+ # `../.gate-base` sits outside $CI_PROJECT_DIR, which is the part GitLab
84
+ # cleans. A leftover from an earlier run makes `git worktree add` fail
85
+ # and, under `set -eu`, fails the job permanently - fail-closed, but the
86
+ # shape that gets a gate switched off rather than fixed.
87
+ #
88
+ # The leading dot is load-bearing. `..` is the NAMESPACE directory,
89
+ # shared with every sibling project on this runner, and a GitLab project
90
+ # path must start with a letter or a digit - so no project can be named
91
+ # `.gate-base` and this `rm -rf` can never reach somebody else's
92
+ # checkout. It was `../base` for one revision, which a group holding a
93
+ # project called `base` would have had wiped on every gate run.
94
+ rm -rf ../.gate-base
95
+ git worktree prune
96
+ git worktree add --detach ../.gate-base "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
97
+ # Every changed path, with no pathspec and no diff filter: rejecting an
98
+ # out-of-bounds path is the gate's first job, and it ownership-checks a
99
+ # deletion before allowing it. Narrowing to `-- index` would let a merge
100
+ # request that adds a valid entry and edits this very file pass; dropping
101
+ # `D` would let one that deletes a stranger's entry pass.
102
+ #
103
+ # `--no-renames` is load-bearing. Git reports a rename as the DESTINATION
104
+ # path only, so copying a stranger's metadata.json into your own
105
+ # namespace and deleting the original was detected as a rename, the
106
+ # deletion never reached the gate, and no ownership check ever ran on the
107
+ # victim's namespace. With this flag both sides are listed.
108
+ #
109
+ # NEVER add `-C`. Copy detection re-collapses the pair to the
110
+ # destination in either flag order, which puts the hole straight back.
111
+ #
112
+ # `-z` and `--changed-from` keep these attacker-controlled strings off
113
+ # the command line and out of the shell's hands entirely: a path named
114
+ # `-h` used to make the parser print help and exit 0, which this job's
115
+ # contract reads as "eligible for auto-merge".
116
+ git diff -z --name-only --no-renames \
117
+ "$CI_MERGE_REQUEST_DIFF_BASE_SHA" HEAD > "$CI_PROJECT_DIR/changed.txt"
118
+ # Installed and run from the trusted target branch, never from the
119
+ # merge request's own lockfile. Its own cache directory, because the
120
+ # shared one is a path the merge request can commit into.
121
+ cd ../.gate-base
122
+ rm -rf "$CI_PROJECT_DIR/.npm-gate"
123
+ npm ci --cache "$CI_PROJECT_DIR/.npm-gate" --prefer-offline --ignore-scripts
124
+ npm run validate -- \
125
+ --forge gitlab --root . --pr-tree "$CI_PROJECT_DIR" \
126
+ --changed-from "$CI_PROJECT_DIR/changed.txt"
127
+ {{gitlabVerifyJob}}
128
+ # GitLab Pages serves whatever the `pages` job leaves in `public/`.
129
+ pages:
130
+ stage: deploy
131
+ rules:
132
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
133
+ before_script:
134
+ - npm ci --cache .npm --prefer-offline --ignore-scripts
135
+ script:
136
+ - |
137
+ set -eu
138
+ {{gitlabEnrichScript}}
139
+ # Built into `dist/`, then moved. Building straight into `public/` was a
140
+ # data-loss bug: the compile step clears its output directory first, so it
141
+ # deleted this index's own committed asset layer (logo, favicon) before
142
+ # the renderer ever read it. `dist/` already contains those assets by the
143
+ # time this runs, so the replacement is complete.
144
+ - npm run build
145
+ - rm -rf public && mv dist public
146
+ artifacts:
147
+ paths:
148
+ - public
@@ -0,0 +1,26 @@
1
+ # The index stores pointers; README, changelog, logo and version list all
2
+ # live in the registry, and grim is what reads a registry. Best-effort by
3
+ # design - a registry outage degrades the site to pointers-only rather
4
+ # than blocking a deploy, so the failure is logged and the build
5
+ # continues. Set `"enrich": false` in the `ci` block to drop this block.
6
+ #
7
+ # Nothing is committed and no token is involved: the sidecars live only
8
+ # in this job's workspace, which is why this needs no CI variables.
9
+ if command -v apk >/dev/null 2>&1; then
10
+ apk add --no-cache curl tar
11
+ elif command -v apt-get >/dev/null 2>&1; then
12
+ apt-get update -qq && apt-get install -y -qq --no-install-recommends curl tar ca-certificates
13
+ fi
14
+ # Alpine is musl; everything else here is glibc.
15
+ if [ -f /etc/alpine-release ]; then libc=musl; else libc=gnu; fi
16
+ # Resolved from `ci.grimVersion` when this file was rendered, so there is
17
+ # no version branch left to take at run time.
18
+ base="{{grimReleaseBase}}"
19
+ tarball="grimoire-$(uname -m)-unknown-linux-$libc.tar.gz"
20
+ tmp="$(mktemp -d)"
21
+ ( cd "$tmp" \
22
+ && curl -fsSL --proto '=https' --tlsv1.2 -O "$base/$tarball" -O "$base/$tarball.sha256" \
23
+ && sha256sum -c "$tarball.sha256" \
24
+ && tar -xzf "$tarball" -C /usr/local/bin --strip-components=1 "${tarball%.tar.gz}/grim" ) \
25
+ && npm run enrich \
26
+ || echo "warning: enrich failed - building without READMEs, logos and version lists"
@@ -0,0 +1,16 @@
1
+
2
+ # Fail closed when a generated CI file is hand-edited: this job re-renders from
3
+ # index.config.json and diffs against what is committed. Fix drift by running
4
+ # `npm run ci` locally and committing the result.
5
+ grim-indexer:verify-ci:
6
+ stage: test
7
+ rules:
8
+ - if: $CI_PIPELINE_SOURCE == "merge_request_event"
9
+ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
10
+ before_script:
11
+ # Rendering needs no build toolchain, so nothing here runs a dependency's
12
+ # lifecycle script.
13
+ - npm ci --cache .npm --prefer-offline --ignore-scripts
14
+ script:
15
+ # Exits 65 on drift; the hint names the stale path and never its contents.
16
+ - npm run ci:check
@@ -0,0 +1,19 @@
1
+ # Generated by @grimoire-rs/indexer - DO NOT EDIT.
2
+ #
3
+ # This file is rendered from the `ci` block of index.config.json and committed
4
+ # to this repository, which owns and runs it. To change what CI does, change
5
+ # the config and re-render:
6
+ #
7
+ # npm run ci
8
+ #
9
+ # The version that renders it is the one in package-lock.json, so CI runs
10
+ # `npm ci` and never fetches a floating release. Bump the dependency the
11
+ # ordinary npm way, then re-render.
12
+ #
13
+ # The `verify-ci` job re-renders and diffs on every push and pull request, so a
14
+ # hand-edit fails CI rather than silently forking. Action pins are excluded
15
+ # from that diff - Renovate may bump `uses: owner/action@<ref>` freely.
16
+ #
17
+ # To own these files by hand instead, set `"allowManualEdits": true` in the
18
+ # `ci` block: the guard is then not emitted, and CI fixes stop arriving by
19
+ # re-render.
@@ -0,0 +1,4 @@
1
+ # `npm run ci:check` compares the generated CI byte for byte, and the renderer
2
+ # emits LF. Git for Windows installs with `core.autocrlf=true`, so without this
3
+ # an untouched clone has CRLF on disk and every generated file reads as drift.
4
+ * text=auto eol=lf
@@ -1,12 +1,17 @@
1
1
  # Build output of `grim-indexer build`.
2
2
  dist/
3
3
 
4
- # NOT ignored: `public/` is this index's own asset layer the logo and
4
+ # NOT ignored: `public/` is this index's own asset layer - the logo and
5
5
  # favicon `index.config.json` names live there, and the build copies it into
6
6
  # `dist/`. Ignoring it means the site references files the deploy never had.
7
7
 
8
- # Renderer scratch dir removed on a clean build, left behind by a killed one.
8
+ # Renderer scratch dir - removed on a clean build, left behind by a killed one.
9
9
  .index-*/
10
10
 
11
11
  node_modules/
12
+ .npm/
13
+
14
+ # NOT ignored: `package-lock.json` is what pins the renderer this index builds
15
+ # and validates with. Committing it is what makes `npm ci` in CI reproducible.
16
+
12
17
  .DS_Store
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "{{name}}",
3
+ "version": "0.0.0",
4
+ "private": true,
5
+ "description": "{{titleJson}}, a Grimoire package index.",
6
+ "type": "module",
7
+ "scripts": {
8
+ "dev": "grim-indexer dev",
9
+ "build": "grim-indexer build",
10
+ "enrich": "grim-indexer enrich",
11
+ "validate": "grim-indexer validate",
12
+ "ci": "grim-indexer ci",
13
+ "ci:check": "grim-indexer ci --check"
14
+ },
15
+ "devDependencies": {
16
+ "@grimoire-rs/indexer": "^{{version}}"
17
+ }
18
+ }
@@ -1,4 +1,4 @@
1
- # `grim publish` manifest this repo holds both its own skills (under
1
+ # `grim publish` manifest - this repo holds both its own skills (under
2
2
  # `skills/`) and the index that lists them, the combined layout
3
3
  # `grim-indexer init --with-skills` scaffolds.
4
4
  #
@@ -18,7 +18,7 @@ version = "0.1.0"
18
18
  # do not own.
19
19
  #
20
20
  # `repository` is this repo's https clone URL. `namespace` is the
21
- # `index/<host>/<namespace>/` your entries land under the contribution gate
21
+ # `index/<host>/<namespace>/` your entries land under - the contribution gate
22
22
  # refuses a namespace whose forge owner is not you. A literal `REPLACE-ME`
23
23
  # means the scaffold had nothing to derive it from: `--announce` then stops
24
24
  # with "cannot derive the index host" rather than announcing anywhere.
@@ -1,24 +0,0 @@
1
- # Builds this index and deploys it to GitHub Pages.
2
- #
3
- # Deliberately a thin caller: the job logic lives in a reusable workflow
4
- # grim-indexer owns, so upgrades arrive by bumping the pinned ref below
5
- # instead of re-scaffolding this repo over your edits. Renovate's
6
- # `github-actions` manager bumps it for you.
7
- name: pages
8
-
9
- on:
10
- push:
11
- branches: [main]
12
- workflow_dispatch:
13
-
14
- permissions: {}
15
-
16
- jobs:
17
- pages:
18
- uses: grimoire-rs/indexer/.github/workflows/index-pages.yml@{{ref}}
19
- permissions:
20
- contents: read
21
- pages: write
22
- id-token: write
23
- with:
24
- grim-indexer-version: "{{version}}"
@@ -1,51 +0,0 @@
1
- # Contribution gate for pull requests against this index.
2
- #
3
- # Exit 0 = eligible for auto-merge, non-zero = manual review required. To
4
- # enforce it, require the status check named `validate / validate` in branch
5
- # protection — NOT `validate`. A thin caller reports its check run as
6
- # `<job key here> / <job key in the called workflow>`, and both happen to be
7
- # `validate`; rename `jobs.validate` below and the required context moves
8
- # with it. Requiring a context that never reports blocks every PR forever,
9
- # and looks exactly like the gate rejecting the contribution.
10
- #
11
- # `pull_request_target` is deliberate and safe HERE, and only because of
12
- # what the called workflow does: it runs grim-indexer from npm against the
13
- # trusted base checkout, and reads the PR head as data in a separate
14
- # directory without ever executing, importing, or installing from it. The
15
- # gate needs a forge token to resolve numeric namespace-owner ids, which an
16
- # unprivileged `pull_request` job does not have.
17
- #
18
- # Do not switch this to run contributor code, and do not widen
19
- # `permissions:` here.
20
- #
21
- # This gate covers third-party contributions. It does NOT cover an announce
22
- # your own CI makes (the `--with-skills` layout, where this repo publishes
23
- # into its own index): GitHub runs no workflows on a PR opened with
24
- # `secrets.GITHUB_TOKEN`, so `grim publish --announce` from CI lands an
25
- # effectively ungated PR — review it by hand. That PR also needs "Allow
26
- # GitHub Actions to create and approve pull requests" (Settings → Actions)
27
- # turned on, off by default; without it grim only pushes the branch and
28
- # reports `outcome: "branch-pushed"`. Enabling it lets any workflow in this
29
- # repo approve PRs too, so weigh it against your branch protection.
30
- #
31
- # Deliberately a thin caller: the job logic lives in a reusable workflow
32
- # grim-indexer owns, so upgrades arrive by bumping the pinned ref below
33
- # instead of re-scaffolding this repo over your edits.
34
- name: validate
35
-
36
- on:
37
- pull_request_target:
38
- paths:
39
- - "index/**"
40
- - "index-policy.json"
41
-
42
- permissions: {}
43
-
44
- jobs:
45
- validate:
46
- uses: grimoire-rs/indexer/.github/workflows/index-validate.yml@{{ref}}
47
- permissions:
48
- contents: read
49
- pull-requests: read
50
- with:
51
- grim-indexer-version: "{{version}}"
@@ -1,13 +0,0 @@
1
- # Builds this index for GitLab Pages and gates merge requests.
2
- #
3
- # Deliberately a thin caller: the job logic lives in a file grim-indexer
4
- # owns, so upgrades arrive by bumping the pinned ref in the URL below
5
- # instead of re-scaffolding this repo over your edits.
6
- #
7
- # If your GitLab instance blocks remote includes, vendor the file locally
8
- # and switch to `- local: "ci/grim-indexer.yml"`.
9
- include:
10
- - remote: "https://raw.githubusercontent.com/grimoire-rs/indexer/{{ref}}/templates/reusable/gitlab-index-ci.yml"
11
-
12
- variables:
13
- GRIM_INDEXER_VERSION: "{{version}}"
@@ -1,125 +0,0 @@
1
- # SPDX-License-Identifier: Apache-2.0
2
- # Copyright 2026 The Grimoire Authors
3
- #
4
- # GitLab counterpart of the two reusable GitHub workflows: scaffolded index
5
- # repos pull this in with `include: remote:` so a fix here reaches them
6
- # without a re-scaffold. Override any variable below in the including
7
- # `.gitlab-ci.yml`.
8
- #
9
- # A private GitLab instance may refuse to fetch a remote include. The
10
- # fallback is to vendor this file into the index repo and switch the
11
- # include to `local:`.
12
- variables:
13
- GRIM_INDEXER_VERSION: "latest"
14
- GRIM_INDEXER_NODE_IMAGE: "node:22-alpine"
15
- GRIM_INDEXER_OUT_DIR: "public"
16
- # Refresh READMEs, changelogs, logos and version lists from the registry
17
- # before building. Set to "false" for a pointers-only site that never
18
- # leaves the runner.
19
- GRIM_INDEXER_ENRICH: "true"
20
- # grim release the enrichment step reads the registry with: "latest" or a tag.
21
- GRIM_VERSION: "latest"
22
-
23
- stages:
24
- - test
25
- - deploy
26
-
27
- # Contribution gate. Exit 0 = eligible for auto-merge, non-zero = manual
28
- # review required, so this job's status IS the gate.
29
- #
30
- # The gate must judge the change against the COMMITTED policy, not the
31
- # policy the merge request proposes — otherwise a contributor allowlists
32
- # their own registry host in the same MR. So the target branch is checked
33
- # out into a sibling worktree and passed as `--root`, with the MR head
34
- # passed as `--pr-tree` and read as data only.
35
- #
36
- # RESIDUAL, and it is not fixable from this file: on GitLab the merge
37
- # request supplies its own `.gitlab-ci.yml`, so a contributor can delete
38
- # this job outright. Enforce it instance-side — a compliance pipeline, a
39
- # required merge check, or protected-branch approval rules — or treat the
40
- # GitLab gate as advisory.
41
- grim-indexer:validate:
42
- stage: test
43
- image: $GRIM_INDEXER_NODE_IMAGE
44
- variables:
45
- GIT_DEPTH: 0
46
- rules:
47
- - if: $CI_PIPELINE_SOURCE == "merge_request_event"
48
- # The job image is picked for `npx`, and `node:*-alpine` ships no git —
49
- # but this job diffs the merge request against its target branch, so git
50
- # is not optional. GitLab's runner clones with a separate helper image, so
51
- # nothing else puts git in here. Install it for whichever package manager
52
- # the (overridable) image has.
53
- #
54
- # The trailing check is the load-bearing part: the gate's contract is
55
- # "exit 0 = eligible for auto-merge", so a missing or failed-to-install
56
- # tool must fail the job, never silently skip validation.
57
- before_script:
58
- - |
59
- set -eu
60
- if ! command -v git >/dev/null 2>&1; then
61
- if command -v apk >/dev/null 2>&1; then
62
- apk add --no-cache git
63
- elif command -v apt-get >/dev/null 2>&1; then
64
- apt-get update -qq && apt-get install -y -qq --no-install-recommends git
65
- fi
66
- fi
67
- command -v git >/dev/null 2>&1 || {
68
- echo "grim-indexer: the gate needs git, and ${GRIM_INDEXER_NODE_IMAGE} has none" >&2
69
- exit 1
70
- }
71
- script:
72
- - |
73
- set -eu
74
- git fetch --quiet origin "$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
75
- git worktree add --detach ../base "origin/$CI_MERGE_REQUEST_TARGET_BRANCH_NAME"
76
- # Every changed path, with no pathspec and no diff filter: rejecting an
77
- # out-of-bounds path is the gate's first job, and it ownership-checks a
78
- # deletion before allowing it. Narrowing to `-- index` would let an MR
79
- # that adds a valid entry and edits this very file pass; dropping `D`
80
- # would let one that deletes a stranger's entry pass.
81
- git diff --name-only "$CI_MERGE_REQUEST_DIFF_BASE_SHA" HEAD > changed.txt
82
- xargs -a changed.txt npx --yes "@grimoire-rs/indexer@$GRIM_INDEXER_VERSION" validate \
83
- --forge gitlab --root ../base --pr-tree .
84
-
85
- # GitLab Pages serves whatever the `pages` job leaves in `public/`.
86
- pages:
87
- stage: deploy
88
- image: $GRIM_INDEXER_NODE_IMAGE
89
- rules:
90
- - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
91
- # The index stores pointers; README, changelog, logo and version list all
92
- # live in the registry, and grim is what reads a registry. Best-effort by
93
- # design — a registry outage degrades the site to pointers-only rather than
94
- # blocking a deploy, so the failure is logged and the build continues.
95
- #
96
- # Nothing is committed and no token is involved: the sidecars live only in
97
- # this job's workspace, which is why this needs no CI variables at all.
98
- script:
99
- - |
100
- set -eu
101
- if [ "$GRIM_INDEXER_ENRICH" = "true" ]; then
102
- if command -v apk >/dev/null 2>&1; then
103
- apk add --no-cache curl tar
104
- elif command -v apt-get >/dev/null 2>&1; then
105
- apt-get update -qq && apt-get install -y -qq --no-install-recommends curl tar ca-certificates
106
- fi
107
- # Alpine is musl; everything else here is glibc.
108
- if [ -f /etc/alpine-release ]; then libc=musl; else libc=gnu; fi
109
- case "$GRIM_VERSION" in
110
- latest) base=https://github.com/grimoire-rs/grimoire/releases/latest/download ;;
111
- *) base="https://github.com/grimoire-rs/grimoire/releases/download/$GRIM_VERSION" ;;
112
- esac
113
- tarball="grimoire-$(uname -m)-unknown-linux-$libc.tar.gz"
114
- tmp="$(mktemp -d)"
115
- ( cd "$tmp" \
116
- && curl -fsSL --proto '=https' --tlsv1.2 -O "$base/$tarball" -O "$base/$tarball.sha256" \
117
- && sha256sum -c "$tarball.sha256" \
118
- && tar -xzf "$tarball" -C /usr/local/bin --strip-components=1 "${tarball%.tar.gz}/grim" ) \
119
- && npx --yes "@grimoire-rs/indexer@$GRIM_INDEXER_VERSION" enrich \
120
- || echo "warning: enrich failed — building without READMEs, logos and version lists"
121
- fi
122
- - npx --yes "@grimoire-rs/indexer@$GRIM_INDEXER_VERSION" build --out-dir "$GRIM_INDEXER_OUT_DIR"
123
- artifacts:
124
- paths:
125
- - $GRIM_INDEXER_OUT_DIR