Release Process¶
Releases are human-triggered: a maintainer runs cz bump locally, which computes the new version from Conventional Commits, updates CHANGELOG.md, commits, and creates a signed tag. Pushing the tag fires the release.yml workflow, which publishes to PyPI and deploys versioned docs.
One-time infrastructure setup¶
Complete these steps once before the first v0.1.0 tag.
1. PyPI Trusted Publishing (OIDC)¶
On pypi.org → Your projects → repo-env → Publishing → Add a new pending publisher (or configure after first upload):
| Field | Value |
|---|---|
| PyPI project name | repo-env |
| Owner | ditschi |
| Repository name | repo-env |
| Workflow name | release.yml |
| Environment name | pypi |
Repeat on test.pypi.org with environment name testpypi.
No long-lived API tokens are stored in GitHub secrets — the workflow uses OIDC (id-token: write).
2. GitHub Environments¶
In the GitHub repo → Settings → Environments, create:
| Environment | Purpose | Suggested protection |
|---|---|---|
testpypi |
TestPyPI publish + install smoke test | Optional reviewers |
pypi |
Production PyPI publish | Required reviewers recommended |
Environment names must match release.yml (environment: name: testpypi / pypi).
3. GitHub Pages¶
Ensure GitHub Pages is enabled for the repo (deploy source: GitHub Actions / gh-pages branch from workflows).
4. Verify locally¶
Prerequisites (every release)¶
Install dev extras (includes commitizen and hatch-vcs):
Step-by-step¶
1. Ensure main is clean and green¶
2. Dry-run bump (see what would change)¶
cz inspects all commits since the last tag and prints the computed next version (patch / minor / major) based on commit types.
3. Run the bump¶
This:
- Computes the next SemVer version.
- Updates
CHANGELOG.md. - Commits with message
chore(release): bump version to X.Y.Z. - Creates an annotated git tag
vX.Y.Z.
For the first release when history predates Conventional Commits, ensure CHANGELOG.md has a sensible [0.1.0] section before bumping, or use cz bump --increment MINOR after reviewing cz bump --dry-run.
4. Push the commit and tag¶
5. CI takes over¶
The release.yml workflow fires on vX.Y.Z tags and:
- Builds sdist + wheel with
hatch build. - Publishes to TestPyPI and verifies install (
uv tool installfrom TestPyPI). - Publishes to PyPI via OIDC Trusted Publishing.
- Creates a GitHub Release with changelog notes for this version.
- Deploys versioned docs:
mike deploy X.Y.Z stable --update-aliases.
Every release runs TestPyPI first, then PyPI — there is no separate gate flag in the workflow.
6. Verify¶
Patch vs minor vs major¶
| Commit type(s) since last tag | Resulting bump |
|---|---|
fix, docs, refactor, test, build, ci, chore, perf, revert |
patch (0.0.x) |
feat |
minor (0.x.0) |
feat! or BREAKING CHANGE: footer |
major (x.0.0) |
Changelog¶
CHANGELOG.md at the repo root is auto-generated by cz changelog and updated on every cz bump. It follows the Keep a Changelog format.
To preview the changelog for unreleased commits:
Versioned docs¶
mike deploys each release as X.Y.Z and keeps a stable alias pointing to the latest stable release. The version selector dropdown in the docs site shows all deployed versions.
To list deployed versions:
Hotfix releases¶
For a hotfix on a previous minor: