chore(release): automate the version and changelog surgery with cargo-release #329

Merged
jqueuniet merged 1 commit from chore/cargo-release into main 2026-09-05 10:42:41 +02:00
Owner

The mechanical half of a release was four hand edits, each with a trap the docs
had to warn about: [workspace.package], nine inter-crate requirements,
bindings/python/pyproject.toml (which cargo set-version cannot reach — its
omission is what shipped a 0.2.0 wheel disagreeing with its own library), then
retitling the changelog section, opening a fresh one, and rewriting two link
references.

cargo release <version> now does all of it, dry-run by default:

cargo release 0.2.2              # preview
cargo release 0.2.2 --execute    # apply, and commit

Configured not to tag, push or publish — tagging triggers the workflow that
publishes to three registries, so it stays a separate deliberate act after the
prepare commit has been reviewed. Changelog entries stay hand-written; only
the surgery is automated.

Two things the dry run turned up

pre-release-replacements resolves paths per-member. At workspace level it
went looking for crates/dm2-binrw/CHANGELOG.md and failed. The replacements
therefore sit on dm2-cli with ../../ paths, where they run once.

{{tag_name}} is not available to replacements. Used there it lands in the
file literally, behind a [WARN] Unrendered {{tag_name}} line that is easy to
miss — the first run wrote compare/{{tag_name}}...HEAD into the changelog. The
link references use v{{version}} instead.

Verification

Run for real against a throwaway clone, not just previewed:

  • the commit touches exactly Cargo.toml, Cargo.lock,
    bindings/python/pyproject.toml and CHANGELOG.md
  • all ten version references move (workspace + nine requirements), and
    cargo-release updates [workspace.dependencies] itself, so cargo set-version
    is no longer needed
  • no tag created, no remote touched
  • the resulting changelog is identical in shape to what was written by hand for
    0.2.1: fresh empty [Unreleased], the entries under ## [0.2.2] - <date>,
    [Unreleased] rebased and a new [0.2.2] reference added
  • cargo release config confirms publish = false, tag = false, push = false
    are in effect
  • prettier reports no new complaints on the generated file

The two <!-- next-header --> / <!-- next-url --> comments added to
CHANGELOG.md are what the replacements anchor on; exactly = 1 makes their
removal an error rather than a silent no-op.

cargo-release is packaged in nixpkgs (1.1.3).

The mechanical half of a release was four hand edits, each with a trap the docs had to warn about: `[workspace.package]`, nine inter-crate requirements, `bindings/python/pyproject.toml` (which `cargo set-version` cannot reach — its omission is what shipped a 0.2.0 wheel disagreeing with its own library), then retitling the changelog section, opening a fresh one, and rewriting two link references. `cargo release <version>` now does all of it, dry-run by default: ```sh cargo release 0.2.2 # preview cargo release 0.2.2 --execute # apply, and commit ``` Configured **not** to tag, push or publish — tagging triggers the workflow that publishes to three registries, so it stays a separate deliberate act after the prepare commit has been reviewed. Changelog *entries* stay hand-written; only the surgery is automated. ## Two things the dry run turned up **`pre-release-replacements` resolves paths per-member.** At workspace level it went looking for `crates/dm2-binrw/CHANGELOG.md` and failed. The replacements therefore sit on `dm2-cli` with `../../` paths, where they run once. **`{{tag_name}}` is not available to replacements.** Used there it lands in the file literally, behind a `[WARN] Unrendered {{tag_name}}` line that is easy to miss — the first run wrote `compare/{{tag_name}}...HEAD` into the changelog. The link references use `v{{version}}` instead. ## Verification Run for real against a throwaway clone, not just previewed: - the commit touches exactly `Cargo.toml`, `Cargo.lock`, `bindings/python/pyproject.toml` and `CHANGELOG.md` - all ten version references move (workspace + nine requirements), and cargo-release updates `[workspace.dependencies]` itself, so `cargo set-version` is no longer needed - no tag created, no remote touched - the resulting changelog is identical in shape to what was written by hand for 0.2.1: fresh empty `[Unreleased]`, the entries under `## [0.2.2] - <date>`, `[Unreleased]` rebased and a new `[0.2.2]` reference added - `cargo release config` confirms `publish = false`, `tag = false`, `push = false` are in effect - prettier reports no new complaints on the generated file The two `<!-- next-header -->` / `<!-- next-url -->` comments added to `CHANGELOG.md` are what the replacements anchor on; `exactly = 1` makes their removal an error rather than a silent no-op. cargo-release is packaged in nixpkgs (1.1.3).
chore(release): automate the version and changelog surgery with cargo-release
All checks were successful
CI / msrv (1.90) (pull_request) Successful in 42s
CI / audit (pull_request) Successful in 19s
CI / stable (pull_request) Successful in 1m42s
CI / python bindings (3.11) (pull_request) Successful in 46s
CI / msrv (1.90) (push) Successful in 40s
CI / audit (push) Successful in 19s
CI / stable (push) Successful in 1m42s
CI / python bindings (3.11) (push) Successful in 44s
a583b10dd0
The mechanical half of a release was four hand edits with a documented trap in
each: bump `[workspace.package]`, bump nine inter-crate requirements, bump
`bindings/python/pyproject.toml` — which `cargo set-version` cannot reach, and
whose omission shipped a 0.2.0 wheel disagreeing with its own library — and
then retitle the changelog section, open a fresh one and rewrite two link
references. `cargo release <version>` now does all of it, dry-run by default.

It is configured not to tag, push or publish. Tagging triggers the workflow
that publishes to three registries, so it stays a separate act after the
prepare commit has been reviewed.

Two details the dry run turned up rather than the documentation:

`pre-release-replacements` is inherited by every workspace member and its
paths resolve against that member's directory, so a workspace-level entry goes
looking for `crates/dm2-binrw/CHANGELOG.md`. The replacements therefore sit on
dm2-cli with `../../` paths, and run once.

`{{tag_name}}` is not available to replacements. Used there it is written into
the file literally, behind a warning that is easy to miss in the output — so
the link references use `v{{version}}`.

Verified by running it for real against a throwaway clone: the commit touches
exactly Cargo.toml, Cargo.lock, pyproject.toml and CHANGELOG.md; all ten
version references move; no tag and no push; and the resulting changelog
matches what was written by hand for 0.2.1.
jqueuniet deleted branch chore/cargo-release 2026-09-05 10:42:42 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
jqueuniet/dm2-tools!329
No description provided.