Use this workflow when publishing a new version (backend + frontend + GitHub release + Docker Hub images).
From repo root:
./scripts/release.shDefault behavior with no version argument:
- Read latest git tag
vX.Y.Z - Auto-bump patch to
vX.Y.(Z+1) - Sync versions to:
Cargo.toml([package].version)package.json(root)frontend/package.json- Build + publish everything
# Exact version
./scripts/release.sh v1.0.3
./scripts/release.sh 1.0.3
# Auto-bump modes
./scripts/release.sh --patch # default
./scripts/release.sh --minor
./scripts/release.sh --major- Validate environment (
git/cargo/npm/podman/gh) and authentication. - Require a clean working tree.
- Resolve target version (explicit or auto-bumped).
- Update versions in Rust + frontend + root package files.
- Build frontend (
frontend/dist). - Build backend binaries:
x86_64-unknown-linux-muslaarch64-unknown-linux-musl
- Commit and tag:
- commit message:
release: vX.Y.Z - annotated tag:
vX.Y.Z - If version files already match the target version, skip the release commit and tag the current commit.
- Push branch and tag to GitHub.
- Build Docker images (explicit platforms):
--platform linux/amd64->docker.io/givenge/reader-rust:vX.Y.Z-x86_64--platform linux/arm64->docker.io/givenge/reader-rust:vX.Y.Z-aarch64
- Verify image architecture locally.
- Push versioned image tags.
- Update and push rolling tags:
latest(x86_64)latest-aarch64(arm64)
- Create GitHub Release using generated notes.
- Docker repository defaults to
docker.io/givenge/reader-rust. - Override repository if needed:
DOCKER_REPO=docker.io/yourname/reader-rust ./scripts/release.sh- If release already exists or tag exists, script exits early to avoid accidental overwrite.