Skip to content

Refactor release workflow to decouple versioning from publishing - #404

Merged
kraenhansen merged 2 commits into
mainfrom
claude/release-workflow-approvals-7sdp00
Aug 12, 2026
Merged

Refactor release workflow to decouple versioning from publishing#404
kraenhansen merged 2 commits into
mainfrom
claude/release-workflow-approvals-7sdp00

Conversation

@kraenhansen

Copy link
Copy Markdown
Collaborator

Summary

Restructures the release workflow to separate the "decide what to do" phase from the "do it" phase, eliminating unnecessary deployment approvals for non-release commits and preventing version PRs from being blocked by pending publish approvals.

Key Changes

  • Split into three jobs: Introduces a mode job that determines whether to version, publish, or skip; a version job that creates the "Version Packages" PR; and a publish job that publishes to NPM
  • Removed workflow-level concurrency: Replaced with job-specific concurrency groups to prevent version PRs from being held up by pending publish approvals
  • Conditional job execution: The version and publish jobs only run when their respective modes are selected, avoiding unnecessary deployment approvals for chore/docs/CI commits
  • Updated permissions:
    • version job: contents: write and pull-requests: write (no environment required)
    • publish job: contents: write and id-token: write (requires main environment approval)
  • Scoped npm config: Moved npm_config_force: true to the publish step only, with a comment explaining why it shouldn't be workflow-level
  • Updated action calls: Changed from changesets/action@v2 to the split changesets/action/select-mode@v2, changesets/action/version@v2, and changesets/action/publish@v2

Implementation Details

The workflow now uses changesets' split actions to answer "what should happen?" before doing it. This allows:

  • Version PRs to be created without waiting for deployment approval
  • Non-release commits to skip the approval queue entirely
  • Publishing to remain gated behind the main environment approval
  • Better concurrency control with separate groups for versioning and publishing

https://claude.ai/code/session_016jd2RhdRGxJ76QtBGnFTFJ

claude added 2 commits August 12, 2026 08:35
The release workflow ran everything in a single job bound to the "main"
environment, so opening the "Version Packages" pull request — and any push
to main that had nothing to release — queued up a deployment approval.

Split it in two:

- A "Version" job with no environment, running changesets/action without a
  publish-script so it can only ever open/update the pull request. It runs
  on ubuntu-latest and skips the Android/Rust/cpp toolchain setup, none of
  which versioning needs.
- A "Publish" job that keeps `environment: main` and the full toolchain, and
  only runs when there are no pending changesets and the registry is
  actually missing one of our package versions.

The registry check is a new `unpublished-packages` script: it asks the same
question `changeset publish` asks, so chores, docs and CI commits no longer
leave a deployment waiting for approval on a no-op publish.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jd2RhdRGxJ76QtBGnFTFJ
Replaces the hand-rolled registry check from the previous commit with
`changesets/action/select-mode`, which the action's README points to for
repos on trusted publishing ("it's recommended to set up the individual
sub-actions instead to tighten publish permissions").

select-mode answers 'version', 'publish' or 'none' — internally by way of
`changeset publish-plan`, new in the Changesets v3 we just moved to. That is
exactly the signal scripts/unpublished-packages.ts was computing by hand, so
the script and its package.json entry are gone. The sub-action also gets the
edge cases right: changesets that release nothing report 'none' rather than
'version', and packages needing only a git tag are part of the plan.

Because publish-plan reaches the registry through `pnpm info`, the select
step needs the same npm_config_force escape hatch as publishing. It stays
step-scoped rather than workflow-scoped: as workflow env it would also reach
`pnpm install`, where force means "recreate the lockfile".

Also drops the workflow-level concurrency group. A publish waiting for its
deployment approval used to hold that group, so no later push could refresh
the version pull request until someone approved — the same class of blockage
this change is meant to remove. The version and publish jobs carry their own
groups instead, so they serialise against themselves but not each other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016jd2RhdRGxJ76QtBGnFTFJ
@kraenhansen kraenhansen self-assigned this Aug 12, 2026
@kraenhansen kraenhansen added the CI Continuous integration label Aug 12, 2026
@kraenhansen
kraenhansen merged commit b647224 into main Aug 12, 2026
9 checks passed
@kraenhansen
kraenhansen deleted the claude/release-workflow-approvals-7sdp00 branch August 12, 2026 09:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI Continuous integration

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants