Releasing
Last updated
The repeatable release runbook — staging validation, version bumps, signed tags, and release.yml.
On this page
How a new version ships. This runbook makes releases repeatable. It is the
last step of the contribution workflow: work flows
dev → staging → main, and this page is only ever run on a validated
staging state.
Versioning
Semantic Versioning. The single source of truth is
version in pyproject.toml; builds regenerate
src/comic_dl/_version.py from it. Never edit _version.py by hand — run
uv run scripts/write-version.py, bump any built-in adapter whose parsing
changed, then regenerate the site-support manifest with
uv run python scripts/update-site-manifest.py.
Branch flow
dev (unstable) → staging (validation) → main (production release)
dev receives all work via squash-merged PRs. staging is cut from dev
when release-ready and frozen for validation — full CI matrix plus packaging
smoke. main is production: every Monday, a validated staging state is
released to main as a new vX.Y.Z. staging proves the release before it
blocks dev; main only ever gets a validated, tagged state.
Before a release
- Fast-forward
stagingto thedevcommit you intend to ship (git merge --ff-only dev), or open astaging ← devPR. - Confirm CI is green on all runner OSes and
packaging.ymlpassed (distro install + Windows exe smoke). - Write the curated
CHANGELOG.mdentry (Added / Changed / Deprecated / Removed / Fixed / Security). - Bump
versioninpyproject.toml; regenerate_version.py. - Commit
chore: release vX.Y.Z(git commit -S). - Merge
stagingintomainvia squash PR (or fast-forward after review).
Cut the tag
git checkout main && git pull
git tag -s vX.Y.Z -m "Release X.Y.Z"
git push origin vX.Y.Z
The tag must equal version in pyproject.toml exactly — PEP 440
(v0.0.1, never v0.0.1-beta; the hyphen breaks arch/rpm versioning). Tags
are GPG-signed; the matching public key must be registered on the GitHub
account to display as Verified.
Pushing a v* tag triggers release.yml:
- package — tag/version gate, builds sdist + wheel (attached to the GitHub Release; PyPI publishing is best-effort).
- linux-packages —
.deb,.rpm,.pkg.tar.zstbuilt in containers, then installed into fresh containers and smoke-tested; a package that cannot install blocks the release. - windows-build —
comic-dl.exevia PyInstaller;self versionasserted against the tag. - release — downloads all artifacts, writes
SHA256SUMS, attaches to the Release.
Supported platforms
| Platform | Package | Architectures |
|---|---|---|
| Debian/Ubuntu | .deb |
amd64 (x86_64), arm64 (aarch64) |
| Fedora/RHEL | .rpm |
amd64, arm64 |
| Arch Linux | .pkg.tar.zst |
amd64 |
| Windows | .exe + .zip |
amd64 |
The sdist + wheel (py3-none-any) cover every other case. Not published:
macOS binaries (signing + notarization not yet in place), native ARM64
Windows, and Android. These are extension points, not promises.
Code signing
Every build job attests artifacts with SLSA build provenance via
actions/attest-build-provenance (Sigstore, keyless). The distro-package
attestation runs after the install-and-smoke-test validation. Verify any
downloaded file with:
gh attestation verify <file> --repo fallen020/comic-dl
The Windows comic-dl.exe remains Authenticode-unsigned; Authenticode
signing and macOS notarization are future enhancements.