Release Process
May 31, 2026 ยท View on GitHub
This is the maintainer runbook for releasing climate_indices. Releases are
tag-based from main; pushing a valid release tag starts the GitHub Actions
release workflow and publishes to PyPI through Trusted Publishing.
Release invariants
mainis trunk and must be releasable.- Release tags use exact SemVer format:
vX.Y.Z. - Package versions omit the leading
v:X.Y.Z. - The Git tag,
pyproject.toml, GitHub Release, and PyPI version must match. - Tag creation and tag pushes require maintainer approval.
- Long-lived
release/*branches are avoided except for approved maintenance work on older supported versions.
Pre-release checklist
- Confirm the release scope and version number.
- Start from current
main:git switch main git pull --ff-only origin main - Create a release-prep branch:
git switch -c chore/release-X.Y.Z - Update
pyproject.tomltoX.Y.Z. - Update
CHANGELOG.mdwith## [X.Y.Z] - YYYY-MM-DD. - Update
RELEASE_NOTES.mdor related docs when needed. - Run validation locally.
- Open a PR into
main. - Merge only after review and passing CI.
Validation commands
Run the normal quality gate:
uv run ruff check src/ tests/
uv run ruff format --check src/ tests/
uv run mypy src/
uv run pytest
Run release integrity checks before pushing a tag:
uv run pytest tests/test_release_integrity.py
Build and inspect package artifacts when preparing the release PR:
uv run python -m build
uv run twine check dist/*
Tag creation
After the release PR is merged and main is green, create the annotated tag
from main only after maintainer approval:
git switch main
git pull --ff-only origin main
git tag -a vX.Y.Z -m "Release vX.Y.Z"
Verify the tag points at the intended commit:
git show --stat vX.Y.Z
git status --short
Push the tag only after approval:
git push origin vX.Y.Z
Do not force-push, rewrite release history, delete remote tags, or reuse a published version.
GitHub Actions release workflow
The release workflow is .github/workflows/release.yml.
It runs on tags matching v*.*.* and also has a bash regex guard requiring the
exact format vX.Y.Z. The workflow:
- Checks out the tagged commit.
- Validates the release tag format.
- Runs linting, formatting checks, type checking, tests, and release integrity tests.
- Runs the security audit.
- Verifies the tag version equals
pyproject.tomlversion. - Builds source and wheel artifacts with
python -m build. - Runs
twine check. - Uploads build artifacts to the workflow run.
- Publishes to PyPI through Trusted Publishing/OIDC.
- Creates a GitHub Release for the tag with generated release notes and attached artifacts.
The publish job uses the release environment, so GitHub environment approval
is required before PyPI publication.
PyPI Trusted Publishing
Publishing uses PyPI Trusted Publishing/OIDC. Maintainers should not add PyPI API tokens to this repository or to the release workflow.
Expected PyPI project configuration:
- Project name:
climate-indices - Owner:
monocongo - Repository:
climate_indices - Workflow:
release.yml - Environment:
release
If publishing fails at the OIDC step, verify the PyPI trusted publisher settings and the GitHub environment name before changing workflow credentials.
Post-release checks
After the workflow completes:
- Confirm the GitHub Release exists as
vX.Y.Z. - Confirm PyPI has
climate-indicesversionX.Y.Z. - Install from PyPI in a clean environment if extra verification is needed:
uv venv /tmp/climate-indices-release-check /tmp/climate-indices-release-check/bin/python -m pip install climate-indices==X.Y.Z /tmp/climate-indices-release-check/bin/python -c "import climate_indices; print(climate_indices.__version__)" - Open a follow-up PR for any next-cycle changelog preparation if needed.
Hotfix flow
Use the normal trunk flow for hotfixes whenever possible:
- Start from updated
main. - Create
hotfix/<topic>. - Make the smallest safe fix with a regression test.
- Run validation.
- Merge the PR into
mainafter CI passes. - Prepare and tag a patch release from
main.
For an older supported version, a maintainer may approve a maintenance branch.
Keep it narrow, document the target version, and merge forward to main when
applicable.