A comprehensive tool to manage releases using semantic versioning for efficient release workflows. Written in Python with full type safety and designed to be flexible and configurable for different team workflows.
- Semantic Versioning Support: Full support for semantic versioning with release candidates, betas, and alphas
- Intelligent Version Comparison: Automatically determines the right version to compare against (RC to RC, final to final, etc.)
- Issue-based Consolidation: Groups commits by parent issues for cleaner release notes
- Configurable Policies: Flexible policies for issue extraction, consolidation, version gaps, and more
- GitHub Integration: Syncs PRs, issues, and releases from GitHub; can create releases and PRs automatically
- Local Git Analysis: Analyzes commit history from local repositories
- SQLite Database: Efficient local caching of GitHub data to minimize API calls
- Template-based Release Notes: Jinja2 templates for customizable release note formatting
- Category-based Grouping: Organize release notes by configurable categories with label mapping
# Install with poetry
poetry install
# Or for development
poetry install --with devWhen running release-tool in GitHub Actions, you need to configure proper authentication for accessing repositories, issues, and pull requests.
The GitHub token (GITHUB_TOKEN) needs the following permissions:
- contents: read - For cloning repositories and reading commit history
- issues: read - For fetching issue data
- pull-requests: read - For fetching pull request data
- contents: write - (Optional) For creating releases and pushing changes
- pull-requests: write - (Optional) For creating PRs with release notes
The tool supports multiple authentication methods for cloning repositories:
# .github/workflows/release.yml
name: Generate Release Notes
on:
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., 1.0.0)'
required: true
permissions:
contents: write # For cloning and creating releases
issues: read # For fetching issues
pull-requests: read # For fetching PRs
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install release-tool
run: pip install release-tool
- name: Generate release notes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
release-tool pull
release-tool generate ${{ github.event.inputs.version }} --uploadIf you need to use SSH (e.g., for private repos without token access), configure your release_tool.toml:
[pull]
clone_method = "ssh" # Options: "https", "ssh", "auto" (default)Then set up SSH keys in your workflow:
- name: Setup SSH
uses: webfactory/ssh-agent@v0.9.0
with:
ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }}
- name: Run release-tool
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Still needed for API calls
run: |
release-tool pull
release-tool generate ${{ github.event.inputs.version }}By default, the tool uses clone_method = "auto" which:
- First tries HTTPS with token authentication
- Falls back to SSH if HTTPS fails
This provides the most flexibility across different environments.
For GitHub Enterprise or custom Git servers:
[github]
api_url = "https://github.enterprise.com/api/v3"
[pull]
clone_url_template = "https://github.enterprise.com/{repo_full_name}.git"If you encounter clone errors:
-
Empty token error (
https://@github.com/...):- Ensure
GITHUB_TOKENis set in your environment - Check workflow permissions are correctly configured
- Ensure
-
Permission denied:
- Verify token has required permissions
- For private repos, ensure token can access the repository
-
SSH authentication failed:
- Confirm SSH keys are properly configured
- Test with:
ssh -T git@github.com
-
Initialize configuration:
release-tool init-config
-
Edit
release_tool.tomland set your repository:[repository] code_repo = "your-org/your-repo"
-
Set GitHub token:
export GITHUB_TOKEN="your_github_token"
-
Pull repository data:
release-tool pull
-
Generate release notes:
release-tool generate 1.0.0 --repo-path /path/to/local/repo
Pull repository data from GitHub to the local database:
release-tool pull [repository] [--repo-path PATH]Generate release notes for a version:
release-tool generate VERSION \
--repo-path /path/to/repo \
[--from-version VERSION] \
[--output FILE] \
[--upload] \
[--create-pr]Options:
--from-version: Compare from this version (auto-detected if not specified)--output, -o: Output file for release notes--upload: Upload release to GitHub--create-pr: Create PR with release notes
List all releases in the database:
release-tool list-releases [repository]Create an example configuration file:
release-tool init-configThe tool is configured via a TOML file (release_tool.toml). Key sections:
[repository]
code_repo = "owner/repo" # Required
issue_repo = "owner/issues" # Optional: separate repo for issues
default_branch = "main"[pull]
clone_code_repo = true # Whether to clone the repository locally
clone_method = "auto" # Options: "https", "ssh", "auto" (default)
clone_url_template = "" # Custom clone URL template (optional)
# Example: "https://github.enterprise.com/{repo_full_name}.git"[issue_policy]
patterns = ["([A-Z]+-\\d+)", "#(\\d+)"] # Regex patterns to find issues
no_issue_action = "warn" # ignore, warn, or error
unclosed_issue_action = "warn"
consolidation_enabled = true[version_policy]
gap_detection = "warn" # ignore, warn, or error
tag_prefix = "v"[[release_notes.categories]]
name = "Features"
labels = ["feature", "enhancement"]
order = 1
[[release_notes.categories]]
name = "Bug Fixes"
labels = ["bug", "fix"]
order = 2[release_notes]
excluded_labels = ["skip-changelog", "internal"]
title_template = "Release {{ version }}"
include_authors = true
include_pr_links = true
[output]
output_file = "docs/releases/{major}.{minor}.{patch}.md"
create_github_release = false
create_pr = false
pr_branch_template = "release-notes-{version}"The tool implements intelligent version comparison:
- Final versions (e.g.,
2.0.0) compare to the previous final version - Release candidates (e.g.,
2.0.0-rc.2) compare to:- Previous RC of the same version (
2.0.0-rc.1) if it exists, OR - Previous final version if no RCs exist
- Previous RC of the same version (
- Consolidated final releases incorporate all changes from RCs, betas, alphas of that version
Commits are consolidated by their parent issue:
- Extract issue references from commits using configurable regex patterns
- Try multiple strategies: commit message, PR body, branch name
- Group commits with the same issue key
- Fetch issue details from GitHub (title, labels, description)
- Apply configurable policies for missing issues
- Extract commits between two versions from Git history
- Consolidate by issue to group related changes
- Fetch issue metadata from GitHub Issues API
- Categorize based on labels and configured category mappings
- Format using Jinja2 templates
- Output to console, file, GitHub release, or PR
src/release_tool/
├── main.py # CLI entry point with Click commands
├── models.py # Pydantic data models (SemanticVersion, Commit, PR, Issue, etc.)
├── config.py # Configuration management with Pydantic validation
├── db.py # SQLite database operations
├── git_ops.py # Git operations using GitPython
├── github_utils.py # GitHub API client using PyGithub
└── policies.py # Policy implementations (extraction, consolidation, generation)
All modules have comprehensive unit tests:
# Run all tests
poetry run pytest
# Run with coverage
poetry run pytest --cov=release_tool
# Run specific test file
poetry run pytest tests/test_models.py -vCurrent test coverage: 44 tests covering models, database, Git operations, policies, and configuration.
Built with modern Python best practices:
- Python 3.10+: Modern Python with type hints
- Poetry: Dependency management and packaging
- Pydantic: Data validation and settings management
- Click: Command-line interface
- Rich: Beautiful terminal output
- PyGithub: GitHub API integration
- GitPython: Local Git repository operations
- Jinja2: Template rendering
- pytest: Comprehensive testing
# 1. Initial setup
release-tool init-config
export GITHUB_TOKEN="ghp_your_token"
# 2. Edit release_tool.toml with your repo settings
# 3. Sync GitHub data once or periodically
release-tool pull
# 4. Generate release notes for version 2.0.0
release-tool generate 2.0.0 \
--repo-path ~/projects/myrepo \
--output docs/releases/2.0.0.md
# 5. Or generate and upload to GitHub
release-tool generate 2.0.0 \
--repo-path ~/projects/myrepo \
--upload
# 6. Or generate and create PR
release-tool generate 2.0.0 \
--repo-path ~/projects/myrepo \
--create-prCopyright (c) Sequent Tech Inc. All rights reserved.