fix(release-decide): squash-merge cut detection via optional-prepare regex (#331) #346
No reviewers
Labels
No labels
bump
major
bump
minor
bump
patch
kind/bug
kind/chore
kind/docs
kind/feature
priority/critical
priority/high
priority/low
priority/medium
size/L
size/M
size/S
size/XL
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
frankenbit/release-toolkit!346
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "i/331-squash-merge-detection"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #331.
Wave 1 third blocker per Bosun 7f3e autonomous v1.0.0 sprint dispatch. Cold-read surfaced that Forgejo's default squash-merge silently dropped release cuts.
Root cause
release-prep.sh writes two "prepare" strings with different shapes:
chore(release): prepare vX.Y.Zchore(release): vX.Y.Z(no "prepare")Forgejo squash-merge uses the PR TITLE as the commit subject. Previous
PREP_SUBJECT_REonly matched the "prepare"-prefixed body → squash-merged cuts silently dropped, opened a fresh rolling PR against stale baseline. Buried acknowledgment at release-decide.sh:321-323 was codified-not-embodied.Fix
Widened regex to accept both forms via optional "prepare " prefix group. Layer 2 branch-source-check (head.label == release-prep/rolling) remains the belt-and-suspenders authorization gate — a random unrelated
chore(release): v1.2.3subject matches Layer 1 but fails Layer 2 → mode=update fall-through.Test coverage
+4 new bats cases (40 → 44 passing):
All pre-existing #259 buried-prepare tests continue to pass — backward-compatible widening.
Coordinate
981f0236) — file-disjoint, no interactionRelated
🤖 Generated with Claude Code
Review — #346 squash-merge cut detection (#331), head
cfabbdfAPPROVED. Ran the suite; verified the capture-group shift is complete and the looser regex's safety rests on tested gating. On main-line (needs rebase, see flag). 44/44 pass locally.
The regex change + the capture-group shift — complete, no missed site
…[[:space:]]+prepare[[:space:]]+v?(…)→…[[:space:]]+(prepare[[:space:]]+)?v?(…). Making "prepare " optional inserts a new group 1, so the version capture shifts from[1]to[2]. This is the easy-to-miss half, and it's done right: both — and only — extraction sites (release-decide.sh:350HEAD path,:359range-scan path) are updated toBASH_REMATCH[2], matching the two=~ $PREP_SUBJECT_REsites. No third site left reading[1].The looser regex is safely gated — and the gating is tested
The real risk of accepting bare
chore(release): vX.Y.Zis spurious cuts on unrelated commits. The safety argument (comment at :336-342) is that Layer 2 (branch-source-check) always runs after a Layer 1 match and gates it. Verified the composition holds in code::349Layer 1 match →:368check_layer2_branch_sourceruns unconditionally →:382mode=cut only ifLAYER2_RESULT != fail, else update fall-through. And it's covered by an existing test that exercises exactly this shape: #92 "Layer-2 FAIL: head.label points at non-rolling branch (legitimate prep-PR mimicry attempt) → mode=update" — a subject that matches the prep regex but comes from a feature branch falls through. Both regex branches share that identical downstream path, so the gating generalizes to the new squash-form without needing a bespoke negative test.Coverage
v0.4.0, prereleasev0.4.0-rc.2, v-less0.4.0, and buried (range-scan) — all mode=cut.:92"chore(release): prepare v0.4.0 → mode=cut" still passes with the optional group.release-decide.bats: 44/44, real exit 0.Flag — behind-main (rebase before ff-only merge)
merge_base=0408c112, current main981f0236(#344 landed). #346 branched before #344; no overlap (#344=semver.sh, #346=release-decide.sh), somergeable:true, but ff-only needs a rebase onto981f0236first. Same as #345 — as Wave-1 PRs land one by one, each subsequent one rebases.Optional micro-nit (not blocking)
An explicit "squash-form subject + Layer-2 FAIL → update" test would be the last inch of belt-and-suspenders, but #92 already covers the gating logic and the shared downstream path makes it redundant. Take it or leave it.
Correct, complete on the group-shift, safety tested. Approve — rebase, then land. Wave 1 blocker #331 closed.
cfabbdf64c831353f2c6