Skip to content

chore: release through a PR because main is protected - #363

Merged
Kudo merged 4 commits into
mainfrom
@kudo/release-pr
Oct 20, 2026
Merged

Kudo merged 4 commits into
mainfrom
@kudo/release-pr

Conversation

@Kudo

@Kudo Kudo commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

Why

The release after #362 failed with GH006: Protected branch update failed, because main only accepts changes through a PR. @semantic-release/git pushes the release commit straight to main. Nothing was published: there's no 9.0.1 tag or release, and v9 didn't move.

How

Release in two steps, with no new dependencies:

  1. Running the workflow with release runs semantic-release --dry-run. A small inline plugin in .releaserc.js saves the next version and notes. The job bumps package.json, adds the notes to CHANGELOG.md and pushes release/x.y.z. The job summary has a link that opens a chore: create new release x.y.z PR with the title filled in.
  2. When that PR merges, the publish job checks the merge before it releases anything. The merged PR must come from release/<version>, have exactly one commit, and be based on the commit right before the merge. The last check keeps PRs that merged while the release PR was open from shipping without changelog entries. Then the job creates the x.y.z tag and GitHub release from the newest CHANGELOG.md section, and moves v<major>. If a check fails, revert the release PR and run the workflow again.

A person opens the release PR, not the workflow. So Actions doesn't need the "Allow GitHub Actions to create and approve pull requests" setting, which would also let workflows approve PRs. And review and test run on the release PR.

Dependency code runs with a write token in dryrun and release-pr, so this also tightens those jobs:

  • The workflow sets permissions: {}, and each job asks only for contents: write. semantic-release checks push access even in dry-run mode, so dryrun needs it too.
  • Install with bun install --frozen-lockfile, so only the locked versions install.
  • Run gh auth setup-git before the push, so the token isn't in the command line or .git/config.

@semantic-release/changelog, @semantic-release/exec and @semantic-release/git aren't used anymore, so I removed them. The lockfile change only moves existing packages around. It adds no new versions.

Things to know:

  • @semantic-release/github no longer posts "released in" comments or labels on issues and PRs.
  • Merge the release PR before any other PR. Re-running the workflow with the same version force-pushes the same branch. A new version pushes a new branch, and the old PR needs to be closed.

Test Plan

🤖 Generated with Claude Code

Kudo added 4 commits October 21, 2026 01:35
main only accepts changes through PRs, so semantic-release can no longer
push the release commit. Open a release PR with the version and changelog,
and create the tag and GitHub release after it merges.
Opening the PR from Actions needs a repo setting that also lets workflows
approve PRs. Push the branch and link the PR instead, so CI also runs on
it. Limit token permissions, install from the lockfile only, and keep the
token out of the push command.
Only publish when the merge came from the release branch with one commit,
and nothing else merged while it was open. Otherwise other changes would
ship without changelog entries.
Retry the PR lookup, since GitHub may not link a new commit to its PR
right away. Skip creating the release when it already exists, so a re-run
can still move the major tag.
@Kudo
Kudo marked this pull request as ready for review October 20, 2026 18:25
@Kudo
Kudo merged commit a018023 into main Oct 20, 2026
14 checks passed
@Kudo
Kudo deleted the @kudo/release-pr branch October 20, 2026 18:26
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