cfcc755702
* fix(release): restore PR-and-merge pattern — main is protected by a ruleset
The first real run of the new release workflow (run 25349824365) failed at
the push step with:
remote: error: GH013: Repository rule violations found for refs/heads/main.
remote: - Changes must be made through a pull request.
remote: ! [remote rejected] main -> main
main is protected by a ruleset that requires PRs. Earlier I checked
/repos/kdlbs/kandev/branches/main/protection (the classic branch-protection
endpoint), which reported "not protected" — but rulesets are a separate,
newer mechanism enforced at push time, not surfaced via that API. So the
"simplify to direct push" refactor in 53c2e45 was based on a false negative.
Restoring the PR-and-merge pattern that the legacy release-pr.sh used:
1. Bump version + regenerate CHANGELOG in working tree (separate step).
2. Create release/<TAG> branch, commit + push it.
3. gh pr create + gh pr merge --squash --delete-branch.
4. Pull squashed commit into local main, tag from there, push tag.
Restored pull-requests: write on the prepare job (needed for gh pr create).
Side note: --atomic in the failed run worked correctly. The tag push was
rejected together with main, so there's no orphan tag on origin from the
failed attempt.
* fix(release): retry tag push + document --auto trade-off
Two non-blocking review suggestions on PR #824:
1. Tag push hardened against transient failures. With the PR-and-merge
pattern, the merge and the tag push are separate operations. If the
tag push fails after the PR merges, main has the bumped commit but
no tag — leaving the release in a half-state where downstream jobs
never run and the next 'bump=patch' run computes the *next* patch,
skipping the originally-intended version.
Now: retry once on push failure. If both attempts fail, log the
recovery command (manual 'git push origin <TAG>') and exit non-zero
loudly so the operator knows what to do.
2. Inline comment documenting why we use 'gh pr merge' without --auto.
The current main ruleset only requires "PR required" — no status
checks — so immediate merge works. If status checks are added to
the ruleset later, this code needs to switch to --auto + polling
before the tag steps. No behavior change today.
* fix(release): delete stale release branch before pushing
If a release run fails after `git push -u origin release/<TAG>` but
before `gh pr merge` lands, the remote branch persists. Because main's
package.json hasn't been bumped, the next workflow run computes the same
NEXT version + same branch name, then fails at the push step with a
non-fast-forward rejection (same content, different SHA from the rebuild).
Recovery currently requires manually closing the stale PR and deleting
the remote branch.
Now: delete any stale remote branch with the same name as a no-op
prologue. GitHub auto-closes the corresponding stale PR when the head
branch disappears, so the subsequent `gh pr create` opens a fresh PR
cleanly.
Caught by Claude and Greptile (P1).