Release Process¶
This document describes the process for releasing a new version of Whistle.
Prerequisites¶
Before releasing, ensure you have:
Push access to the GitHub repository
All changes merged to the
mainbranchAll tests passing on CI
The release process is fully automated via GitHub Actions. You only need to create and push a git tag.
Release Steps¶
Ensure everything is ready
Run tests locally to verify everything works:
make test make format
Set the version number
Define the version number in an environment variable to avoid typos:
export VERSION=2.0.2 # Or for a release candidate: export VERSION=2.1.0-rc1
Update version in pyproject.toml
Update the version in
pyproject.tomland commit the change:# Update the version in pyproject.toml (cross-platform) sed -i.bak "s/^version = .*/version = \"$VERSION\"/" pyproject.toml && rm pyproject.toml.bak uv lock # Commit the version change git add pyproject.toml uv.lock git commit -m "chore: bump version to $VERSION"
Create an annotated git tag
Create an annotated tag (required for proper git object tracking):
git tag -a $VERSION -m "Release $VERSION"
The
-aflag creates an annotated tag (a real git object with metadata). The-mflag provides a message for the tag.Push the tag to GitHub
git push origin main git push origin $VERSION
GitHub Actions takes over
Once the tag is pushed, the Release workflow automatically:
Builds the Python package (wheel and sdist)
Tests the package on Python 3.10-3.14
Publishes to TestPyPI
Publishes to PyPI
Creates a GitHub Release with the built artifacts
Monitor the release
Watch the GitHub Actions workflow at: https://github.com/python-whistle/whistle/actions
The workflow typically takes 5-10 minutes to complete.
Verify the release
Once complete, verify the release:
Check PyPI: https://pypi.org/project/whistle/
Check GitHub Releases: https://github.com/python-whistle/whistle/releases
Test installation:
pip install whistle==$VERSION
Version Naming¶
Follow semantic versioning:
Stable releases:
X.Y.Z(e.g.,2.0.2,2.1.0)Release candidates:
X.Y.Z-rcN(e.g.,2.1.0-rc1)Beta releases:
X.Y.Z-betaN(e.g.,2.1.0-beta1)Alpha releases:
X.Y.Z-alphaN(e.g.,2.1.0-alpha1)
Pre-release versions (rc, beta, alpha) are automatically marked as pre-releases on GitHub.
Troubleshooting¶
Release workflow fails
Check the GitHub Actions logs for errors
Fix any issues in the code
Delete the failed tag both locally and on GitHub:
export VERSION=2.0.2 # Set to the failed version git tag -d $VERSION git push origin :refs/tags/$VERSION
Create and push the tag again after fixing issues
PyPI credentials issues
The release workflow uses GitHub’s trusted publishing (OIDC). No manual credentials are needed. If publishing fails, verify the PyPI trusted publisher configuration at: https://pypi.org/manage/account/publishing/
Manual Build (Testing)¶
To test the build process locally without publishing:
make wheel
This creates distribution files in the dist/ directory using an isolated sandbox environment.
Emergency Rollback¶
If a release has critical issues:
Do not delete the PyPI release (PyPI does not allow re-uploading the same version)
Instead, release a new patch version with the fix
Optionally mark the problematic release as yanked on PyPI (prevents new installs but doesn’t break existing ones)
For yanking a release on PyPI:
Select the problematic version
Click “Options” → “Yank release”