Skip to content

fix(release-automation): release-plz release_always = false to gate tag creation#151

Merged
githubrobbi merged 1 commit intomainfrom
fix/release-plz-release-always-false
May 8, 2026
Merged

fix(release-automation): release-plz release_always = false to gate tag creation#151
githubrobbi merged 1 commit intomainfrom
fix/release-plz-release-always-false

Conversation

@githubrobbi
Copy link
Copy Markdown
Collaborator

Summary

Single-line config change to release-plz.toml that fixes the R4 active-mode release job race observed on PR #149's merge (run 25549828912).

Root cause

release-plz default release_always = true makes the release job try to create a tag on EVERY push to main, racing the existing auto-tag-release.ymlrelease.yml chain (still active until R5). On PR #149's merge, the bespoke update_all_versions.rs left the CHANGELOG in a state release-plz couldn't reconcile with cliff.toml output, so release-plz committed a synthetic local fix-up (SHA 113f188...) and tried to tag that local SHA — meanwhile release.yml had already created the v0.5.91 tag at the real merge SHA 5ff321b04. Two tag-creators, one tag, race lost.

Fix

release_always = false flips release-plz release from "every push" to "only on merges of release-plz-* PRs" (matching our existing pr_branch_prefix = "release-plz-").

  • Bespoke just ship (branch release/vX.Y.Z) → no match → release job no-ops cleanly → release.yml is sole tag-creator. ✓
  • release-plz-driven (branch release-plz-vX.Y.Z) → matches → release job creates tag normally. ✓
  • Post-R5 steady state → only release-plz path remains → setting continues to gate correctly without modification.

Recommended setting per release-plz docs for any PR-gated release flow.

Files changed

File Change
release-plz.toml +59/-0 — single release_always = false line + 56-line rationale comment block
docs/architecture/release-automation-plan.md +1/-1 (effectively, two §8.1 deviation rows rewritten) — corrects "R4 baseline" row's misprediction ("silently treats as no-baseline" was wrong; actual is HARD-FAIL); adds new "R4 release-job race" row documenting this fix

Verification

  • taplo format --check release-plz.toml → ok
  • cargo fmt --check --all → ok
  • typos release-plz.toml docs/architecture/release-automation-plan.md → ok
  • lint-fast (staged) → 4s ok
  • lint-pre-push (workspace) → 4s ok (bucket 2 skipped, no rust/dep/infra)
  • Manual cross-check vs release-plz docs: release_always documented under [workspace] reference; pr_branch_prefix already set in our config

Related

… tag creation through release-plz-* PRs only

Why
---

The first R4 active-mode workflow run on PR #149's merge (run 25549828912)
failed the `release-plz-release` job with:

    failed to create ref refs/tags/v0.5.91 with sha 113f188...
    Reference update failed (HTTP 422)

Root cause: release-plz's default `release_always = true` makes the
`release` job attempt a tag-creation on EVERY push to `main`, racing
`auto-tag-release.yml` -> `release.yml` (the existing R3-era path
still active until R5 retires the bespoke flow).  On PR #149's merge:

  1. release-plz fired and tried to recompute the CHANGELOG (the bespoke
     `update_all_versions.rs` rewrites `## [0.5.90]` -> `## [0.5.91]`
     in place rather than producing a cliff-style entry, leaving state
     inconsistent with what release-plz expects).
  2. release-plz committed the recomputation locally (synthetic SHA
     `113f188...`) and tried to tag that SHA.
  3. Meanwhile `release.yml` had already created the `v0.5.91` tag at
     the actual merge commit `5ff321b04`.
  4. Two tag-creators racing for the same ref -> release-plz lost ->
     workflow turned RED.

Fix
---

Set `release_always = false` workspace-level in `release-plz.toml`.

This makes `release-plz release` only fire when the latest commit on
`main` is the merge of a PR whose branch starts with
`pr_branch_prefix` (`release-plz-`).

Coexistence semantics:

  * Bespoke `just ship` cycles use `release/vX.Y.Z` branch names ->
    NOT `release-plz-*` -> `release` job NO-OPS cleanly.
    `auto-tag-release.yml` + `release.yml` remain the sole tag-creator
    during the R4 -> R5 transition window.
  * release-plz-driven cycles use `release-plz-vX.Y.Z` branches ->
    matches the gate -> `release` job fires correctly.

Steady-state (post-R5): bespoke flow deleted -> only the
`release-plz-*` path remains -> `release_always = false` continues
gating correctly without modification.  This is the recommended
setting for any project using PR-gated releases per release-plz docs:
https://release-plz.ieni.dev/docs/config (search for `release_always`).

Documentation
-------------

Updates two rows in `docs/architecture/release-automation-plan.md`
\u00a78.1 deviations log:

  * Corrects the existing "R4 baseline" row's misprediction
    ("silently treats as no-baseline" -> actual: HARD-FAIL with
    `cargo package failed`).  Records the v0.5.91 bootstrap details
    (PR #149 squash-merged to `5ff321b04`; tag created by
    `auto-tag-release.yml` -> `release.yml`, NOT release-plz).
  * Adds a new "R4 release-job race" row capturing the symptom +
    root cause + this fix + the post-R5 forward-compat note.

Verification
------------

* `taplo format --check release-plz.toml` -> ok.
* `cargo fmt --check --all` -> ok.
* `typos release-plz.toml docs/architecture/release-automation-plan.md` -> ok.
* Manual cross-check vs release-plz docs: `release_always` field
  documented in https://release-plz.ieni.dev/docs/config under
  the `[workspace]` reference; `pr_branch_prefix` already set to
  `release-plz-` in our config (line 113).

Related
-------

* PR #148 (R4 active mode landed)
* PR #149 (v0.5.91 bootstrap via bespoke flow)
* PR #145 (R3.5 dep-version + R6 publishability)
* docs/architecture/release-automation-plan.md \u00a78.1 (deviations log)
@githubrobbi githubrobbi enabled auto-merge (squash) May 8, 2026 10:53
@githubrobbi githubrobbi merged commit 88beb96 into main May 8, 2026
18 checks passed
@githubrobbi githubrobbi deleted the fix/release-plz-release-always-false branch May 8, 2026 10:54
githubrobbi added a commit that referenced this pull request May 8, 2026
…153)

Phase R5 of `docs/architecture/release-automation-plan.md`.  Deletes the
parallel `auto-tag-release.yml` + `update_all_versions.rs` + `version-bump`
recipes track that has been driving releases since v0.4.x; release-plz
(R4 active since 2026-05-08) is now the sole version-bump + tag creator.
This is the point-of-no-return milestone for the release-automation
initiative; the bespoke flow can no longer be the fallback on the next
push to `main`.

Removed (~1430 LOC):

  - `.github/workflows/auto-tag-release.yml` (168 LOC).
  - `build/update_all_versions.rs` (1073 LOC).
  - `scripts/ci/ci-pipeline.rs` (53 LOC) — Phase 7 deprecation shim;
    `REMOVE-AFTER: v0.5.73` marker satisfied at v0.5.92.
  - `increment_version` + `version_bump` fns in
    `scripts/ci-pipeline/src/version.rs`.
  - `STEP_VERSION_INCREMENT` from `ALL_STEPS` in
    `scripts/ci-pipeline/src/workflow.rs`.
  - Version-bump step from `run_enhanced_phase2` (ship.rs) and
    `phase2_optimized` (phases.rs).
  - `version-bump` recipe in `just/build.just`.
  - Version-bump step from `quick-deploy` recipe in `just/dev.just`.
  - `!build/update_all_versions.rs` carve-out in `.gitignore`.

Added (~140 LOC, mostly comments + workflow YAML):

  - `detect-release-bump` short-circuit job in
    `.github/workflows/release-cache-warm.yml` — diffs
    `[workspace.package].version` between `HEAD` and `HEAD~1` and
    skips the warm matrix when the push is a version bump (saves
    ~165 runner-min/release because `release.yml` rebuilds + caches
    that same dep graph anyway).
  - Bridge step in `release-plz.yml`'s release job —
    `gh workflow run release.yml ...` after release-plz creates the
    workspace tag.  Replaces the GITHUB_TOKEN anti-loop workaround
    that R4 deferred to a future GitHub App / PAT setup; uses
    `workflow_dispatch` (explicitly carved out of the anti-loop
    policy) instead.  Flips `git_release_enable = false` in
    `release-plz.toml` so `release.yml` owns the GitHub Release page
    (avoids the body-overwrite race that softprops/action-gh-release
    would otherwise hit when run against a release-plz-created
    Release with `body_path: release-notes.md`).

Doc updates:

  - `docs/architecture/release-automation-plan.md` — flip R5 row to
    🟢, append four deviation log entries (v0.5.91 immutable-release
    lockout, R5-before-R4-bakein pragmatic acceleration, R5
    cache-warm short-circuit, R5 downstream-trigger bridge resolves
    prior R4 deferred row).
  - `docs/architecture/dev-flow-implementation-plan.md` — tick the
    final Phase 7 bake-in checkbox (deprecation shim retired,
    `REMOVE-AFTER: v0.5.73` satisfied at v0.5.92).
  - `CONTRIBUTING.md` — rewrite the Release row in the four-layer
    quality-gates matrix to describe the post-R5 release-plz flow.
  - `docs/publishing.md` — flip R3.5 / R5 / R6 status rows to landed;
    R4 stays 🟡 (active, bake-in pending first release-plz-driven
    release).
  - `docs/architecture/security/supply-chain-posture.md` — replace
    `auto-tag-release.yml` reference with the post-R5 chain.
  - Trailing comments in `release-plz.toml`, `Cargo.toml`,
    `scripts/ci-pipeline/Cargo.toml`, `.gitignore`, and
    `scripts/ci-pipeline/src/{version,workflow,ship,phases}.rs`
    rewritten to describe the post-R5 steady state and explicitly
    note the R5 retirement of any pre-R5 tooling they referenced.

Validation:

  - `cargo check --workspace --locked --all-targets` green.
  - `cargo clippy -p uffs-ci-pipeline --locked --all-targets
    -- -D warnings` green.
  - `cargo fmt --all` green.
  - `actionlint` on the two modified workflow YAML files green.
  - `just gates-drift` — manifest + consumers agree (23 gates).

R4 bake-in completes naturally on the next `feat:` / `fix:` / `perf:` /
`security:` commit to `main`, which release-plz will turn into the
first end-to-end release-plz-driven release (v0.5.93).  At that point
the R4 row in the dashboard flips to 🟢 in a follow-up commit.

Refs: #148 (R4 active-mode flip), #145 (R3.5 internal-dep version
requirements + R6 metadata), #151 (`release_always = false` gate),
#152 (v0.5.92 manual bootstrap after v0.5.91 immutable-release
lockout).
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