feat(release): record the release version for Nix in the tagged commit #124

Merged
pti merged 1 commit from feat/release-nix-version into main 2026-11-03 09:55:05 +01:00
Owner

A flake cannot read Git tags, so nix profile install …?ref=refs/tags/wraptool-vX.Y.Z reported devel+<commit> instead of the release version. This makes the release script record the version where the flake can see it.

How it works

  • release-version builds a release commit on top of main that adds nix/release-version (containing e.g. 0.11.0) and signs the tag on that commit. It uses a temporary GIT_INDEX_FILE + commit-tree, so the working tree and current branch are untouched, and pushes only the tag — main never receives the commit. It refuses to run if nix/release-version exists on main. --dry-run creates the commit object (no refs) and prints it.
  • flake.nix picks the version in order: WRAPTOOL_VERSION (impure) → nix/release-version → devel+<short-sha>[-dirty].
  • lint.yml: release tags are no longer reachable from main, so git describe --abbrev=0 on main would stay at 0.10.0 forever. The SonarQube projectVersion now comes from the newest wraptool-v* tag by version sort.
  • publish-binaries.yml needs no change: it checks out the tag, checks rev-list -n1 tag == HEAD, and uses an exact-match describe.
  • Docs: releases.qmd (script behaviour; the tag stays the only version source, the file is a copy written from it), contributing.qmd (version precedence table), installation.qmd (Nix version note), CHANGELOG Unreleased.

Trade-off to be aware of

The Forgejo release, and git describe on main, now see the tag as off main's history. The release commit differs from main only by the one file, which nothing but Nix reads, so the binaries are identical.

Verified

  • test-release-version.sh (runs in CI) gains three cases, all passing:
    • dry run: release commit records the version, is a child of main, and leaves main and the tree untouched;
    • full --yes release against a throwaway remote (the gpg stub now fakes -bsau signing): annotated tag pushed, tag commit holds the file and is a child of main, remote main unchanged;
    • refusal when the file is on main.
  • Mutation check: tagging HEAD instead of the release commit makes the suite fail.
  • Flake, in a scratch clone: main-like commit → devel+ce5f73ddf7c7; commit with nix/release-version = 9.9.9 → 9.9.9, and the built binary prints wraptool 9.9.9; WRAPTOOL_VERSION=1.0.0 still wins.
  • Not verified: an actual signed release with the real key and CI's publish workflow — that happens on the next ./release-version. quarto render not run.

🤖 Generated with Claude Code

A flake cannot read Git tags, so `nix profile install …?ref=refs/tags/wraptool-vX.Y.Z` reported `devel+<commit>` instead of the release version. This makes the release script record the version where the flake can see it. ## How it works - **`release-version`** builds a release commit on top of `main` that adds `nix/release-version` (containing e.g. `0.11.0`) and signs the tag on **that** commit. It uses a temporary `GIT_INDEX_FILE` + `commit-tree`, so the working tree and current branch are untouched, and pushes only the tag — `main` never receives the commit. It refuses to run if `nix/release-version` exists on `main`. `--dry-run` creates the commit object (no refs) and prints it. - **`flake.nix`** picks the version in order: `WRAPTOOL_VERSION` (impure) → `nix/release-version` → `devel+<short-sha>[-dirty]`. - **`lint.yml`**: release tags are no longer reachable from `main`, so `git describe --abbrev=0` on `main` would stay at 0.10.0 forever. The SonarQube `projectVersion` now comes from the newest `wraptool-v*` tag by version sort. - `publish-binaries.yml` needs no change: it checks out the tag, checks `rev-list -n1 tag == HEAD`, and uses an exact-match describe. - Docs: `releases.qmd` (script behaviour; the tag stays the only version source, the file is a copy written from it), `contributing.qmd` (version precedence table), `installation.qmd` (Nix version note), CHANGELOG `Unreleased`. ## Trade-off to be aware of The Forgejo release, and `git describe` on `main`, now see the tag as off `main`'s history. The release commit differs from `main` only by the one file, which nothing but Nix reads, so the binaries are identical. ## Verified - `test-release-version.sh` (runs in CI) gains three cases, all passing: - dry run: release commit records the version, is a child of `main`, and leaves `main` and the tree untouched; - full `--yes` release against a throwaway remote (the gpg stub now fakes `-bsau` signing): annotated tag pushed, tag commit holds the file and is a child of `main`, remote `main` unchanged; - refusal when the file is on `main`. - Mutation check: tagging `HEAD` instead of the release commit makes the suite fail. - Flake, in a scratch clone: `main`-like commit → `devel+ce5f73ddf7c7`; commit with `nix/release-version` = `9.9.9` → `9.9.9`, and the built binary prints `wraptool 9.9.9`; `WRAPTOOL_VERSION=1.0.0` still wins. - Not verified: an actual signed release with the real key and CI's publish workflow — that happens on the next `./release-version`. `quarto render` not run. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(release): record the release version for Nix in the tagged commit
All checks were successful
Lint / lint (pull_request) Successful in 1m23s
Lint / sonarqube (pull_request) Has been skipped
42fda6b575
A flake cannot read Git tags, so a Nix build of a release tag reported
devel+<commit> instead of the release version. release-version now
tags a release commit on top of main that adds nix/release-version,
built with a temporary index so the checkout is untouched; the flake
prefers WRAPTOOL_VERSION, then that file, then devel+<short-sha>.
main never receives the commit, and the script refuses to run if the
file is on main, so development builds never report a stale version.

Release tags are therefore not reachable from main: SonarQube's
analysis version now comes from the newest tag by version sort instead
of git describe. publish-binaries is unaffected; it checks out the tag
and verifies it with an exact-match describe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pti merged commit c777caad24 into main 2026-11-03 09:55:05 +01:00
pti deleted branch feat/release-nix-version 2026-11-03 09:55:06 +01:00
Sign in to join this conversation.
No reviewers
No labels
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
pti/wraptool!124
No description provided.