Skip to content

Upgrade to Changesets v3 and split the release workflow - #28

Merged
sa-maxencerb merged 1 commit into
mainfrom
chore/changesets-v3-upgrade
Sep 16, 2026
Merged

sa-maxencerb merged 1 commit into
mainfrom
chore/changesets-v3-upgrade

Conversation

@maxencerb

Copy link
Copy Markdown
Contributor

changesets/action@v2 hard-validates that the project is on @changesets/cli v3 (and tells v2 users to stay on @v1), so the action and the CLI have to move together. The v2 default also gives us GitHub-signed version commits, which was the original motivation.

Changes

@changesets/cli ^2.31.1 → ^3.0.3

.changeset/config.json — schema → @changesets/config@4.0.1, plus:

"privatePackages": { "version": true, "tag": false }

This one is required, not cosmetic. v3 stopped versioning private packages by default, which made @3flabs/guardian-test-fixtures implicitly ignored and turned the existing retargetter-request-path changeset into a hard failure:

Error: Found mixed changeset retargetter-request-path
Found ignored packages: @3flabs/guardian-test-fixtures
Found not ignored packages: @3flabs/guardian-defaults @3flabs/guardian-coordinator
Mixed changesets that contain both ignored and not ignored packages are not allowed

The config restores the previous behaviour: fixtures gets versioned, never tagged or published.

changeset:publish → changeset:prepack (build + the workspace:* rewrite). Under the pack flow the rewrite has to run before tarballs are built — each tarball freezes its manifest, and npm doesn't understand the workspace: protocol.

Workflow: one job → four

job permissions builds?
select-mode contents: read no
version contents: write, pull-requests: write no
pack contents: read yes
publish id-token: write, contents: write no

id-token: write now exists only in publish, and publish builds nothing — it uploads the tarballs pack produced. Previously the build ran in a job simultaneously holding OIDC, contents: write and pull-requests: write.

Version commits are signed as a side effect: push-with-git-cli defaults to false, so the commit goes through the GitHub API and GitHub signs it with its own GPG key — it lands on the Version PR as Verified instead of unsigned. Nothing shells out to git for writes anymore, so the Authenticate git for the changesets push step is deleted outright.

Other v2 breaking changes, and why they're no-ops here: env: GITHUB_TOKEN no longer configures the action (we rely on the github-token default); .npmrc/NPM_TOKEN handling was removed in favour of trusted publishing, which is already our setup; published-package detection moved from stdout parsing to a CHANGESETS_OUTPUT file, which propagates fine through bun run.

Verification

v3's release notes only name npm/pnpm/yarn, so bun compatibility was the main risk. Ran the real flow against this repo's actual changesets in a scratch worktree:

  • changeset version → correct bumps, workspace:* untouched, changelogs generated, no spurious reformatting
  • changeset publish-plan → correctly excludes the private fixtures package, orders by dependency
  • changeset pack → three tarballs, zero literal workspace: specifiers in their manifests, integrity hashes recorded in publish-plan.json

Locally green: build, typecheck, lint, format, fixtures check, tests.

Note on the changeset in this PR

.changeset/changesets-v3-release.md is a patch for all four packages, added to exercise the new pipeline end to end. Merging this PR runs the version path; merging the resulting Version PR runs pack → publish.

The publish half is the part I could not exercise without actually releasing — worth watching on the first run.

Follow-up worth considering

The publish job still runs bun install --frozen-lockfile while holding id-token: write, since it needs @changesets/cli present. That's the one remaining place where lifecycle scripts and the OIDC credential coexist. --ignore-scripts would close it; not done here because it needs testing against the dep tree.

`changesets/action@v2` validates that the project is on `@changesets/cli`
v3, so the action and the CLI have to move together:

- `@changesets/cli` ^2.31.1 -> ^3.0.3
- `.changeset/config.json`: bump the schema to `@changesets/config@4.0.1`
  and add `privatePackages: { version: true, tag: false }`. v3 stopped
  versioning private packages by default, which made
  `@3flabs/guardian-test-fixtures` implicitly ignored and turned
  `retargetter-request-path` into a hard "mixed changeset" error. This
  restores the previous behaviour: the fixtures package is versioned but
  never tagged or published.
- `changeset:publish` -> `changeset:prepack` (`build` + the `workspace:*`
  rewrite). Under the pack flow the rewrite has to run *before* tarballs
  are built, because each tarball freezes its manifest and npm does not
  understand the `workspace:` protocol.

release.yml goes from one job to four, each holding only what it needs:

  select-mode  contents: read
  version      contents: write, pull-requests: write
  pack         contents: read          <- build runs here
  publish      id-token: write, contents: write

`id-token: write` now exists only in `publish`, and `publish` builds
nothing — it uploads the tarballs `pack` produced. Previously the build
ran in a job simultaneously holding OIDC, `contents: write` and
`pull-requests: write`.

Version commits are also signed now: `push-with-git-cli` defaults to
false, so the commit is created through the GitHub API and GitHub signs
it with its own GPG key. Nothing shells out to git for writes anymore,
so the `Authenticate git for the changesets push` step is gone.

Verified against this repo before committing: `changeset version`
produces correct bumps with `workspace:*` untouched, `publish-plan`
excludes the private fixtures package, and `changeset pack` emits three
tarballs with zero literal `workspace:` specifiers in their manifests.
@changeset-bot

changeset-bot Bot commented Sep 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 109abf1

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 4 packages
Name Type
@3flabs/guardian Patch
@3flabs/guardian-defaults Patch
@3flabs/guardian-coordinator Patch
@3flabs/guardian-test-fixtures Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@sa-maxencerb
sa-maxencerb merged commit 43db013 into main Sep 16, 2026
1 check passed
@sa-maxencerb
sa-maxencerb deleted the chore/changesets-v3-upgrade branch September 16, 2026 12:43
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.

2 participants