Skip to content

fix(release): commit the standing PR's release branch with the PR title - #729

Merged
goosewobbler merged 10 commits into
mainfrom
fix/release-commit-subject
Oct 24, 2026
Merged

goosewobbler merged 10 commits into
mainfrom
fix/release-commit-subject

Conversation

@goosewobbler

@goosewobbler goosewobbler commented Oct 23, 2026 •

Copy link
Copy Markdown
Owner

Description

The standing PR's release branch holds a single commit, always titled chore: release preparation. With GitHub's default squash setting ("Default message"), a single-commit PR is squashed under that commit's subject rather than the PR title. So 0.42.0 landed on main as chore: release preparation (#614) rather than chore: release v0.42.0 (#614). Earlier releases got the PR title only because this repo's squash setting was "Pull request title" until recently.

  • The commit now uses the PR title, so the squash reads the same under any squash setting, including on repos that keep GitHub's default.
  • Fallback: the title is replaced by chore: release preparation, on both the commit and the PR, in two cases. The run warns each time, and the option's description says so.
    • It carries a CI-skip marker, which the merge would copy onto main, skipping the publish workflow. Always replaced.
    • It matches no release.ci.skipPatterns entry, so the merge would trigger another standing-PR update. Replaced only when the patterns match the fallback; otherwise the title is kept and the warning says the merge will trigger another update.
  • The PR title is now built before the commit instead of after.
  • Hooks: the release-branch commit honours git.skipHooks, as the publish stage's commit already does, so a commit-msg hook such as commitlint can be skipped for a custom title.

Related Issue(s)

None; seen on #614's merge.

Type of Change

  • feat — New feature
  • fix — Bug fix
  • docs — Documentation change
  • refactor — Code refactoring
  • test — Adding or updating tests
  • chore — Maintenance, dependencies, tooling
  • Breaking change — Requires major version bump

Scope

  • @releasekit/version
  • @releasekit/notes
  • @releasekit/publish
  • @releasekit/release
  • @releasekit/config
  • @releasekit/core
  • CI / workflows
  • Root / monorepo

Checklist

  • Lint passes (pnpm lint)
  • Tests pass (pnpm test)
  • Typecheck passes (pnpm typecheck)
  • Documentation updated (if applicable)
  • Breaking changes noted in description

Testing Notes

  • New tests drive runStandingPRUpdate and check both the release commit's subject and the PR title:
    • The default sync title chore: release v1.2.3 is used as is, with no warning.
    • chore: release preparation replaces a title that matches no skip pattern, and a title with a CI-skip marker, including when custom skip patterns miss the fallback.
    • The title is kept, with a warning, when the skip patterns match neither it nor the fallback, and when there are none.
    • An existing standing PR is retitled to match the commit.
    • git.skipHooks reaches the release commit, set and unset.
    • All nine fail against main's standing-pr.ts.
  • Gate: pnpm lint, and typecheck and tests for @releasekit/release (864) and @releasekit/config (230), pass. schema:check and docs:check pass.

🤖 Generated with Claude Code

RetriggerView in GreptileConfidence Score: 5/5

The PR appears safe to merge.

Summary

The release branch commit now uses the standing PR title when it matches skipPatterns and contains no CI-skip marker.

  • Standing release PRs use a safe title for their commit and pull request.

Reviews (3) · Last reviewed commit: "fix(release): align standing PR title wi..." · Reviewed by Greptile

@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Standing release PR: #730 · v0.42.1 queued (4 packages) · open 5h 54m · ✅ ready to merge

Release Preview — v0.42.0 → v0.42.1

Note: Labels on this PR are advisory in standing-pr mode. Bumps come from conventional commits in the standing PR; override by editing labels on the standing PR itself. Add release:immediate to bypass the standing PR and release this PR directly.

These changes will be added to the release PR (#730) when merged:

Changelog

monorepo 0.42.0 → 0.42.1

Changed

  • drop the half of the title comment the warnings repeat (release)
  • state the standing PR title fallback the same way everywhere (release)
  • cover jsonOutput when disabled; fix inverted guard test (version) (PR #754 · closes #725)
  • drop versionCalculator tests that mocked a missing helper (version) (PR #755 · closes #726)
  • link standing-pr.yml comments to published ci-setup URLs (templates) (PR #756 · closes #728)
  • tighten the standing PR title comment (release)
  • drop a comment the title check now covers (release)
  • bump anthropics/claude-code-action from 1.0.252 to 1.0.255 (deps) (PR #746)

Fixed

  • honour git.skipHooks on the standing PR's release commit (release)
  • fall back to the fixed standing PR title only when it's safe (release)
  • keep root changelog history when several packages release (notes) (PR #775 · closes #736)
  • warn when the standing PR title falls back (release)
  • align standing PR title with safe commit subject (release)
  • drop an entry's own refs from LLM-rewritten descriptions (notes) (PR #747 · closes #719)
  • keep CI-skip markers out of the release commit (release)
  • commit the standing PR's release branch with the PR title (release)

All packages → 0.42.1 (sync versioning)

  • @releasekit/version
  • @releasekit/notes
  • @releasekit/publish
  • @releasekit/release

After merge — predicted release

No version escalation — this PR's changes will be included in the queued release without affecting the projected versions.

Package Standing PR This PR After merge
monorepo 0.42.1 0.42.1 0.42.1

Updated automatically by ReleaseKit

Comment thread packages/release/src/standing-pr/standing-pr.ts Outdated
github-actions Bot and others added 2 commits October 23, 2026 19:37
GitHub's default squash title for a single-commit PR is the commit's
subject, so v0.42.0 landed on main as "chore: release preparation (#614)"
instead of "chore: release v0.42.0 (#614)". The release branch's commit
now uses the PR title, falling back to the fixed subject when a custom
title matches no skip pattern.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A custom standing-PR title carrying a CI-skip marker would otherwise reach
the release commit, and a single-commit squash would copy it onto main and
skip the publish workflow. Such a title now falls back to the fixed subject.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@goosewobbler
goosewobbler force-pushed the fix/release-commit-subject branch from cb56e53 to 9db0382 Compare October 23, 2026 18:38
Co-authored-by: Cursor <cursoragent@cursor.com>
@goosewobbler

Copy link
Copy Markdown
Owner Author

@greptile review

github-actions Bot and others added 2 commits October 23, 2026 22:14
A custom title that matches no skip pattern, or carries a CI-skip marker,
was silently replaced on both the commit and the PR. The run now warns, and
the `title` option's description says when the fallback applies.

The commit subject and PR title are one variable again, and one test covers
both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The comment below says the title must match a skip pattern, and the code
enforces it, so the note on the default titles repeated it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
goosewobbler pushed a commit that referenced this pull request Oct 23, 2026
Both PRs added fields at the same spot in setupGit, so whichever merged
second conflicted. These seeds now sit elsewhere in the helper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@goosewobbler goosewobbler added this to the 0.42.1 milestone Oct 23, 2026
github-actions Bot and others added 3 commits October 24, 2026 00:34
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… safe

The fallback subject was never checked against release.ci.skipPatterns.
With custom or empty patterns, even the default title failed the check
and was replaced by a subject that matched nothing either, so the PR lost
its title and the merge still triggered another standing-PR update.

A title with a CI-skip marker is still always replaced. A title the skip
patterns miss is replaced only when they match the fallback; otherwise
it's kept, with a warning that the merge will trigger another update.

Tests cover custom and empty skip patterns, the warnings, and retitling
an existing standing PR. The ci-setup and release README tables now state
the rule and list ${tag}.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The release-branch commit now carries the standing PR title, which a
consumer configures, so a commit-msg hook such as commitlint can reject
it. The publish stage's commit already respects git.skipHooks; the
standing PR's commit now does too. Unset still runs the hooks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
github-actions Bot and others added 2 commits October 24, 2026 01:12
…ywhere

ci-setup.md said the fallback applied only when the skip patterns match
it, but a title with a CI-skip marker is always replaced. The schema
description now says which titles are replaced, and both tables name
the non-sync default.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…peat

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@goosewobbler
goosewobbler merged commit 9fb7581 into main Oct 24, 2026
33 checks passed
@goosewobbler
goosewobbler deleted the fix/release-commit-subject branch October 24, 2026 00:28
goosewobbler added a commit that referenced this pull request Oct 24, 2026
… pnpm setup (#753)

* fix(ci): standing-PR templates — publish concurrency, LLM on publish, pnpm setup

Fixes #739

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(release): guard release branch delete against concurrent updates

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(ci): pass LLM provider keys on immediate releases

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(ci): give closed-PR runs a group per PR so a queued publish isn't replaced

The workflows had gone back to one shared group for push, schedule and
merge runs, which is the bug #739 reports: GitHub keeps one pending run
per group, so a newer push or schedule run replaced a queued publish. A
shared closed-PR group has the same flaw, since an ordinary PR closing
could replace it. Events on a closed PR (publish on merge, a retry label)
now each get a group per PR. The branch-delete guard already in this PR
covers the update that can now run alongside a publish.

Also:
- troubleshooting.md and the ci-setup troubleshooting row point the LLM
  key at the publishing jobs, not update-release-pr;
- the ci-setup update job lists all three provider keys again;
- a test checks the guard still deletes a branch whose tip matches.

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

* docs(ci): list every job in the standing-PR secrets table

The table said "both jobs" for GITHUB_TOKEN and left retry-publish off
the NPM_TOKEN row, but the workflow now has four jobs and retry-publish
publishes too.

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

* test(release): move the setupGit ref seeds away from #729's status seed

Both PRs added fields at the same spot in setupGit, so whichever merged
second conflicted. These seeds now sit elsewhere in the helper.

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

* fix(release): delete the release branch under a lease

The tip check and the delete were separate steps, so an update's
force-push landing between them was still deleted, and a failed fetch
left the check comparing stale data. Delete with --force-with-lease
pinned to the manifest's releaseBranchSha instead, which the remote
checks atomically, and keep cleanup errors as warnings so they can't
fail a finished publish. Drops Git.resolveRef, which only the old check
used, and validates releaseBranchSha in the manifest schema.

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

* fix(ci): stop closed-PR events cancelling or replacing a publish

A maintainer's edit on a merged PR landed in the per-PR closed group
with cancel-in-progress on, so it cancelled a running publish. Only the
publish on merge and the retry label now use that group, events on a
closed PR that run no job get a group of their own, and only edits on
an open PR cancel.

The publish jobs now end with refresh-after-release, so an update that
ran during the publish is rebuilt once the tags exist. Also adds the
example immediate-release job's .npmrc step, restores the preview-notes
keys on the example update job, adds LLM keys to the ci-setup retry
job, and brings ci-setup, the example README and the release README's
preview snippet in line.

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

* fix(release): lease the branch delete on the merged PR's head

The merged PR's head commit is what was merged, so lease the delete on
it instead of a manifest field. That also covers manifests written
before this change and a hand push to release/next before the merge.
If the head can't be read, or isn't a commit SHA, keep the branch and
warn. Adds headSha to the forge's PullRequestDetails and drops the
manifest's releaseBranchSha. A null lease no longer crashes the push.

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

* fix(ci): keep immediate releases queued with updates

Only the standing PR's own merge and retry runs get a per-PR group. A
merged release:immediate PR goes back to the shared group, so it no
longer writes release/next at the same time as the update from its own
merge. Drops the reconcile step added to the publish jobs: it checks
the job's checkout, the tagged merge commit, before fetching main, so
it closed a standing PR an update had just opened.

The template moves to Node 24 like the example, since OIDC trusted
publishing needs a newer npm than Node 22 ships. The npm hints now say
to drop pnpm/action-setup, and the retry label notes mention the
concurrency group.

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

* fix(git): refuse a push lease whose expect isn't a commit SHA

An empty expect means "only if the ref is absent" to git, and a symbolic
one is resolved locally, so either silently changes what the lease
checks.

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

* fix(ci): keep immediate-release off the standing PR, and tidy hints

immediate-release now skips the standing PR itself, so a standing PR
carrying release:immediate doesn't publish twice. The npm hints also
swap `pnpm exec` for `npx`, the templates say pnpm/action-setup needs a
`packageManager` field or a `version`, and deleteBranchOnMerge says when
publish keeps the branch.

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

* fix(ci): match the standing branch exactly, and harden the lease checks

The immediate-release guard and the concurrency group matched any
`release/*` head, so a release:immediate hotfix from `release/hotfix-x`
was skipped and shipped nothing. Both now match `release/next`, the
hardcoded default like the label names.

The lease check is shared as isCommitSha from @releasekit/git, a lease
the remote refuses mid-update counts as a moved branch rather than a
failed delete, and the warning says whether the head was unreadable or
not a SHA. The deleteBranchOnMerge: false tests seed a head commit, so
they now fail if the flag is ignored.

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

* fix(release): fall back to the event's head commit for the delete lease

If reading the merged PR from GitHub fails, the event payload that
triggered the publish already holds the same head commit, so use it
rather than keeping the branch. Also treats GitHub's "incorrect old
value provided" as a refused lease, not a failed delete.

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

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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