Skip to content

Migrate to pnpm, upgrade Changesets to v3, and gate the publish step - #13

Merged
nimble-turtle merged 1 commit into
mainfrom
chore/pnpm-and-changesets-v3
Sep 19, 2026
Merged

nimble-turtle merged 1 commit into
mainfrom
chore/pnpm-and-changesets-v3

Conversation

@nimble-turtle

Copy link
Copy Markdown
Contributor

Fixes the Release workflow failing on every push to main that carries no changeset.

Root cause

changeset publish ran, npm info returned stale data reporting the current version as unpublished, the publish was retried, and npm rejected it:

error an error occurred while publishing @activistchecklist/react-review-comments: undefined
You cannot publish over the previously published versions: 0.3.1.

Changesets 2.x anticipates exactly this — there is a comment in its source saying "npm info can return stale data at times so we need to gracefully handle this situation" — but the graceful path is gated on the error code:

if (json.error.code === "E403" && isAlreadyPublishedError(json.error.summary)) {
  return { result: "skipped" };
}

Modern npm reports no code for this error (note the literal undefined in the log above), so the guard never matches and the run fails instead of skipping. No 2.x release fixes this — 2.31.1, the newest, still has the gate.

This is not new. It is what made the run for chore: version packages (#8) red in May: 0.3.0 was not published by its own version PR, it was published by the next unrelated merge (#9). Timings confirm it — run #8 failed at 21:05, run #9 succeeded at 21:48, and 0.3.0 landed on npm at 21:48:50.

Why this also means leaving Yarn

Changesets v3.0.3 fixes it properly: it drops the E403 check and routes already-published to a result that is excluded from the failure list, so the command exits 0. Verified in both the sequential and bulk publish paths.

But v3 hard-refuses Yarn Classic:

if (await getYarnVersion(packages) === "classic")
  throw new Error("Yarn Classic is not supported. Please upgrade to Yarn Berry or another maintained package manager.");

So v3 requires leaving Yarn 1. This moves to pnpm, which v3 supports (engines: pnpm >=10).

Defence in depth

Three independent layers now have to fail before a release breaks:

  1. The gate (Decide whether changesets has work to do) skips changesets entirely when there are no pending changesets and the current version is already on npm. This alone fixes the reported failure.
  2. Changesets v3 treats an already-published version as success, so even if the gate is fooled by stale npm info, the run stays green.
  3. CI on PRs runs typecheck, tests, and build before any of this.

The gate's three branches were tested directly:

Situation Decision
No changeset, version already on npm (the bug) run=false — skip
No changeset, version not on npm run=true — publish
Pending changeset present run=true — version PR

OIDC trusted publishing

Publishing moves from npm publish to pnpm publish, so this matters. pnpm 10.x is a known-good line for npm OIDC trusted publishing — the OIDC regression was in pnpm 11.0.8 (pnpm#11513), fixed in 11.1.3+. packageManager pins pnpm@10.34.5.

The npm install -g npm@latest step is removed: pnpm performs the OIDC publish itself, and pulling a moving npm is what drifted the error shape that broke the 2.x guard to begin with.

Other changes

  • .gitignore no longer ignores pnpm-lock.yaml. The old comment described the stray-lockfile hazard from Remove stray pnpm-lock.yaml that breaks npm publish #9 — that is resolved by pnpm genuinely being the tool now, rather than being mistakenly detected.
  • package.json: build/prepack call pnpm run instead of yarn; pnpm.ignoredBuiltDependencies: ["esbuild"] records that esbuild's install script is intentionally not run (it ships prebuilt binaries — build verified working without it).
  • AGENTS.md documents the pnpm requirement.
  • README's install block is untouched: it lists npm/yarn/pnpm for consumers, which is still correct.

Verification

On a clean rm -rf node_modules && pnpm install:

  • pnpm install --frozen-lockfile — reproducible, no warnings
  • pnpm run typecheck — clean
  • pnpm run test — 72/72 passing
  • pnpm run build — succeeds
  • pnpm pack — exercises prepack; tarball contains exactly LICENSE, README.md, package.json, server, shared, src (no lockfile, no dist)

No changeset

Intentionally omitted — tooling only, nothing in the published package changes behaviour, so this is not a releasable change under AGENTS.md. With the new gate, merging this will correctly report 0.3.1 is already on npm -> nothing to release and skip.

What cannot be verified until the next real release

The OIDC publish through pnpm publish only exercises on an actual release. Everything up to that point is tested here. If it does fail, the fallback is to restore the registry-url-based npm path with an NPM_TOKEN secret.

🤖 Generated with Claude Code

Every push to main without a pending changeset failed the Release
workflow. changesets invoked publish, `npm info` returned stale data and
reported the current version as unpublished, the publish was retried, and
npm rejected it with "cannot publish over the previously published
versions". This is what made the run for "chore: version packages" (#8)
red in May; 0.3.0 was then published by the next unrelated merge (#9).

changesets 2.x anticipates stale `npm info` and has a graceful path for
it, but gates that path on `json.error.code === "E403"`. Modern npm
reports no code for this error, so the guard never matches and the run
fails instead of skipping. No 2.x release fixes this; 2.31.1 still has
the gate. Changesets v3 drops the code check and routes already-published
to a non-failure result that exits 0.

v3 refuses to run under Yarn Classic ("Yarn Classic is not supported"),
so adopting it means leaving Yarn 1. This moves the repo to pnpm, which
v3 supports (engines: pnpm >=10). pnpm 10.x is also a known-good line for
npm OIDC trusted publishing; the OIDC regression was in 11.0.8, fixed in
11.1.3.

Three layers now have to fail before a release breaks:

- the gate skips changesets entirely when there is nothing to release
- v3 treats an already-published version as success, not failure
- tests, typecheck, and build run on the PR before any of this

Also removes the global `npm install -g npm@latest` step: pnpm performs
the OIDC publish itself, and pulling a moving npm is what drifted the
error shape that broke the 2.x guard in the first place.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 19, 2026

Copy link
Copy Markdown

Review Change StackReview Change Stack

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: 44551a01-fd3c-43d7-8318-3361583aedb4

📥 Commits

Reviewing files that changed from the base of the PR and between 568ecc3 and 34d7272.

⛔ Files ignored due to path filters (2)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (5)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • .gitignore
  • AGENTS.md
  • package.json
 _______________________________________________________________________
< Simplicity does not precede complexity, but follows it. - Alan Perlis >
 -----------------------------------------------------------------------
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@nimble-turtle
nimble-turtle merged commit 260b2f6 into main Sep 19, 2026
1 of 2 checks passed
@nimble-turtle
nimble-turtle deleted the chore/pnpm-and-changesets-v3 branch September 19, 2026 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant