GitHub Actions
Create a new release with GitHub Actions¶
This guide shows you how to automatically bump versions, create changelogs, and publish releases using Commitizen in GitHub Actions.
Prerequisites¶
Before setting up the workflow, you'll need:
- A personal access token with repository write permissions
- Commitizen configured in your project (see configuration documentation)
Automatic Version Bumping¶
To automatically execute cz bump in your CI and push the new commit and tag back to your repository, follow these steps:
Step 1: Create a Personal Access Token¶
- Go to GitHub Settings > Developer settings > Personal access tokens
- Click "Generate new token (classic)"
- Give it a descriptive name (e.g., "Commitizen CI")
- Select the
reposcope to grant full repository access - Click "Generate token" and copy the token immediately (you won't be able to see it again)
Important: Use Personal Access Token, not GITHUB_TOKEN
If you use GITHUB_TOKEN instead of PERSONAL_ACCESS_TOKEN, the workflow won't trigger another workflow run. This is a GitHub security feature to prevent infinite loops. The GITHUB_TOKEN is treated like using [skip ci] in other CI systems.
Step 2: Add the Token as a Repository Secret¶
- Go to your repository on GitHub
- Navigate to
Settings > Secrets and variables > Actions - Click "New repository secret"
- Name it
PERSONAL_ACCESS_TOKEN - Paste the token you copied in Step 1
- Click "Add secret"
Step 3: Create the Workflow File¶
Create a new file .github/workflows/bump-version.yml in your repository with the following content:
name: Bump version
on:
push:
branches:
- main
jobs:
bump:
runs-on: ubuntu-latest
permissions:
contents: write
actions: write
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
- uses: commitizen-tools/setup-cz@main
with:
python-version: "3.x"
- id: bump-version
run: |
old_sha="$(git rev-parse HEAD)"
cz --no-raise 21 bump --yes --annotated-tag
if [ "$(git rev-parse HEAD)" = "$old_sha" ]; then
echo "No bump-eligible commits found, skipping release."
echo "bumped=false" >> $GITHUB_OUTPUT
exit 0
fi
echo "bumped=true" >> $GITHUB_OUTPUT
git push --follow-tags
new_version="$(cz version -p)"
echo "new_version=$new_version" >> $GITHUB_OUTPUT
new_version_tag="$(cz version -p --tag)"
echo "new_version_tag=$new_version_tag" >> $GITHUB_OUTPUT
- name: Github Release
if: steps.bump-version.outputs.bumped == 'true'
env:
GH_TOKEN: ${{ github.token }}
NEW_VERSION: ${{ steps.bump-version.outputs.new_version }}
NEW_VERSION_TAG: ${{ steps.bump-version.outputs.new_version_tag }}
run: |
gh release create "${NEW_VERSION_TAG}" --notes-file .changelog.md
cz changelog --dry-run "${NEW_VERSION}" > .changelog.md
How it works¶
- The action will trigger the workflow on every push to the
mainbranch. - The job requests
contents: writeandactions: writeso it can push the bump commit and tag, and trigger dependent workflows. - Setup: The
setup-czaction installs the Commitizen CLI with the requested Python version - Bump: The
cz bump --yes --annotated-tagcommand automatically:- Determines the version increment based on your commit messages
- Updates version files (as configured in your
pyproject.tomlor other config) - Creates a new annotated git tag
- Generates/updates the changelog
- Push:
git push --follow-tagspushes the bump commit along with the new tag back to the repository - Github Release: creates a Github Release
Once you push this workflow file to your repository, it will automatically run on the next push to your default branch.
Check out commitizen-tools/setup-cz for more details.
Previewing the Version Bump on Pull Requests¶
To help reviewers spot unexpected version bumps before merging, you can run
cz version -p on every pull request and post (or update) a sticky
comment summarizing the would-be version bump.
Create .github/workflows/pr-bump-preview.yml:
name: PR bump preview
on:
pull_request_target:
types: [opened, reopened, synchronize, ready_for_review]
permissions:
contents: read
pull-requests: write
jobs:
bump-preview:
# Skip drafts and fork PRs (see "How it works" below).
if: >
${{
github.event.pull_request.draft == false &&
github.event.pull_request.head.repo.full_name ==
github.event.pull_request.base.repo.full_name
}}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
fetch-tags: true
persist-credentials: false
- uses: commitizen-tools/setup-cz@main
with:
python-version: "3.x"
set-git-config: false
- name: Run cz version
id: dry-run
run: |
set +e
output="$(cz version -p --next 2>&1)"
status=$?
set -e
{
echo "status=${status}"
echo "output<<__CZ_BUMP_PREVIEW__"
printf '%s\n' "${output}"
echo "__CZ_BUMP_PREVIEW__"
} >> "$GITHUB_OUTPUT"
- name: Build comment body
env:
STATUS: ${{ steps.dry-run.outputs.status }}
OUTPUT: ${{ steps.dry-run.outputs.output }}
run: |
{
echo "<!-- commitizen-bump-preview -->"
echo "## 🔍 Commitizen bump preview"
echo ""
case "${STATUS}" in
0)
echo "Merging this PR will produce the following bump:"
echo ""
echo '```'
printf '%s\n' "${OUTPUT}"
echo '```'
;;
21)
echo "No commits in this PR are eligible for a version bump."
;;
*)
echo "⚠️ \`cz bump --dry-run\` exited with status \`${STATUS}\`:"
echo ""
echo '```'
printf '%s\n' "${OUTPUT}"
echo '```'
;;
esac
} > comment.md
- name: Find existing preview comment
id: find-comment
uses: peter-evans/find-comment@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue-number: ${{ github.event.pull_request.number }}
comment-author: "github-actions[bot]"
body-includes: "<!-- commitizen-bump-preview -->"
- uses: peter-evans/create-or-update-comment@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
comment-id: ${{ steps.find-comment.outputs.comment-id }}
issue-number: ${{ github.event.pull_request.number }}
body-path: comment.md
edit-mode: replace
You can find the complete workflow in our repository at pr-bump-preview.yml.
Publishing a Python Package¶
After a new version tag is created by the bump workflow, you can automatically publish your package to PyPI.
Step 1: Create a PyPI API token¶
- Go to PyPI Account Settings
- Scroll to the "API tokens" section
- Click "Add API token"
- Give it a name (e.g., "GitHub Actions")
- Set the scope (project-specific or account-wide)
- Click "Add token" and copy the token immediately
Using trusted publishing (recommended)
Instead of API tokens, consider using PyPI trusted publishing with OpenID Connect (OIDC). This is more secure as it doesn't require storing secrets. The pypa/gh-action-pypi-publish action supports trusted publishing when you configure it in your PyPI project settings.
Step 2: Add the token as a repository secret¶
- Go to your repository on GitHub
- Navigate to
Settings > Secrets and variables > Actions - Click "New repository secret"
- Name it
PYPI_PASSWORD - Paste the PyPI token
- Click "Add secret"
Step 3: Create the Publish Workflow¶
Create a new file .github/workflows/pythonpublish.yml that triggers on tag pushes:
name: Upload Python Package
on:
push:
tags:
- "*" # Will trigger for every tag, alternative: 'v*'
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: "3.x"
- name: Install the latest version of uv
uses: astral-sh/setup-uv@v10
- name: publish
run: |
uv sync
uv publish --username "${PYPI_USERNAME}" --password "${PYPI_PASSWORD}"
This workflow uses uv to build and publish the package. You can find the complete workflow in our repository at pythonpublish.yml.
Alternative publishing methods
You can also use pypa/gh-action-pypi-publish or other build tools like setuptools, flit, or hatchling to publish your package.