Skip to main content

Release workflow (prepare / publish / announce)

Every release invocation, the stages it runs, and which one to reach for

Anodizer's release pipeline is one ordered list of stages. Most operators run it end-to-end via anodizer release, but a handful of dedicated entry points let you split, resume, or re-fire individual phases without rebuilding from scratch. This page enumerates every supported invocation and exactly which stages it runs.

State machine

InvocationStages runStages skippedUse case
anodizer releaseallnonenormal release
anodizer release --snapshotlocal stagesblob, publish, snapcraft-publish, announcelocal dry-run (no upstream side effects)
anodizer release --prepare (alias --prepare-only)build, archive, nfpm, sbom, checksum, signrelease, docker, docker-sign, blob, publish, snapcraft-publish, announce, verify-releasesplit-merge flow: prepare artifacts locally before manual review
anodizer release --publish-onlysign, release, blob, publish, snapcraft-publish, announcebuild, archive, nfpm, sbom, checksumresume from prepared dist/ after manual review or after the Determinism Harness preserved dist/
anodizer release --announce-onlyannounce, after-hooksevery other stagere-fire announcers after a transient announce failure (Slack 502, Discord 5xx)
anodizer publishrelease, blob, publish, snapcraft-publishevery other stagepublish-only subcommand; overlaps with release --publish-only (see below)
anodizer publish --mergeshard-merge → release, blob, publish, snapcraft-publishevery other stagesplit-merge multi-host flow (mirrors GR Pro goreleaser publish --merge)
anodizer announceannounceevery other stageannounce-only subcommand
anodizer announce --mergeshard-merge → announceevery other stagesplit-merge multi-host flow (mirrors GR Pro goreleaser announce --merge)
anodizer continuerelease, blob, publish, snapcraft-publish, announce, after-hooksbuild, archive, nfpm, sbom, checksum, signsingle-host stage-resume (paused release, transient publish failure)
anodizer continue --mergeshard-merge → sign, checksum, sbom, release, blob, publish, snapcraft-publish, announcebuild, archive, nfpmmulti-host split-merge resume (mirrors GR Pro goreleaser continue --merge)

anodizer tag rollback is the deliberate-withdrawal command for the post-failure recovery flow; see Release Resilience for the full flag matrix and recovery flags for the surrounding context.

For composition with the --skip= flag (used to drop individual stages from any invocation above), see the inline help on anodizer release --skip --help.

release --prepare vs release --publish-only

These are the two halves of the split-merge flow.

# Phase 1: prepare dist on the build host
anodizer release --prepare

# (manual review of dist/ — diff archives, verify checksums, ...)

# Phase 2: publish from the same host
anodizer release --publish-only

--prepare runs every artifact-producing stage (build / archive / nfpm / sbom / checksum / sign) and leaves them in dist/. --publish-only consumes that tree and runs the upload chain.

The --prepare-only alias exists for GR-imported scripts; it is a literal alias for --prepare.

release --announce-only vs anodizer announce

Both re-fire announcers without re-publishing.

# Flag form: re-fire against the configured dist/ + the prior run's report.json
anodizer release --announce-only

# Subcommand form: same, but accepts --dist to point at a non-default tree
anodizer announce --dist /path/to/preserved-dist

release --announce-only derives the run id from the current git tag / short commit (matching the writer that produced <dist>/run-<id>/report.json); anodizer announce does not require the report file and announces fresh from the dist's artifacts.json.

Both honor the nightly short-circuit — announcers never fire on a nightly tag, matching GoReleaser's customization/publish/nightlies.md rule.

publish vs continue

Both consume a populated dist/ and run the release / blob / publish chain. They differ in framing and post-hooks:

Aspectanodizer publishanodizer continue
Stagesrelease, blob, publish, snapcraft-publishrelease, blob, publish, snapcraft-publish, announce, after-hooks
Framing"run the publish chain""resume a stalled release"
GR Pro analoggoreleaser publishgoreleaser continue
--merge modeshard-merge then publishshard-merge then full post-build pipeline
Recommended forpublishing a one-off dist treeresuming a paused (--prepare) or stalled release

Neither is being deprecated. Prefer continue for the resume-after-failure use case; reach for publish when you explicitly want the unframed publish chain without the announce / after-hook fan-out.

continue resumes STAGES; a plain re-run reconciles PUBLISHERS. They answer different questions, so pick by what failed:

What failedWhat to type
a build/package stage, or a --prepare run is paused mid-pipelineanodizer continue — the completed stages are not redone
a publisher, with dist/ already populatedre-run the identical anodizer release command — every publisher reconciles and self-skips (see Release resilience)

Idempotency of --publish-only retries

release --publish-only is safe to re-run against a dist/ that already has a <dist>/run-<id>/report.json. Publishers converge: each one reconciles against its own upstream before dispatching and skips itself when this exact version is already landed there.

$ anodizer release --publish-only
   • skipping cargo — already published for this version (all 3 planned crate(s) already on crates.io with verified content)
   • skipping homebrew — already published for this version (open PR for widget 0.2.1: https://github.com/acme/homebrew-tap/pull/41)
   • pushing widget_0.2.1_amd64.deb (deb) → https://push.fury.io/acme (gemfury account 'acme')

Reconciliation fails toward publishing — a publisher skips only on a full positive match of package name and version upstream, so an unreachable registry or an ambiguous response still attempts the publish rather than assuming it succeeded.

Two things this does NOT replace:

  1. Deliberate withdrawal. anodizer tag rollback still exists to withdraw a release you've decided should not exist — deleting the tag, reverting the bump commit, and unwinding whatever already published. Re-running release only converges forward; it never undoes anything.
  2. Content drift. If a version is already published upstream with different content, that publisher records a failure telling you to bump the version. Immutable releases cannot be overwritten by re-running.

The contract for report.json: it exists for human triage. Skip decisions come from the live upstream state via each publisher's reconcile(), never from the report.

See also