Skip to content

Add scripts/cut-release.sh to automate cutting a release - #562

Merged
brawer merged 1 commit into
mainfrom
add-cut-release-script
Aug 10, 2026
Merged

Add scripts/cut-release.sh to automate cutting a release#562
brawer merged 1 commit into
mainfrom
add-cut-release-script

Conversation

@brawer

@brawer brawer commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Follow-up from the release-process review/discussion (see #561 and the discussion around it).

Until now, cutting a release meant manually bumping Cargo.toml (in practice this got skipped for the last 8 releases -- v0.6.1 through v0.6.8 were all cut with Cargo.toml still saying 0.6.0, which is also why the SBOM's own recorded osm-diffs version has been stale this whole time), then going to the GitHub web UI to pick a tag, generate notes, and publish.

cut-release.sh automates the mechanical parts end to end:

  1. Validates preconditions: on a clean, up-to-date main; the chosen tag doesn't already exist; the version is actually newer than Cargo.toml's current one; the latest CI run on main's current HEAD is a successful "Execute unit and integration tests" run.
  2. Bumps Cargo.toml's version (scoped to [package] only -- doesn't touch dependency version = fields) and syncs Cargo.lock's self-entry via cargo check.
  3. Opens a PR for that bump, enables auto-merge, and waits for it to clear required checks and the merge queue -- main is protected via a ruleset (pull_request + required_status_checks + merge_queue), so it can't just push directly; confirmed this via gh api repos/.../rules/branches/main.
  4. Once merged, creates the GitHub Release (tag + --generate-notes, using the existing .github/release.yml categories) at the new main HEAD.

That release tag is what triggers .github/workflows/release.yml (build, SBOM, attest) -- completely unchanged by this script.

The only manual step left is deciding the version number itself (major/minor/patch, based on whether the pipeline's output schema changed) and running the script. Everything mechanical -- the Cargo.toml/tag/notes consistency that kept drifting -- is now enforced by construction instead of relied on from memory. This also sets up baking the real release version into the binary later (Cargo.toml's version already becomes CARGO_PKG_VERSION at compile time, so once that's wired into the CLI/output, it'll reflect the true release version for free).

Testing

Verified each risky piece of logic in isolation, not the full live flow (which would create real PRs/tags/releases):

  • tag-format validation against valid/invalid inputs
  • the "is this version actually newer" guard, including the classic 9-vs-10 string-sort trap (0.9.0 -> 0.10.0)
  • the Cargo.toml rewrite, scoped correctly to [package] only, on a scratch copy of the real file (dependency version = fields untouched)
  • gh run list's JSON field names against the real repo

🤖 Generated with Claude Code

Until now, cutting a release meant: manually bumping Cargo.toml (in
practice, this got skipped for the last 8 releases -- v0.6.1 through
v0.6.8 were all cut with Cargo.toml still saying "0.6.0", which is
also why the SBOM's own recorded osm-diffs version has been stale
this whole time), then going to the GitHub web UI to pick a tag,
generate notes, and publish.

cut-release.sh automates the mechanical parts end to end:
  1. Validates preconditions: on a clean, up-to-date main; the chosen
     tag doesn't already exist; the version is actually newer than
     Cargo.toml's current one; the latest CI run on main's current
     HEAD is a successful "Execute unit and integration tests" run.
  2. Bumps Cargo.toml's version (scoped to [package] only, doesn't
     touch dependency "version = " fields) and syncs Cargo.lock's
     self-entry via `cargo check`.
  3. Opens a PR for that bump, enables auto-merge, and waits for it to
     clear required checks and the merge queue -- main is protected
     via a ruleset (pull_request + required_status_checks +
     merge_queue), so this can't just push directly.
  4. Once merged, creates the GitHub Release (tag + --generate-notes,
     using the existing .github/release.yml categories) at the new
     main HEAD.

That release tag is what triggers .github/workflows/release.yml
(build, SBOM, attest) -- completely unchanged by this script.

The only remaining manual step is deciding the version number itself
(major/minor/patch, based on whether the pipeline's output schema
changed) and running the script -- everything mechanical (the
Cargo.toml/tag/notes consistency that kept drifting) is now
enforced by construction instead of relied upon from memory.

Verified each risky piece of logic in isolation (not the full
live flow, which would create real PRs/tags/releases):
  - tag-format validation against valid/invalid inputs
  - the "is this version actually newer" guard, including the classic
    9-vs-10 string-sort trap (0.9.0 -> 0.10.0)
  - the Cargo.toml rewrite, scoped correctly to [package] only, on a
    scratch copy of the real file
  - `gh run list`'s JSON field names against the real repo
@brawer
brawer added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit bd5d5de Aug 10, 2026
4 checks passed
@brawer
brawer deleted the add-cut-release-script branch August 10, 2026 06:25
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.

1 participant