Pipeline Overview
code
Conventional Commits → semantic-release → Tag + Changelog
→ PyPI publish (trusted publishing)
→ Docker build + push (GHCR)
→ GitHub Release with assets
Conventional Commits → Version Bumps
| Prefix | Bump | Example |
|---|---|---|
fix: | PATCH | fix(parser): handle empty YAML blocks |
feat: | MINOR | feat(cli): add --json output flag |
feat!: or BREAKING CHANGE: | MAJOR | feat!: restructure artifact schema |
docs:, chore:, refactor:, test: | No bump | docs: update README |
python-semantic-release
Config in pyproject.toml:
toml
[tool.semantic_release]
version_toml = ["pyproject.toml:project.version"]
branch = "main"
commit_message = "chore(release): {version}"
build_command = "uv build"
[tool.semantic_release.changelog]
changelog_file = "CHANGELOG.md"
[tool.semantic_release.remote]
type = "github"
GitHub Actions Release Workflow
Three-job pipeline (release → publish-pypi → publish-docker):
Job 1: Release (version bump + tag)
- •
python-semantic-release/python-semantic-release@v10 - •Needs:
contents: write,id-token: write - •Uses
RELEASE_TOKEN(PAT) for pushing tags - •Outputs:
released,version,tag
Job 2: PyPI (trusted publishing)
- •Triggered by
needs.release.outputs.released == 'true' - •
pypa/gh-action-pypi-publish@release/v1 - •Uses
id-token: writefor OIDC trusted publishing (no API keys) - •Environment:
pypi(configured in repo settings with PyPI project URL)
Job 3: Docker (multi-arch GHCR)
- •Checks out at the release tag
- •Multi-platform:
linux/amd64,linux/arm64 - •Tags:
latest,vX.Y.Z,vX.Y,vX - •Uses GHA cache for layer caching
- •Generates build provenance attestation
PyPI Trusted Publishing Setup
- •PyPI project settings → "Add a new publisher"
- •Set: GitHub owner, repo name, workflow filename, environment name (
pypi) - •No API keys needed — OIDC token from GitHub Actions
Docker Tagging Strategy
For version 3.2.1:
code
ghcr.io/owner/repo:latest # Rolling latest ghcr.io/owner/repo:v3.2.1 # Exact version ghcr.io/owner/repo:v3.2 # Minor (for compat pinning) ghcr.io/owner/repo:v3 # Major
Version Bump in pyproject.toml
semantic-release handles this automatically. The version in pyproject.toml is the single source of truth. Never edit manually.
Manual/Emergency Release
bash
# Trigger via GitHub UI or CLI gh workflow run release.yml -f force=patch # or minor/major
Pre-Release Checklist
- •All CI green on main
- •Conventional commits since last release
- •CHANGELOG reviewed (auto-generated but verify)
- •Docker build tested locally:
docker build -t test . - •No uncommitted changes on main