Skip to content

Commit 74a9078

Browse files
ci(release): reconcile lockfile before gated changeset commands (#1104)
* ci(release): reconcile lockfile before gated changeset commands verifyDepsBeforeRun: error gates pnpm run/exec. The frozen install in the release job does not refresh the lockfile's overrides hash, so a lockfile whose overrides drifted from pnpm-workspace.yaml passes the frozen install but trips the gate on `pnpm run changeset:version` / `pnpm changeset publish`, killing every release before it versions or publishes. A non-frozen install is not gated and reconciles the hash; changesets/action commits the result, self-healing the repo. * ci(release): reconcile lockfile inside the changeset command, not as a prior step changesets/action does git checkout changeset-release/main + git reset --hard right before running the version/publish command, so any reconcile placed in an earlier workflow step is discarded by that reset and the gated 'pnpm changeset' call still trips verifyDepsBeforeRun. Move the non-frozen install into a single non-gated node entrypoint the action invokes, so it runs after the action's git work and immediately before the gated pnpm call. Drop the now-unreferenced changeset:version script. * style: format * ci(release): use --prefer-frozen-lockfile for the reconcile changeset publish rebuilds packages via prepublishOnly at pack time. A non-frozen reconcile could re-resolve in-range transitive deps so shipped bits diverge from tested bits. prefer-frozen reconciles the deps state to satisfy verifyDepsBeforeRun without re-resolving when the lockfile is satisfiable, and falls back to a full install (e.g. after changeset version bumps workspace versions) when it isn't. * ci(release): revert reconcile to --no-frozen-lockfile The PR's purpose is to reliably clear ERR_PNPM_VERIFY_DEPS_BEFORE_RUN. --no-frozen-lockfile is pnpm's documented remediation and unconditionally refreshes the deps-state hash. --prefer-frozen-lockfile's fast path is gated by a satisfiability check that may not include the settings hash, so it could skip the rewrite in exactly the stale-metadata case this fixes. The shipped-vs-tested concern that motivated prefer-frozen is low-probability, pre-existing, and negligible when the lockfile is satisfiable (no re-resolution occurs). --------- Co-authored-by: emdashbot[bot] <emdashbot[bot]@users.noreply.github.com>
1 parent 361f0e2 commit 74a9078

3 files changed

Lines changed: 32 additions & 5 deletions

File tree

.github/scripts/release.mjs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { execFileSync } from "node:child_process";
2+
3+
const mode = process.argv[2];
4+
5+
const run = (args) => execFileSync("pnpm", args, { stdio: "inherit" });
6+
7+
// changesets/action runs `git checkout changeset-release/main` + `git reset
8+
// --hard` immediately before this, which can leave the deps state out of
9+
// sync with pnpm-workspace.yaml. The next gated pnpm call
10+
// (verifyDepsBeforeRun: error) would then abort the release. `pnpm install`
11+
// is not gated, so reconcile here, after the action's git work and before
12+
// any `pnpm changeset` call. Do not hoist this into an earlier workflow
13+
// step: the action's git reset runs after workflow steps and undoes it.
14+
// Must be --no-frozen-lockfile, not --prefer-frozen-lockfile: prefer-frozen
15+
// can take the lockfile fast path and skip rewriting the stale deps-state
16+
// hash, which is the exact condition that trips the gate.
17+
run(["install", "--no-frozen-lockfile"]);
18+
19+
if (mode === "version") {
20+
run(["changeset", "version"]);
21+
run(["install", "--no-frozen-lockfile"]);
22+
} else if (mode === "publish") {
23+
run(["changeset", "publish"]);
24+
} else {
25+
throw new Error(
26+
`Unknown release mode: ${JSON.stringify(mode)} (expected "version" or "publish")`,
27+
);
28+
}

.github/workflows/release.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,16 +71,16 @@ jobs:
7171
id: changesets
7272
uses: changesets/action@63a615b9cd06ba9a3e6d13796c7fbcb080a60a0b # v1.8.0
7373
with:
74-
version: pnpm run changeset:version
75-
publish: pnpm changeset publish
74+
version: node .github/scripts/release.mjs version
75+
publish: node .github/scripts/release.mjs publish
7676
commit: "ci: release"
7777
title: "ci: release"
7878
env:
7979
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
8080

8181
- name: Publish (manual)
8282
if: ${{ inputs.publish-only }}
83-
run: pnpm changeset publish
83+
run: node .github/scripts/release.mjs publish
8484

8585
sync-templates:
8686
name: Sync Templates

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@
2828
"screenshots": "node scripts/screenshot-all-templates.mjs",
2929
"query-counts": "node scripts/query-counts.mjs",
3030
"locale:extract": "pnpm --filter @emdash-cms/admin locale:extract",
31-
"locale:compile": "pnpm --filter @emdash-cms/admin locale:compile",
32-
"changeset:version": "pnpm changeset version && pnpm install --no-frozen-lockfile"
31+
"locale:compile": "pnpm --filter @emdash-cms/admin locale:compile"
3332
},
3433
"keywords": [],
3534
"author": "Matt Kane",

0 commit comments

Comments
 (0)