π·οΈ Automatically create GitHub releases using Calendar Versioning (CalVer) on every commit.
This tool is perfect for:
- π¦ Packages where users should always use the latest version
- π¬ Research software where releases are not tied to specific feature completions
- π Projects with continuous deployment where each merge to main is a potential release
- π€ Automating away the decision of "when should we release?"
By automatically creating a release on every commit to your main branch, you ensure that:
- Users always have access to the latest changes
- Version numbers clearly indicate when changes were made
- Each change is properly documented through commit messages
- The release process is completely automated
Note
For the best experience, we recommend using squash merges for your Pull Requests. This ensures that:
- Each release corresponds to one logical change
- Release notes are clean and meaningful
- The git history remains linear and easy to understand
Configure this in your GitHub repository settings under "Pull Requests" β "Allow squash merging" and uncheck other merge methods.
ToC
- π
Automatic Calendar Versioning (
v{YYYY}.{MM}.{PATCH}
) - π€ Creates GitHub releases automatically
- π Generates release notes from commit messages
- π·οΈ Supports release skipping with commit message flags
- π Integrates with GitHub Actions
- π Can be used as a Python package
- π₯οΈ Command-line interface included
- π§ͺ Dry-run mode for testing
- π Customizable release notes format
Add this to your workflow file (e.g., .github/workflows/release.yml
):
Note
See the basnijholt/home-assistant-streamdeck-yaml
's release.yml
workflow's for a full example, and see it's releases page for the result.
A minimal example:
name: Create Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: basnijholt/calver-auto-release@v1
id: release
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
And full example including publishing to PyPI:
name: Create Release
on:
push:
branches:
- main
jobs:
release:
runs-on: ubuntu-latest
environment: # Needed for `pypa/gh-action-pypi-publish`
name: pypi
url: https://pypi.org/p/${{ github.repository }}
permissions: # Needed for `pypa/gh-action-pypi-publish`
id-token: write # for PyPI publishing
steps:
# Create release with CalVer
- uses: basnijholt/calver-auto-release@v1
id: release
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# Optional: custom configuration
skip_patterns: "[skip release],[no-release]"
footer: "Custom footer text"
generate_release_notes: true # Add GitHub's automatic release notes
# Optional: publish to PyPI
# Only run if a new version was created
- name: Build package
if: steps.release.outputs.version != ''
run: |
python -m pip install build
python -m build
# Option 1: Publish with official PyPA action
- name: Publish package distributions to PyPI
if: steps.release.outputs.version != ''
uses: pypa/gh-action-pypi-publish@release/v1
# Option 2: Publish with twine
# - name: Publish package distributions to PyPI
# if: steps.release.outputs.version != ''
# env:
# TWINE_USERNAME: __token__
# TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
# run: |
# python -m pip install twine
# twine upload dist/*
The action creates a new release with CalVer versioning, and you can optionally add your preferred method for publishing to PyPI or any other post-release tasks.
Important
The secrets.GITHUB_TOKEN
variable is automatically populated (see docs).
However, releases created using GITHUB_TOKEN
will not trigger other workflows that run on the release
event.
If you need to trigger other workflows when a release is created, you'll need to:
- Create a Personal Access Token (PAT) with
contents: write
permissions at https://github.com/settings/tokens - Add it to your repository secrets (e.g., as
PAT
) - Use it in the workflow:
- uses: basnijholt/calver-auto-release@v1 with: github_token: ${{ secrets.PAT }} # Instead of secrets.GITHUB_TOKEN
# Basic usage
calver-auto-release --repo-path /path/to/repo
# Dry run (show what would happen without creating the release)
calver-auto-release --repo-path /path/to/repo --dry-run
# Custom skip patterns
calver-auto-release --repo-path /path/to/repo --skip-pattern "[no-release]" --skip-pattern "[skip]"
from calver_auto_release import create_release
# Basic usage
create_release() # Uses current directory
# With custom configuration
create_release(
repo_path="/path/to/repo",
skip_patterns=["[skip]", "[no-release]"],
footer="\nCustom footer text",
dry_run=True, # Show what would happen without creating the release
)
The generated release notes will have this format:
π Release YYYY.MM.PATCH
π This release includes the following changes:
- First commit message
- Second commit message
- etc.
π Thank you for using this project! Please report any issues or feedback on the GitHub repository
- Git repository with an 'origin' remote configured
- Python 3.10 or higher
- Git command-line tools installed
Install using pip:
pip install calver-auto-release
Or using uv:
uv pip install calver-auto-release
You can skip creating a release by including these patterns in your commit message:
[skip release]
[pre-commit.ci]
β¬οΈ Update
The version format follows CalVer: YYYY.MM.PATCH
YYYY
: Current yearMM
: Current monthPATCH
: Incremental number, resets when year or month changes
You can customize the footer text that appears at the end of each release note:
create_release(
footer="\nCustom footer text for all releases"
)
Or via CLI:
calver-auto-release --footer "Custom footer text"
Or in the GitHub Action:
- uses: basnijholt/calver-auto-release@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
footer: "Custom footer text"
MIT License
Contributions are welcome! Please feel free to submit a Pull Request.
- Clone the repository
- Install development dependencies:
pip install -e ".[dev]"
- Install pre-commit hooks:
pre-commit install
- Run tests:
pytest