feat(2026-05-03-perform-code-optimization-and-document-cleanup): followup Fix CI pnpm version conflict in check.yml
This commit is contained in:
@@ -32,8 +32,6 @@ jobs:
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: "10"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
@@ -38,8 +38,6 @@ jobs:
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: "10"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
+22
-1
@@ -43,6 +43,7 @@ pnpm run check
|
||||
| `pnpm run verify:docs` | markdownlint + offline link-check + docs-flow verifier |
|
||||
| `pnpm run verify:docs:online` | Same as `verify:docs` but with full external link checking |
|
||||
| `pnpm run verify:generated` | Assert generated output freshness (stub; fleshed out in M3) |
|
||||
| `pnpm run verify:ci` | Assert CI workflow files carry no pnpm version pins (see [pnpm version pinning](#pnpm-version-pinning)) |
|
||||
| `pnpm run check` | Aggregate: run every gate above and report a summary |
|
||||
|
||||
## Quality tooling (added in M1)
|
||||
@@ -167,6 +168,7 @@ PASS verify:pi
|
||||
PASS verify:reviewers
|
||||
PASS verify:docs
|
||||
PASS verify:generated
|
||||
PASS verify:ci
|
||||
```
|
||||
|
||||
This is the only acceptable state for merge. Any failure on a check not in
|
||||
@@ -415,7 +417,8 @@ Two GitHub Actions workflows live in `.github/workflows/`:
|
||||
2. Installs `shellcheck` via `apt-get` (Ubuntu) or `brew` (macOS).
|
||||
3. Installs `ripgrep` via `apt-get` (Ubuntu only; pre-installed on macOS runners).
|
||||
4. Installs Node.js 22 via `actions/setup-node`.
|
||||
5. Installs pnpm 10 via `pnpm/action-setup`.
|
||||
5. Installs pnpm via `pnpm/action-setup@v4` — **no `version:` key is set**; the action reads the version from
|
||||
`package.json#packageManager` (currently `pnpm@10.18.1+sha512…`), which is the single source of truth.
|
||||
6. Runs `pnpm install --frozen-lockfile`.
|
||||
7. Runs `pnpm run check` (the same command contributors run locally).
|
||||
|
||||
@@ -423,6 +426,24 @@ The matrix runs both `ubuntu-latest` and `macos-latest` to guard against
|
||||
platform-specific regressions. Because M2 made all shell scripts portable
|
||||
across BSD and GNU coreutils, both runners should stay green.
|
||||
|
||||
### pnpm version pinning
|
||||
|
||||
The pnpm version is pinned **exclusively** in `package.json#packageManager`:
|
||||
|
||||
```json
|
||||
"packageManager": "pnpm@10.18.1+sha512.77a884a..."
|
||||
```
|
||||
|
||||
This field carries an exact version *and* an integrity hash, giving stronger
|
||||
reproducibility than a floating major like `version: "10"`. The
|
||||
`pnpm/action-setup@v4` step in `check.yml` reads this field automatically;
|
||||
do **not** add a `with.version` key to that step.
|
||||
|
||||
`pnpm run verify:ci` (backed by `scripts/lib/assert-no-pnpm-version-pin.mjs`)
|
||||
greps every `.github/workflows/*.yml` for `pnpm/action-setup` blocks that
|
||||
carry a `version:` key and fails if any are found. This prevents
|
||||
reintroduction of the conflict that caused `pnpm/action-setup@v4` to error.
|
||||
|
||||
### Adding new prerequisites to CI
|
||||
|
||||
If a new tool is required (e.g. a new binary called by a verify script),
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
"verify:docs": "markdownlint-cli2 ; R1=$?; node scripts/lib/run-link-check.mjs ; R2=$?; node scripts/verify-docs-flow.mjs ; R3=$?; [ $((R1+R2+R3)) -eq 0 ]",
|
||||
"verify:docs:online": "markdownlint-cli2 ; R1=$?; node scripts/lib/run-link-check.mjs --online ; R2=$?; node scripts/verify-docs-flow.mjs ; R3=$?; [ $((R1+R2+R3)) -eq 0 ]",
|
||||
"verify:generated": "node scripts/verify-generated.mjs",
|
||||
"verify:ci": "node scripts/lib/assert-no-pnpm-version-pin.mjs",
|
||||
"check": "node scripts/lib/run-check.mjs"
|
||||
},
|
||||
"pi": {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* assert-no-pnpm-version-pin.mjs — CI regression guard (followup: fix pnpm version conflict)
|
||||
*
|
||||
* Ensures no .github/workflows/*.yml file pins pnpm via a `version:` key
|
||||
* under a `pnpm/action-setup` step. The canonical version source is
|
||||
* `package.json#packageManager`, which carries an exact version + integrity
|
||||
* hash. Duplicating the version in the workflow creates a conflict that
|
||||
* pnpm/action-setup@v4 treats as an error.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/lib/assert-no-pnpm-version-pin.mjs
|
||||
* pnpm run verify:ci
|
||||
*
|
||||
* Exit codes:
|
||||
* 0 — no version pin found
|
||||
* 1 — one or more violations found (details on stderr)
|
||||
*/
|
||||
|
||||
import { readFileSync, readdirSync } from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const REPO_ROOT = path.resolve(__dirname, "../..");
|
||||
const WORKFLOWS_DIR = path.join(REPO_ROOT, ".github", "workflows");
|
||||
|
||||
let violations = 0;
|
||||
|
||||
// Read workflow files — silently pass if directory doesn't exist
|
||||
let files;
|
||||
try {
|
||||
files = readdirSync(WORKFLOWS_DIR).filter(
|
||||
(f) => f.endsWith(".yml") || f.endsWith(".yaml")
|
||||
);
|
||||
} catch {
|
||||
process.stdout.write("OK: no .github/workflows directory found; nothing to check.\n");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
for (const file of files) {
|
||||
const fullPath = path.join(WORKFLOWS_DIR, file);
|
||||
const content = readFileSync(fullPath, "utf8");
|
||||
const lines = content.split("\n");
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
// Locate a step that uses pnpm/action-setup
|
||||
if (!lines[i].includes("pnpm/action-setup")) continue;
|
||||
|
||||
// Look ahead up to 10 lines for a `version:` key in the same step
|
||||
const end = Math.min(i + 10, lines.length);
|
||||
for (let j = i + 1; j < end; j++) {
|
||||
const ahead = lines[j];
|
||||
// A new step begins at a `- name:` or `- uses:` list item → stop
|
||||
if (/^\s*-\s+(name|uses)\s*:/.test(ahead)) break;
|
||||
// `version:` key found inside this step → violation
|
||||
if (/^\s+version\s*:/.test(ahead)) {
|
||||
process.stderr.write(
|
||||
`ERROR: ${file}:${j + 1}: 'version:' key found under pnpm/action-setup step.\n` +
|
||||
` Remove 'with.version'; let package.json#packageManager be the single\n` +
|
||||
` source of truth for the pnpm version (exact version + integrity hash).\n\n`
|
||||
);
|
||||
violations++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (violations > 0) {
|
||||
process.stderr.write(`${violations} violation(s) found.\n`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
process.stdout.write("OK: no pnpm version pins found in workflow files.\n");
|
||||
process.exit(0);
|
||||
@@ -33,6 +33,7 @@ const STEPS = [
|
||||
{ label: "verify:reviewers", cmd: "pnpm", args: ["run", "verify:reviewers"] },
|
||||
{ label: "verify:docs", cmd: "pnpm", args: ["run", "verify:docs"] },
|
||||
{ label: "verify:generated", cmd: "pnpm", args: ["run", "verify:generated"] },
|
||||
{ label: "verify:ci", cmd: "pnpm", args: ["run", "verify:ci"] },
|
||||
];
|
||||
|
||||
// ── Runner ─────────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user