GitHub is the release authority for rustnzb. Release tags use the vX.Y.Z
format and must point to a commit reachable from main.
The container image is published to GHCR (…/rustnzbd) on three tag channels:
:latest— the current stable release. Moved only by a stablevX.Y.Zrelease.:beta— the newest pre-release, for soak testing before a stable promotion. A pre-release tag never moves:latest.:vX.Y.Z/:vX.Y.Z-beta.N— immutable, one per tag.
Pre-release tags use a suffix: vX.Y.Z-beta.N (also -rc.N / -alpha.N).
They are flagged as GitHub pre-releases and publish only :vX.Y.Z-beta.N and
:beta. Cutting a pre-release tag is how a build enters soak testing.
Prefer shipping a stable release only after a pre-release has soaked:
- Tag a pre-release on a
maincommit, e.g.v1.5.0-beta.1, and push it. The release workflow publishes:v1.5.0-beta.1+:betaand a GitHub pre-release.:latestis untouched. - Let it soak. Bump the suffix (
-beta.2, …) for fixes during soak. - When satisfied, run the Promote pre-release to stable workflow
(
workflow_dispatch) with the soaked tag. It copies the exact image digest that soaked to:v1.5.0+:latest, then rebuilds the standalone release binaries from the same commit and publishes the stable GitHub release.
Because promotion copies the soaked image by digest, :v1.5.0 is byte-identical
to the beta that was tested; only the tag changes. The image's own embedded
build ref therefore still reads the pre-release version it was built as — that
is the promoted lineage, not a rebuild. The standalone binaries are rebuilt and
carry the stable version.
A stable vX.Y.Z tag pushed directly (a hotfix without soak) still works and
takes the rebuild path below.
-
Update the workspace version in
Cargo.tomland any user-visible version metadata. -
Run the checks in DEVELOPMENT.md.
-
Merge the release change to
mainthrough a reviewed pull request. -
Create and push an annotated
vX.Y.Ztag on thatmaincommit. -
Monitor the GitHub Actions release workflow.
-
Verify the GitHub release assets, checksums, and multi-architecture GHCR image:
ghcr.io/thedancingdeveloper-org/rustnzbd:vX.Y.Z ghcr.io/thedancingdeveloper-org/rustnzbd:latest
GitHub generates release notes from the tagged history. Review them before publishing; do not add version-specific release-note files to the repository.
The seven nzb-* crates under crates/ are published to crates.io from
standalone repositories (one per crate, named in ci/nzb-crates.txt, URL in
each crate's repository field). This monorepo is the head:
- The monorepo owns version numbers. Change a crate's
versiononly incrates/<name>/Cargo.toml; the standalone repos never originate a bump. Keep each new version strictly above the crates.io maximum for that crate. - Standalone repos are sync targets.
ci/tasks/sync-crate <name>exportscrates/<name>atHEADand opens a pull request on that crate's standalone repo. It never publishes and never pushes to the monorepo. - Publish only from a synced tag. After a sync PR merges, publish that
crate from a
vX.Y.Ztag on the standalone repo — never from an out-of-sync tree. - Drift is gated. The scheduled
crate-driftjob (.github/workflows/quality-schedule.yml, viaci/tasks/crate-drift) fails when any standalone repo'ssrc/or package version differs from the monorepo. A failure means a crate changed here without a sync; runci/tasks/sync-crate <name>, merge, and publish from the tag.
Do not move or replace a published tag. Revert the faulty change on main,
release a new patch version, and publish a new tag. Operators should pin an
immutable image tag rather than relying on latest for controlled rollouts.