fix(release): route alphas through a pull request like every other release - #556
Conversation
…lease The one-step `alpha` subcommand could never work in this repository. A ruleset covering `main` and `dev` requires a pull request on both, so committing the bump onto `dev` and pushing the branch was rejected with GH013 — the premise that "dev is already the integration branch, so the commit and tag land on it directly" was simply wrong. Nothing was published: `release.py` pushes the branch before tagging precisely so a rejected push cannot leave a dangling tag. `alpha` is replaced by `alpha-pr`, which is `release_pr` based on `dev`. The base is the only real difference between the two lines, and everything else derives from it: the target's track must be the one that ships from that base, only a `main`-bound release stamps the CHANGELOG, and the branch is named `rc-<base>/release/v<target>`. So the alpha flow is now the same reviewed path a beta takes, not a parallel one. `publish` derives its branch from the version's track as well, so one command serves both lines with no flag to get wrong, and `_tag_and_publish` no longer pushes a release branch at all. That push was never valid: the bump always arrives via a merged release PR, so it was either a no-op or a rule violation. It asserts the branch matches its remote instead, turning "the release PR has not merged yet" into a clear message. That also fixes the documented "from main directly" path, which the same ruleset had made impossible. Two smaller things found while fixing this: - `target_for` let `bump_version`'s `ValueError` escape as an unhandled traceback. `release-pr beta` on a line that is already a beta is an ordinary mistake; it now reports as a release error like every other rejection. - Tests cover the flow contracts that unit tests had missed: that `alpha-pr` targets `dev` and does not stamp, that `release-pr` does stamp, and that the publish path pushes the tag and nothing else.
adriannoes
left a comment
There was a problem hiding this comment.
Code and tests for routing alphas through alpha-pr look solid. What still blocks merge is leftover operator docs that teach the removed one-step alpha subcommand.
What worked well
alpha-propens a PR intodevthe same way product releases do.- Product stamp stays on
main; alphas skip CHANGELOG stamp as designed. _tag_and_publishpushes the tag only (no protected branch), andpublishpicks the branch from the version track.- Good regression coverage for the GH013 / branch-push removal.
Required before merge
-
RELEASE.md still presents
alphaas a live subcommand (inventory around the "subcommands are …" sentence) and still saysrelease.py alpharefuses ahead-of-main cuts, while argparse only registersalpha-pr. The new Cutting an alpha recipe is correct; these two leftovers teach a command that exits withinvalid choice. Please rename both toalpha-pr(and describe open-PR-into-dev, not a one-step cut ondev). Done when no prose recommends barerelease.py alpha, anduv run python scripts/release.py alpha --helpis not what any sentence points operators at. -
Under
## [Unreleased], ### Added still teaches one-stepscripts/release.py alpha <bump>(bump, commit, tag, push ondev), while the new ### Fixed entry says that command is replaced byalpha-pr. Because alphas do not stamp CHANGELOG, the Release workflow uses Unreleased as the alpha body, so both bullets ship together. Please rewrite the Added release-process bullet to the currentalpha-pr→ merge →publish(tag only) contract, or fold the obsolete one-step description into Fixed so Unreleased teaches a single path. Done when Unreleased no longer names a deletedalphasubcommand as current procedure.
Also noted
_apply_preparestill lists deleted calleralphain its docstring, and_tag_and_publishstill says it pushes the branch while the body andtest_tag_and_publish_never_pushes_the_branchassert tag-only push. Worth aligning those one-liners withalpha_prand tag-only push; not merge-blocking on its own.
Review path
Trusted author, checkout at the frozen head, 49 release pytest + ruff clean, CI lint/test green. No product MCP/CLI surface in this PR. Docs leftovers only.
…command Three leftovers taught a command argparse no longer registers, so following the prose landed on `invalid choice: 'alpha'`. RELEASE.md's subcommand inventory listed `alpha` and omitted `alpha-pr`, and the ahead-of-main paragraph credited the refusal to `release.py alpha`. Both now name `alpha-pr` and describe opening a PR into `dev` rather than a one-step cut. The CHANGELOG mattered more than an internal doc would: because alphas do not stamp, the Release workflow uses `## [Unreleased]` as an alpha's GitHub Release body, so the obsolete Added bullet would have published alongside the entry saying that command was replaced. Rather than reconcile the two, the Added bullet is rewritten to the `alpha-pr` -> merge -> `publish` contract and the Fixed entry is dropped: the one-step `alpha` never appeared in a release, so no reader has behavior to be told was fixed, and one unreleased cycle should describe its end state rather than the path it took to get there. Also aligned the two docstrings the review flagged: `_apply_prepare` listed `alpha` among its callers, and `_tag_and_publish`'s summary line still claimed it pushes the branch while its body and regression test assert tag-only.
|
All three were real, and the second one was the sharpest catch. Pushed in 8fab96d. RELEASE.mdThe subcommand inventory listed CHANGELOGYou are right that this is not a normal docs leftover, and the reason you gave is the one that matters: because alphas do not stamp, the Release workflow uses I went with the second option you offered, and a bit further. Rather than folding the obsolete description into Fixed, I rewrote the Added bullet to the DocstringsBoth aligned, and thanks for flagging them even as non-blocking — 300 tests, ruff clean, lockstep verify green. |
adriannoes
left a comment
There was a problem hiding this comment.
Follow-up 8fab96d closes the docs gaps that blocked merge.
RELEASE.md now teaches alpha-pr in both the inventory and the ahead-of-main refusal, and Unreleased Added describes a single alpha-pr -> merge -> publish path (dropping the Fixed narrative that would have shipped beside it in an alpha body). Docstrings for _tag_and_publish and the _apply_prepare callers list match the tag-only / alpha_pr contract.
Approving.
For later (non-blocking)
_apply_prepare still ends its stamp note with (see ``alpha``). Worth renaming that cross-ref to alpha_pr (or dropping the see-also) in a tiny follow-up so the deleted subcommand name does not linger in the module.
Motivation
The
alphasubcommand added in #554 could never work in this repository, and cutting the first real alpha is what proved it. A ruleset coveringmainanddevrequires a pull request on both, soalpha's "bump, commit ontodev, push the branch, then tag" was rejected withGH013: Changes must be made through a pull request. The premise in its docstring — thatdevis already the integration branch so the commit and tag can land on it directly — was just wrong, and no test caught it because none of them touch real branch protection.Nothing was published.
release.pypushes the branch before tagging precisely so a rejected push cannot leave a dangling tag, and that held: no tag locally or on the remote, no GitHub Release, PyPI 404.The same discovery invalidates a second path.
publishfrommainhas only ever worked because itsgit push origin mainis a no-op — the bump always arrives via a merged release PR, so no ref update is attempted and the rule never fires. Theprepareonmain→publishflow thatRELEASE.mddocumented would have failed identically.Outcome
Alphas now reach
devthrough a pull request, like every other release.alpha-prreplacesalphaand isrelease_prbased ondev: the base is the only real difference between the two lines, and everything else derives from it — the target's track must be the one that ships from that base, only amain-bound release stamps the CHANGELOG, and the branch is namedrc-<base>/release/v<target>. The alpha flow is the same reviewed path a beta takes rather than a parallel one, which is why this is a deletion of special-casing rather than an addition.publishderives its branch from the version's track too, so one command serves both lines with no flag to get wrong, and_tag_and_publishno longer pushes a release branch at all. It asserts the branch matches its remote instead, so an unmerged release PR is reported as such rather than surfacing as a rejected push. That also fixes themain-side path above.Two smaller things found while fixing it:
target_forletbump_version'sValueErrorescape as an unhandled traceback.release-pr betaon a line that is already a beta is an ordinary mistake, not a crash, and now reports like every other rejection.alpha-prtargetsdevand does not stamp, thatrelease-prdoes stamp, and that the publish path pushes the tag and nothing else. The last one is the regression test for this bug.Notes
The workflow-side guards from #554 — the ancestor check, the
## [Unreleased]fallback for alpha bodies, theprereleaseflag, and the installer-skip verification — are still unexercised, since no alpha tag has been pushed yet. Cuttingv0.5.0-alpha.1through this corrected flow is what will validate them.