Skip to content

fix(release): add bump=none to iterate pre-release trains#1909

Merged
guibeira merged 1 commit into
mainfrom
fix/release-versions
Jun 24, 2026
Merged

fix(release): add bump=none to iterate pre-release trains#1909
guibeira merged 1 commit into
mainfrom
fix/release-versions

Conversation

@guibeira

@guibeira guibeira commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Problem

A stable release landed 0.19.6 when it should have been 0.19.5.

Sequence that broke:

  • stable 0.19.4
  • next0.19.5-next.1
  • next again → 0.19.6-next.1 (should be 0.19.5-next.2)
  • stable → promotes → 0.19.6 (should be 0.19.5)

Root cause

Two compounding factors:

  1. bump_manifests.py writes the pre-release version (0.19.5-next.1) into engine/Cargo.toml, which is the calculator's source for "current".
  2. The patch path in calculate_release_version.py always does bump_base(cur.base, "patch") — it cannot iterate an existing train (calculate_version only iterates for minor/major). So a second patch + next on top of 0.19.5-next.1 computes bump_base("0.19.5") = 0.19.6.

Single next per patch worked (that's why earlier patch releases were fine); the bug only surfaces with multiple next pre-releases on the same patch release.

Fix

Add a none bump that iterates an in-flight pre-release train without advancing the base:

  • patch/minor/major start a train (they pick the base).
  • none iterates it (0.19.5-next.1.2.3), then promote → 0.19.5.

none anchors on the highest pre-release base above the latest stable; when none exists it falls back to the latest stable, preserving alpha-release.yml semantics (which relies on --bump none anchoring on the current stable, in its own iii-alpha/ namespace).

Changes

  • calculate_release_version.py: new highest_inflight_prerelease_base() helper + rewritten bump="none" path.
  • create-tag.yml: 4th bump option none; pre-flight rejects bump=none + prerelease=none.
  • tests: +13 (helper, in-flight iteration, prefix isolation, full release sequence). 132 passing.

Usage

When bump pre
1st pre-release (sets base) patch/minor/major next
iterate pre-releases none next
stable patch/minor/major none

Note

Residual footgun unchanged: using patch (instead of none) to iterate still re-bumps the base. none is the correct iterate path. Not blocked here because changing the base mid-train is sometimes intended.

Summary by CodeRabbit

  • New Features

    • Added support for a special none release option that continues an existing prerelease line instead of always moving to a new patch version.
    • Expanded release workflow options to include none and added clearer guidance for how it behaves.
  • Bug Fixes

    • Improved version selection so prerelease iterations stay on the correct version track and don’t jump ahead unexpectedly.
    • Added validation to prevent invalid none release combinations.

Repeated `next` pre-releases on a patch-level release advanced the base
instead of iterating the counter: 0.19.5-next.1 -> 0.19.6-next.1, so the
stable promote landed 0.19.6 instead of 0.19.5. Cause: the `patch` path
always re-bumps cur.base, and the manifest carries the in-flight
pre-release version, so each repeated patch+next re-bumped the base.

Add a `none` bump that iterates an in-flight pre-release train (highest
pre-release base above the latest stable) without advancing the base,
falling back to the latest stable when no train exists (preserves
alpha-release semantics). patch/minor/major still START a train; none
ITERATES it.

- calculate_release_version.py: highest_inflight_prerelease_base() helper
  + rewritten bump="none" path.
- create-tag.yml: 4th bump option `none`; pre-flight rejects none+none.
- tests: helper, in-flight iteration, prefix isolation, full sequence.
@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
iii-website Ready Ready Preview, Comment Jun 24, 2026 11:35am

Request Review

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0adf97ea-a851-4c32-a9bc-8833e4c7c06d

📥 Commits

Reviewing files that changed from the base of the PR and between 32477c9 and 65892b6.

📒 Files selected for processing (3)
  • .github/scripts/calculate_release_version.py
  • .github/scripts/test_calculate_release_version.py
  • .github/workflows/create-tag.yml

📝 Walkthrough

Walkthrough

Adds highest_inflight_prerelease_base to calculate_release_version.py, which scans existing tags to find the highest prerelease base above the latest stable. The calculate_version function's bump_type="none" path is updated to anchor on this in-flight base when one exists. Tests cover the new helper and updated path. The create-tag workflow gains none as a selectable bump input with a validation guard.

Changes

In-flight prerelease base anchoring for bump_type="none"

Layer / File(s) Summary
highest_inflight_prerelease_base helper and calculate_version integration
.github/scripts/calculate_release_version.py
Adds highest_inflight_prerelease_base that regex-scans tag strings to find the highest prerelease base strictly above latest_stable. Updates calculate_version docs and the bump_type="none" branch to use this in-flight base when available, falling back to latest_stable or current base otherwise.
Unit and integration tests
.github/scripts/test_calculate_release_version.py
Imports the new helper and adds TestHighestInflightPrereleaseBase (empty input, stable-floor filtering, highest-base selection, prefix scoping, null stable floor, numeric comparison). Extends TestCalculateVersionBumpNone with in-flight iteration, multi-candidate selection, channel switching, below-stable filtering, prefix isolation, and a full patch→none→promote cycle test.
create-tag workflow: none bump option and validation guard
.github/workflows/create-tag.yml
Adds none to the bump input choices with updated description. Adds a pre-flight check that emits an error and exits when bump=none and prerelease=none are both supplied.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • iii-hq/iii#1429: Modifies the same create-tag workflow's bump_version() logic to avoid bumping the base when a prerelease channel is already present — directly related to how prerelease train identity is maintained.
  • iii-hq/iii#1692: Modifies the same calculate_release_version.py prerelease/channel bumping logic and its test coverage, building the prerelease counter mechanics that this PR extends with in-flight base scanning.

Suggested reviewers

  • anthonyiscoding
  • andersonleal

Poem

🐇 Hippity-hop, the versions align,
No more skipping ahead down the line!
In-flight trains get anchored with care,
The highest base found floating up there.
bump=none now knows just where to stay —
Promoting to stable on release day! 🏷️

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding bump=none to iterate prerelease trains.
Description check ✅ Passed The description covers the problem, rationale, changes, and usage; it is mostly complete despite using different headings than the template.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/release-versions

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@guibeira guibeira marked this pull request as ready for review June 24, 2026 11:40
@guibeira guibeira merged commit b3dcd90 into main Jun 24, 2026
38 checks passed
@guibeira guibeira deleted the fix/release-versions branch June 24, 2026 12:37
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.

2 participants