Releasing¶
How to cut a release for an OpsDev.nz module. All modules follow the same process — automated, reproducible, and gated through Test PyPI.
Conventions¶
| What | Rule |
|---|---|
| Versioning | Semantic Versioning — MAJOR.MINOR.PATCH |
| Tag format | v<version> (e.g. v0.1.0, v1.2.3) |
| Branch | main only — tags must point at a commit on main |
| Trigger | Push of a v* tag fires the publish workflow |
| Auth | Trusted Publishing (OIDC) — no API tokens |
Release Checklist¶
1. Prepare the release¶
On a branch off main:
# Bump version in pyproject.toml
version = "0.1.0"
# Add a changelog entry under [Unreleased], move to new [0.1.0] section
See Keep a Changelog for format.
2. Merge to main¶
Create a PR, get it reviewed, merge to main.
3. Tag and push¶
git checkout main
git pull origin main
git tag -s v0.1.0 -m "v0.1.0: first public release"
git push origin v0.1.0
Use -s to sign the tag with your GPG or SSH key.
4. Watch the pipeline¶
The push triggers .github/workflows/publish.yml. The pipeline runs two jobs:
| Job | What it does |
|---|---|
test-pypi |
Builds wheel, publishes to Test PyPI, installs from Test PyPI in a clean venv, runs <module> --version as a smoke test |
pypi |
Runs only if test-pypi passes. Builds wheel, publishes to real PyPI |
If the Test PyPI publish or smoke test fails, the real PyPI publish is aborted. Fix the issue, bump the patch version, and tag again.
5. Verify¶
Module-specific setup¶
Each module documents its own Trusted Publishing setup in
modules/<module>/docs/release-process.md. This includes:
- Which GitHub environments are configured (
test-pypi,pypi) - Links to the PyPI project pages for Trusted Publisher configuration
- Module-specific smoke test expectations
Dry-run releases¶
To validate the pipeline without publishing to real PyPI, temporarily comment
out the pypi job in the publish workflow, tag and push, then restore it
after confirming the Test PyPI job succeeds.