This guide provides detailed instructions for releasing new versions of antipasta to PyPI.
Pre-flight check:
make release-doctor # Check system health and prerequisitesSafe one-command releases (recommended):
make release-patch-safe # Bug fixes (X.Y.Z -> X.Y.(Z+1)) with safety checks
make release-minor-safe # New features (X.Y.Z -> X.(Y+1).0) with safety checks
make release-major-safe # Breaking changes (X.0.0) with safety checksStandard releases (without safety checks):
make release-patch # Bug fixes (X.Y.Z -> X.Y.(Z+1))
make release-minor # New features (X.Y.Z -> X.(Y+1).0)
make release-major # Breaking changes (X.0.0)These commands handle everything: version bump → commit → push → GitHub release → PyPI deployment.
Testing before release:
# Test what will happen (dry-run)
make release-dry-patch # Simulate patch release
make release-dry-minor # Simulate minor release
make release-dry-major # Simulate major release
make gh-release-dry # Simulate GitHub release creation
# Deploy to TestPyPI first
make gh-release-test # Safe testing on TestPyPIAntipasta supports two release methods:
- GitHub Actions (Recommended): Automated deployment via GitHub Releases
- Manual Release: Direct upload from your local machine
Before any release, run the release doctor to check your system:
make release-doctorThis comprehensive health check verifies:
- ✅ GitHub CLI installation and authentication
- ✅ Git repository state (uncommitted changes, branch)
- ✅ Version status and available tags
- ✅ Python environment and build tools
- ✅ GitHub repository and workflow configuration
Before making an actual release, test what will happen:
# See what a patch release would do
make release-dry-patch
# Test GitHub release creation
make gh-release-dry
# Run pre-release safety checks
make release-safety-checkThese commands simulate the entire release process without making any changes.
- GitHub Repository Access: Push access to the antipasta repository
- Trusted Publishing: Already configured in PyPI project settings (no tokens needed!)
The easiest and safest way to release is using the safe all-in-one commands:
# Safe releases with automatic safety checks (recommended)
make release-patch-safe # Bug fixes (X.Y.Z -> X.Y.(Z+1))
make release-minor-safe # New features (X.Y.Z -> X.(Y+1).0)
make release-major-safe # Breaking changes (X.0.0)
# Or standard releases without safety checks
make release-patch # Bug fixes (X.Y.Z -> X.Y.(Z+1))
make release-minor # New features (X.Y.Z -> X.(Y+1).0)
make release-major # Breaking changes (X.0.0)These commands automatically:
- Bump the version
- Commit changes
- Push to GitHub
- Create a GitHub release
- Trigger PyPI deployment
For more control over the release process:
-
Check System Health:
make release-doctor # Comprehensive pre-flight check make release-safety-check # Quick safety validation
-
Test First (Optional but Recommended):
make release-dry-patch # Simulate the release make gh-release-dry # Check if release would succeed
-
Bump Version:
make version-bump-patch # or minor/major -
Create GitHub Release:
# Safe release with checks (recommended) make gh-release-safe # Standard release make gh-release # Or create a draft to review first make gh-release-draft
-
Monitor Deployment:
- The command outputs links to:
- GitHub Actions progress
- PyPI package page
- Package appears on PyPI within minutes
- The command outputs links to:
GitHub UI
- Navigate to your repo → Releases → "Draft a new release"
- Click "Choose a tag" → Create new tag:
v1.1.1(match your version) - Release title:
v1.1.1 - Click "Generate release notes" for automatic changelog
- Click "Publish release"
GitHub CLI (manual)
gh release create v1.1.1 --generate-notes --title "v1.1.1"Before a production release, test on TestPyPI:
Using Makefile (Recommended)
make gh-release-testThis triggers the TestPyPI workflow and provides installation instructions.
Using GitHub UI
- Go to Actions → "Publish to PyPI" workflow
- Click "Run workflow"
- Select
testpypias target - Run the workflow
Test Installation
pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ antipasta- PyPI Account: Create an account at pypi.org
- TestPyPI Account (optional): Create an account at test.pypi.org
- API Tokens: Generate API tokens for both PyPI and TestPyPI
- Configure Authentication: Set up your
~/.pypircfile:
[distutils]
index-servers =
pypi
testpypi
[pypi]
username = __token__
password = pypi-YOUR-TOKEN-HERE
[testpypi]
username = __token__
password = pypi-YOUR-TEST-TOKEN-HERE
repository = https://test.pypi.org/legacy/- Clean Git State: Ensure your working directory is clean and you're on the main branch
Run the release checklist to ensure everything is ready:
make release-checkThis displays a checklist of items to verify before releasing:
- All tests passing
- Code formatted properly
- Type checks passing
- Version bumped appropriately
- CHANGELOG updated (if applicable)
- Git working directory clean
- On the correct branch
Ensure all quality checks pass:
make checkThis runs:
- Linting (
ruff) - Type checking (
mypy) - Tests (
pytest)
Choose the appropriate version bump based on your changes:
For backward-compatible bug fixes (X.Y.Z -> X.Y.(Z+1)):
make version-bump-patchFor backward-compatible new features (X.Y.Z -> X.(Y+1).0):
make version-bump-minorFor incompatible API changes (X.0.0):
make version-bump-majorThe version will be updated in both src/antipasta/__version__.py and pyproject.toml.
Build the distribution packages and verify they're correct:
make build-checkThis will:
- Clean any previous build artifacts
- Build both source distribution (.tar.gz) and wheel (.whl)
- Run
twine checkto validate the packages
You can also do a dry run to see what will be uploaded:
make release-dry-runTest your release on TestPyPI first:
make release-testThen install and test from TestPyPI:
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ antipastaOnce you're confident everything works, release to PyPI:
make releaseThis uploads your packages to the official PyPI repository.
After a successful release, create a git tag:
# Commit the version changes
git add -A
git commit -m "chore: release v$(make version-show 2>&1 | grep "Current version" | cut -d: -f2 | xargs)"
# Create and push tag
git tag -a v$(make version-show 2>&1 | grep "Current version" | cut -d: -f2 | xargs) -m "Release v$(make version-show 2>&1 | grep "Current version" | cut -d: -f2 | xargs)"
git push origin main --tagsTest that the new version can be installed from PyPI:
pip install --upgrade antipasta
antipasta --versionIf you get authentication errors:
- Verify your
.pypircfile has the correct API tokens - Ensure tokens start with
pypi- - Check that tokens have upload permissions
If twine check fails:
- Run
make cleanto remove old artifacts - Ensure
README.mdis valid markdown - Check that all required fields are in
pyproject.toml
If PyPI reports the version already exists:
- You cannot overwrite an existing version on PyPI
- Bump the version again (even for a patch)
- Delete local build artifacts:
make clean
TestPyPI may have missing dependencies. When testing installation:
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ antipastaThe --extra-index-url ensures dependencies are pulled from production PyPI.
Follow Semantic Versioning:
-
MAJOR (X.0.0): Incompatible API changes
- Removing features
- Changing function signatures
- Major behavior changes
-
MINOR (X.Y.Z -> X.(Y+1).0): Backward-compatible functionality
- New features
- New configuration options
- Deprecations (but not removals)
-
PATCH (X.Y.Z -> X.Y.(Z+1)): Backward-compatible bug fixes
- Bug fixes
- Performance improvements
- Documentation updates
Use the built-in checklist command:
make release-checkThis displays the current version and a checklist of items to verify:
- All tests passing (
make test) - Code formatted (
make format) - Type checks passing (
make type-check) - Version bumped appropriately
- CHANGELOG.md updated (if exists)
- Git working directory clean
- On correct branch (main/master)
For a complete quality check before release:
make check # Runs lint, type-check, and testsFor frequent releases, consider:
- GitHub Actions: Automate releases on tag push
- Semantic Release: Automatic version management based on commit messages
- Pre-commit Hooks: Ensure quality checks before commits
If a critical issue is found after release:
- Do NOT delete the release from PyPI (it's not allowed)
- Yank the release (marks it as broken):
pip install twine twine yank antipasta==X.Y.Z
- Fix the issue and release a new patch version
- Communicate with users about the issue