A Python implementation of semantic-release — automated version management and package publishing driven by conventional commits.
python-semantic-release analyzes your Git commit history using the Conventional Commits specification to automatically determine the next version, generate a changelog, tag the release, and publish a GitHub release — all from the command line or a CI pipeline.
- Automated versioning — determines MAJOR, MINOR, or PATCH bumps from commit types
- Changelog generation — produces structured Markdown changelogs with compare links
- GitHub releases — creates and publishes releases via the GitHub API
- Version file updates — writes the new version to
VERSION,pyproject.toml, and any custom files - Git commit & tag — stages changed files, commits, and tags the release
- Config migration — converts existing
release.config.jsfiles to.releaserc.yaml - CI-aware — writes
version_changedto$GITHUB_OUTPUTfor use in GitHub Actions workflows - Configurable rules — customize which commit types trigger which version bump level
pip install python-semantic-releaseOr with uv:
uv add python-semantic-release# Run a release from the current directory
semantic-release run
# Dry run — preview what would happen without making changes
semantic-release run --dry-run
# Use a specific config file
semantic-release run --config .releaserc.yaml
# Run outside of CI (skip CI environment checks)
semantic-release run --no-ciThis tool follows the Conventional Commits specification:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
| Commit type | Version bump |
|---|---|
feat |
MINOR |
fix |
PATCH |
perf |
PATCH |
feat! / BREAKING CHANGE: |
MAJOR |
chore, docs, style, refactor, test, ci, build |
No release |
feat: add support for draft releases → 1.0.0 → 1.1.0
fix(parser): handle empty commit body → 1.1.0 → 1.1.1
feat!: redesign configuration schema → 1.1.1 → 2.0.0
chore: update dependencies → no release
Place a .releaserc.yaml in your project root:
options:
branches:
- main
tag_format: "v${version}"
dry_run: false
version:
version_files:
- VERSION
- "pyproject.toml:project.version"
commit_analyzer:
preset: angular
release_rules:
- type: feat
release: minor
- type: fix
release: patch
- type: docs
release: patch # promote docs to trigger a release
changelog:
changelog_file: CHANGELOG.md
git:
assets:
- CHANGELOG.md
- VERSION
- pyproject.toml
message: "chore(release): ${nextRelease.version} [skip ci]"
github:
draft_release: false
labels:
- releasedIf no config file is found, sensible defaults are used automatically.
If your project uses the JavaScript semantic-release package, you can convert your existing config:
semantic-release convert --input release.config.js --output .releaserc.yaml- name: Semantic Release
run: semantic-release run --no-ci
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check if version changed
if: env.version_changed == 'true'
run: echo "A new release was published!"The version_changed output variable is written to $GITHUB_OUTPUT automatically.
- Python 3.13+
- uv
git clone https://github.com/jedi-knights/python-semantic-release
cd python-semantic-release
uv sync --extra devuv run pytestuv run ruff check .
uv run ruff format .| Module | Responsibility |
|---|---|
cli.py |
Click command-line interface (run, convert) |
orchestrator.py |
Coordinates the full release pipeline |
commit_parser.py |
Parses conventional commits |
commit_analyzer.py |
Determines release type from commits |
version_service.py |
Calculates and bumps semantic versions |
version_updater.py |
Writes new version to files |
release_notes_generator.py |
Generates Markdown changelog sections |
git_service.py |
Git operations (tag, commit, push) |
git_plugin.py |
Stages and commits release assets |
github_service.py |
GitHub API client (releases, comments, labels) |
config_loader.py |
Loads .releaserc.yaml configuration |
config_converter.py |
Converts release.config.js → .releaserc.yaml |
models.py |
Shared dataclasses and enums |
protocols.py |
Structural typing protocols |
MIT