Release Process¶
This project uses Python Semantic Release to automate versioning, changelog generation, git tagging, and publishing to PyPI.
Overview¶
The release process is triggered manually via GitHub Actions, but everything else is automated:
- ✅ Version number calculation (from commit messages)
- ✅ Version bumping in
dmp_af/__init__.py
andpyproject.toml
- ✅ Changelog generation from commits
- ✅ Git tag creation
- ✅ GitHub release creation
- ✅ PyPI publishing
Commit Message Convention¶
We follow the Conventional Commits specification:
Types and Version Bumps¶
feat:
- New feature → MINOR version bump (0.14.0 → 0.15.0)fix:
- Bug fix → PATCH version bump (0.14.0 → 0.14.1)perf:
- Performance improvement → PATCH version bumpdocs:
- Documentation changes → No version bumpstyle:
- Code style changes → No version bumprefactor:
- Code refactoring → No version bumptest:
- Test changes → No version bumpbuild:
- Build system changes → No version bumpci:
- CI/CD changes → No version bumpchore:
- Other changes → No version bump
Breaking Changes¶
To trigger a MAJOR version bump (0.14.0 → 1.0.0), include BREAKING CHANGE:
in the commit footer:
Or use the !
shorthand:
Examples¶
# Patch release (0.14.6 → 0.14.7)
git commit -m "fix: correct snapshot task generation for new dbt format"
# Minor release (0.14.6 → 0.15.0)
git commit -m "feat: add support for dbt Cloud metadata export"
# With scope
git commit -m "feat(operators): add new Python venv operator"
# With body and footer
git commit -m "fix(sensors): timeout handling in external sensor
Previously the sensor would hang indefinitely when the upstream
task failed. Now it respects the timeout parameter.
Fixes #123"
# Major release (0.14.6 → 1.0.0)
git commit -m "feat: redesign DAG configuration API
BREAKING CHANGE: The DmpAfConfig class now requires explicit
domain specification. The old automatic domain detection has been
removed."
Triggering a Release¶
Option 1: Automatic Version Detection (Recommended)¶
Let semantic-release analyze commits and determine the version bump:
- Go to Actions tab in GitHub
- Select Semantic Release workflow
- Click Run workflow
- Leave all inputs empty
- Click Run workflow
The workflow will: - Analyze commits since last release - Determine version bump (patch/minor/major) - Skip release if no relevant commits found
Option 2: Force Specific Version Bump¶
Override automatic detection:
- Go to Actions tab in GitHub
- Select Semantic Release workflow
- Click Run workflow
- Select force level:
patch
,minor
, ormajor
- Click Run workflow
Option 3: Prerelease¶
Create a prerelease version (e.g., 0.15.0-rc.1):
- Go to Actions tab in GitHub
- Select Semantic Release workflow
- Click Run workflow
- Check Create a prerelease version
- Click Run workflow
What Happens During Release¶
- Verify Tests: Waits for integration tests to pass on main branch
- Version Calculation: Analyzes commits to determine next version
- Update Files: Updates
__version__
in code and pyproject.toml - Generate Changelog: Adds new release section to CHANGELOG.md
- Create Commit: Commits changes with message
chore(release): X.Y.Z
- Create Tag: Creates git tag
vX.Y.Z
- Push Changes: Pushes commit and tag to main branch
- GitHub Release: Creates GitHub release with changelog
- Build Package: Builds wheel and source distribution
- Publish to PyPI: Uploads to PyPI with trusted publishing
Validating Commits Locally¶
To ensure your commits follow the convention, install pre-commit hooks:
# Install pre-commit hook
uv run pre-commit install --hook-type commit-msg
# Test your commit message
uv run pre-commit run conventional-pre-commit \
--hook-stage commit-msg \
--commit-msg-filename <(printf 'feat: my new feature\n')
# If your shell does not support process substitution, write the message to a file instead:
printf 'feat: my new feature\n' > /tmp/commit-msg.txt
uv run pre-commit run conventional-pre-commit \
--hook-stage commit-msg \
--commit-msg-filename /tmp/commit-msg.txt
The hook will validate commit messages and reject invalid ones:
# ✅ Valid
git commit -m "feat: add new sensor type"
# ❌ Invalid (will be rejected)
git commit -m "added new sensor"
git commit -m "WIP: testing something"
Previewing Next Version¶
To see what version will be released without actually releasing:
# Install semantic-release
uv sync --group release
# Preview next version
uvx --from python-semantic-release semantic-release version --print
# Show what would change
uvx --from python-semantic-release semantic-release version --print-tag
uvx --from python-semantic-release semantic-release version --print-last-released
uvx --from python-semantic-release semantic-release changelog --unreleased
Troubleshooting¶
No Release Created¶
Problem: Workflow runs but doesn't create a release.
Causes: - No commits with feat:
, fix:
, or breaking changes since last release - Only commits with docs:
, chore:
, style:
, etc.
Solution: Ensure you have commits that warrant a version bump.
Version Conflict¶
Problem: PyPI rejects the upload because version already exists.
Solution: Version conflicts should not happen with semantic-release. If they do: 1. Check the last git tag: git describe --tags --abbrev=0
2. Check PyPI version: https://pypi.org/project/dmp-af/ 3. Manually tag if needed: git tag vX.Y.Z && git push origin vX.Y.Z
Tests Failing¶
Problem: Release workflow fails at test verification step.
Solution: Fix the tests on main branch first. The release cannot proceed if integration tests are failing.
Commit Hook Rejection¶
Problem: Cannot commit because message is rejected.
Solutions:
# Bypass the hook (not recommended)
git commit --no-verify -m "your message"
# Or fix the message format
git commit -m "feat: your feature description"
Migration from Manual Releases¶
First Release with Semantic Release¶
If migrating from manual releases:
- Ensure
dmp_af/__init__.py
has correct current version - Create a git tag for the current version:
git tag v0.14.6
- Push the tag:
git push origin v0.14.6
- Make commits following conventional format
- Trigger first semantic release
Converting Old Commits¶
Old commits without conventional format won't affect new releases. Semantic-release only looks at commits since the last tagged release.
Best Practices¶
- Write meaningful commit messages: They become your changelog
- Use scopes:
feat(operators):
,fix(sensors):
for better organization - Include issue references:
Fixes #123
,Closes #456
- Group related changes: Make logical, atomic commits
- Test before merging: Only merge to main when tests pass
- Review changelog: Check the generated changelog in the release PR
Configuration¶
Configuration is in pyproject.toml
under [tool.semantic_release]
. Key settings:
branch = "main"
: Release from main branchversion_variables
: Where to update version in codechangelog_file
: Path to changelogmajor_on_zero = false
: Allow 0.x.y versions without forcing 1.0.0commit_parser_options
: Define which commit types trigger releases