just release-plan leaves the tree dirty, so just release always aborts #36

Closed
opened 2026-09-01 04:39:24 +00:00 by logaritmisk · 0 comments
Owner

The two-step release workflow the justfile documents cannot be followed as written: Step 1 breaks Step 2 every time.

Hit while cutting v0.3.0.

Reproduction

$ just release-plan minor      # documented as "dry run, no writes"
   Upgrading trueskill-tt from 0.2.0 to 0.3.0
   ...
warning: aborting release due to dry run; re-run with `--execute`

$ just release minor
error: working tree is dirty — commit or stash first
error: recipe `release` failed with exit code 1

Cause

release.toml's pre-release hook runs even in dry-run mode:

pre-release-hook = ["sh", "-c", "git cliff -o CHANGELOG.md --tag {{version}} && git add CHANGELOG.md"]

So the "no writes" preview writes CHANGELOG.md and stages it. just release then hits its own guard:

if [[ -n "$(git status --porcelain)" ]]; then
    echo "error: working tree is dirty — commit or stash first" >&2; exit 1
fi

The guard is right — it is there because publishing is irreversible. The dry run is what should not be writing.

Both are documented in the justfile as the intended sequence (justfile:56-57), so anyone following the repo's own instructions hits this on every release. The workaround is git restore --staged --worktree CHANGELOG.md between the two steps, which is not obvious from the error.

Possible fixes

  • Make the hook a no-op under DRY_RUN=true, which cargo-release sets in the hook environment — e.g. [ "$DRY_RUN" = "true" ] || (git cliff ... && git add CHANGELOG.md). Preferred: the preview stays a preview, and the guard keeps its teeth.
  • Or have just release-plan clean up after itself.
  • Or, weakest, document the reset step in the justfile comment.

Worth confirming which environment variable the installed cargo-release version exposes to hooks before picking the first option.

The two-step release workflow the justfile documents cannot be followed as written: Step 1 breaks Step 2 every time. Hit while cutting v0.3.0. ## Reproduction ``` $ just release-plan minor # documented as "dry run, no writes" Upgrading trueskill-tt from 0.2.0 to 0.3.0 ... warning: aborting release due to dry run; re-run with `--execute` $ just release minor error: working tree is dirty — commit or stash first error: recipe `release` failed with exit code 1 ``` ## Cause `release.toml`'s pre-release hook runs even in dry-run mode: ```toml pre-release-hook = ["sh", "-c", "git cliff -o CHANGELOG.md --tag {{version}} && git add CHANGELOG.md"] ``` So the "no writes" preview writes `CHANGELOG.md` **and stages it**. `just release` then hits its own guard: ``` if [[ -n "$(git status --porcelain)" ]]; then echo "error: working tree is dirty — commit or stash first" >&2; exit 1 fi ``` The guard is right — it is there because publishing is irreversible. The dry run is what should not be writing. Both are documented in the justfile as the intended sequence (`justfile:56-57`), so anyone following the repo's own instructions hits this on every release. The workaround is `git restore --staged --worktree CHANGELOG.md` between the two steps, which is not obvious from the error. ## Possible fixes - Make the hook a no-op under `DRY_RUN=true`, which cargo-release sets in the hook environment — e.g. `[ "$DRY_RUN" = "true" ] || (git cliff ... && git add CHANGELOG.md)`. Preferred: the preview stays a preview, and the guard keeps its teeth. - Or have `just release-plan` clean up after itself. - Or, weakest, document the reset step in the justfile comment. Worth confirming which environment variable the installed cargo-release version exposes to hooks before picking the first option.
logaritmisk added the buginfra labels 2026-09-07 13:53:41 +00:00
Sign in to join this conversation.