fix(release): make pr mode tag on merge instead of on the pre-bump commit - #936
Conversation
There was a problem hiding this comment.
The two-phase split (propose without tagging/publishing, finalize by reading committed versions rather than recomputing) is sound, and the chore(release):-in-window guard correctly avoids treating a hand-edited version file as a merged release. Mode gating in execute.rs (tag creation, tag push, release publish) is consistent for both the Pr-proposing path and the finalizing→None path. Good test coverage for the single-package cases described in the PR.
Two non-blocking observations:
Nit: In a monorepo, finalizing is a single global bool derived from !finalize_tags.is_empty() (mod.rs). If any package needs finalizing, bump_order is set to &[] for the whole run, so proposing/bumping for every other package is skipped entirely that run — not just tag/release creation for the finalizing package. Unless another commit lands on the target branch soon after, unrelated packages with pending commits won't get their release PR opened/updated until the next trigger. Might be worth scoping the skip to just the packages being finalized rather than gating the entire per-package loop.
Nit: finalize_tags is forced to empty whenever dry_run is true (mod.rs), and ferrflow check always calls run_release_logic with dry_run: true (check.rs). So ferrflow check right after a release PR merges will report "nothing to release" instead of previewing the pending finalize — easy to be confused by if anyone relies on check to see what the next real run will do.
Neither affects the core single-package flow this PR is fixing.
SonarQube — 2 issue(s) introduite(s) par cette PR
2 issue(s) corrigée(s) sur les fichiers touchés. Comparaison entre le projet bac à sable de cette PR et la branche par défaut : SonarQube Community n'analyse pas les PR, ce delta est calculé côté CI. Détail |
Closes #934.
Splits
releaseCommitMode: "pr"into the two phases it always needed.Proposing. Compute the bump, write the files onto the release branch, open or update the PR. No tags, no GitHub releases. Every later commit on the target branch regenerates the branch, so the open PR keeps tracking the version that would ship now.
Finalising. After the PR merges, a
chore(release):commit sits on the target branch carrying versions that no tag covers. That run tags exactly those versions and publishes the releases.The versions are read from the version files, never recomputed. That is the part the issue flagged as load-bearing: gating the tags alone would have left the merge proposing
1.1.0 → 1.2.0instead of tagging1.1.0, and every merged release PR would have spawned another one a notch higher.Shape
ReleasePlangainsfinalizing, which resolves the mode toNonefor that run. One flag covers both halves: the commit step becomes a no-op because the files are already committed, and the tag and release steps run because the mode is no longerPr.finalize::merged_release_tagsdoes the detection. For each package it reads the version from the first versioned file, computes the tag through the existingtag_for_version, and keeps it only when that tag is missing and achore(release):commit appears in the window since the package's last tag. The second condition is what stops a hand-edited version file from being tagged as if it had been released.Verified end to end
Against real repositories with a local bare remote, not just unit tests.
Proposing, no tags anywhere:
Finalising after the merge:
The tag now lands on the commit that carries the bump, and the version there matches the tag. A third run reports "Nothing to release", so it is idempotent.
Squash merge takes the same path, tagging the squash commit with
1.1.0present.And the symptom that started this, the PR never updating, is gone. A second
feat!:landing onmainbefore the merge regenerates the branch:Before this change run2 said "Nothing to release".
Tests
Five unit tests on the detection, including a commit that merely mentions
chore(release):in its text and must not trigger finalisation, and prerelease detection from the version.Four tests on the gating itself, through the existing forge harness:
prmode creates no tags locally, pushes none, and publishes no releases; finalising does all three; finalising tags the release commit rather than the one behind it; andcommitmode still does everything in one pass.1191 bin tests and 909 lib tests passing, clippy clean, wasm surface still builds.
Limits worth knowing
A package with no
versionedFileshas no version to read, so it is not finalised this way.commitmode remains the answer for tag-only packages. Called out in the README rather than left to be discovered.is_prereleaseis derived by parsing the version, since the finalising run has no bump plan to inherit it from. Non-semver versions fall back tofalse.Existing repositories
Anything already on
prmode has tags one commit behind their bump and releases published for PRs that may never merge. Those are not repaired by this change. IdleWarden/idlewarden#1 is the case from the issue and needs its 12 tags and 12 releases removed by hand before it can release cleanly again.