Skip to content

fix: make minor version bump fully idempotent on retrigger#7276

Merged
gsarantid merged 2 commits into
mainfrom
fix-minor-bump-idempotency
Jul 9, 2026
Merged

fix: make minor version bump fully idempotent on retrigger#7276
gsarantid merged 2 commits into
mainfrom
fix-minor-bump-idempotency

Conversation

@gsarantid

@gsarantid gsarantid commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

When Nina retriggered unified-release-centralized-version-bump #35 yesterday after our 9.5.0 minor bump had already succeeded, cloudbeat-version-bump #36 re-ran bump-minor.sh with the same env vars (WORKFLOW=minor BRANCH=9.5 NEW_VERSION=9.5.0). By then main was at 9.6.0 (from merged #7268), and the sed inside update_version_beat unconditionally rewrote version.go back to 9.5.0, opening the now-closed #7275 — a PR proposing to downgrade main (verified: defaultBeatVersion and 4 ARM defaultValue fields all flipped 9.6.0 -> 9.5.0).

The existing no_new_commits guard couldn't tell the difference between "advance forward" and "regress backward" — it only asks "did anything change vs main?" — so the regression commits passed the check and got pushed.

This PR closes that gap and a related one in post-minor-merge.sh, with defense in depth so no future retrigger can produce a bad PR or a wrong-content release branch.

Fix — three layers

1. Top-level guard in bump-minor.sh

If main is already at next_minor_version(NEW_VERSION) (e.g. main = 9.6.0 while NEW_VERSION = 9.5.0), the entire minor bump has completed. Exit 0 before touching any files.

2. Hardened shared helpers in common.sh

New is_downgrade() helper using sort -V (so 9.10.0 > 9.9.0 sorts correctly). update_version_beat and update_arm_templates now call it before writing: if the current value is already >= the target, they refuse and log a clear message. Belt-and-suspenders — even if a future caller forgets the top-level guard, no downgrade can escape the shared helper.

3. Sanity check in post-minor-merge.sh's branch_out()

If main has drifted from NEW_VERSION at the moment we're about to cut the release branch, refuse and exit non-zero. Closes a related edge case (spotted during review): if main was advanced (e.g. via manual intervention or an out-of-order run) but the release branch was never cut, branch_out() previously would have silently cut ${BRANCH} from current main — producing a 9.5 release branch pointing at 9.6.0 code. Same philosophy as fail_if_stale_remote_branch (from #7227): detect the anomaly, fail clearly, require a human to fix the underlying state.

Related history

Explicit non-goals

  • bump-patch.sh unchanged — patch bumps only advance forward, no regression risk.
  • bump_main_to_next_minor() in post-minor-merge.sh unchanged — verified already idempotent (no_new_commits catches the "main already at target" case as a genuine sed no-op).

Test plan

  • is_downgrade unit tests — 9 cases pass, including the multi-digit 9.9.0 -> 9.10.0 case that naive lexical comparison would get wrong.
  • Retrigger simulation on real main (=9.6.0) with NEW_VERSION=9.5.0 DRY_RUN=true — exits 0 immediately with main is already at 9.6.0 — minor bump for 9.5.0 has already completed. Idempotent no-op. No branch, no commits, no PR.
  • Happy path (main=9.5.0, NEW_VERSION=9.7.0) — guard doesn't fire, full flow proceeds through update_version_beat (9.5.0 -> 9.7.0), update_arm_templates, update_mergify, and would gh pr create.
  • update_version_beat unit tests — regression attempt (9.6.0 -> 9.5.0) prints refusal and doesn't commit; upgrade (9.6.0 -> 9.7.0) commits cleanly; no-op (9.7.0 -> 9.7.0) doesn't create duplicate commits.
  • branch_out() sanity check — three paths validated:
    • Branch missing + main drifted -> refuses with clear error, exits 1
    • Branch missing + main correct -> proceeds normally (dry-run)
    • Branch already exists -> existing "branch exists" short-circuit fires first (sanity check skipped)
  • shellcheck clean on bump-minor.sh, common.sh, and post-minor-merge.sh.
  • Fork smoke test: [fork smoke test] fix: make bump-minor.sh idempotent on retrigger gsarantid/cloudbeat#5 — git plumbing verified end-to-end.

After merge

Cloudbeat-version-bump #36 becomes safe to unblock at its Wait for PR merge gate — post-minor-merge.sh is already idempotent, so branch_out() short-circuits (branch exists), bump_main_to_next_minor() no-ops (main already at 9.6.0), and the DRA-artifacts poll finds the already-published 9.5.0 artifacts.

When Nina retriggered the centralized version-bump pipeline yesterday
after our 9.5.0 bump had already succeeded, cloudbeat-version-bump #36
re-ran bump-minor.sh with the same env vars (NEW_VERSION=9.5.0). At that
point main was at 9.6.0 (from #7268), and the sed inside
update_version_beat happily rewrote version.go from 9.6.0 back to
9.5.0. The existing no_new_commits guard couldn't tell the difference
between "advance forward" and "regress backward" — it only asks "did
anything change vs main?" — so the regression commits passed the check
and the script pushed the resulting PR #7275 (now closed).

Two-layer fix:

1. bump-minor.sh: top-level guard. If main is already at
   next_minor_version(NEW_VERSION) (e.g. main=9.6.0 while
   NEW_VERSION=9.5.0), the entire bump has already completed. Exit 0
   before touching any files.

2. common.sh: new is_downgrade() helper (using sort -V so
   9.10.0 > 9.9.0 works correctly). update_version_beat and
   update_arm_templates now call it before writing: if the current
   value is >= the target, they refuse the write and log a clear
   message. Belt-and-suspenders — even if a caller forgets the
   top-level guard, no downgrade can escape the shared helper.

bump-patch.sh and post-minor-merge.sh are unchanged; patch bumps only
ever advance forward, and post-minor-merge is already idempotent via
its branch-exists check plus no_new_commits.

Co-authored-by: Cursor <cursoragent@cursor.com>
@gsarantid gsarantid requested a review from a team as a code owner July 9, 2026 08:27
@mergify

mergify Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

This pull request does not have a backport label. Could you fix it @gsarantid? 🙏
To fixup this pull request, you need to add the backport labels for the needed
branches, such as:

  • backport-v./d./d./d is the label to automatically backport to the 8./d branch. /d is the digit
  • backport-active-all is the label that automatically backports to all active branches.
  • backport-active-8 is the label that automatically backports to all active minor branches for the 8 major.
  • backport-active-9 is the label that automatically backports to all active minor branches for the 9 major.

@gsarantid gsarantid requested a review from groman92 July 9, 2026 08:33
@mergify

mergify Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

Defensive addition to branch_out() in post-minor-merge.sh: if main's
version.go doesn't match NEW_VERSION at the moment we're about to cut
the release branch, refuse and exit non-zero.

This closes a related idempotency gap: if main has been advanced (e.g.
via manual intervention outside the pipeline, or an out-of-order
run) but the release branch was never cut, the previous branch_out()
would silently cut ${BRANCH} from current main — producing a "9.5"
release branch pointing at 9.6.0 code. The new check catches this and
requires a human to create the branch manually from the correct
commit, matching the fail-fast philosophy already used by
fail_if_stale_remote_branch (from #7227).

Doesn't affect the normal flow — main == NEW_VERSION at cut time on
a clean pipeline run — and the pre-existing "branch already exists"
short-circuit still fires first when the branch is already cut.

Co-authored-by: Cursor <cursoragent@cursor.com>
@gsarantid gsarantid changed the title fix: make bump-minor.sh idempotent on retrigger fix: make minor version bump fully idempotent on retrigger Jul 9, 2026
@gsarantid gsarantid added this pull request to the merge queue Jul 9, 2026
Merged via the queue into main with commit e3cc831 Jul 9, 2026
12 checks passed
@gsarantid gsarantid deleted the fix-minor-bump-idempotency branch July 9, 2026 09:39
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.

3 participants