Reusable Commitizen-based release tooling for monorepo and single-package projects
Project description
release-toolkit
Opinionated Commitizen release tooling for Python projects — works for single-package repos and monorepos with per-package changelogs, with optional Slack notifications on tag pushes.
The headline feature is the impacts_cz Commitizen plugin: in a monorepo,
only commits tagged with Impacts: <package> count toward a package's
version bump and changelog. In a single-package repo it collapses to plain
Conventional Commits.
Requires Python ≥ 3.11 and uv — rt release
runs uv sync / uv run cz bump, rt init writes [dependency-groups].dev
(PEP 735), and the generated GitHub workflow uses astral-sh/setup-uv. Other
package managers (Poetry, plain pip) are not supported out of the box.
Quick start
Install the CLI once on your PATH:
uv tool install release-toolkit
Bootstrap a repo (the CLI also writes a matching GitHub workflow under
.github/workflows/ and adds release-toolkit to [dependency-groups].dev
so cz bump has the plugin available in CI):
# single-package repo
rt init single ./pyproject.toml
# monorepo: PATH NAME pairs
rt init monorepo \
packages/client/pyproject.toml client \
packages/service/pyproject.toml service
uv sync --group dev
Cut a release from the package directory:
rt release # monorepo (uses the Impacts: filter)
rt release --no-filter # single-package repo
rt is a short alias for release-toolkit; both names work everywhere.
Authoring commits
In a monorepo, declare which packages a commit affects via an Impacts:
footer:
feat: add streaming endpoint
Impacts: client, commons
- the footer is matched case-insensitively, on its own line
- tags split on commas/whitespace, matched with word boundaries
- a commit without
Impacts:is invisible to every package - if you want shared-code commits to bump everyone, add a tag like
commonsto every package'simpactslist - the footer name is configurable via
impacts_footer(e.g.Affects)
In a single-package repo, just write Conventional Commits — the plugin has
nothing to filter and behaves like cz_conventional_commits.
Why this exists
Vanilla cz bump reads every commit between the last matching tag and
HEAD when computing the next version. In a monorepo that is wrong — a
feat: for service would still bump client. Commitizen's
changelog_pattern only filters the rendered changelog, not the
increment.
impacts_cz rebuilds changelog_pattern from the package's impacts
list, and rt release applies the same filter when picking
MAJOR / MINOR / PATCH / NONE before invoking cz bump --increment.
CLI reference
rt release
Drives the full flow from one command, run from the package directory:
uv sync --group dev- refuses a dirty worktree
- fast-forwards
--master-branch(defaultmaster); warns on other branches - computes the filtered increment, aborts if
NONE(skip with--no-filter) - shows
cz bump --dry-runand asks[y/N] - runs
cz bump, thengit push --follow-tags
Anything after -- is forwarded to cz bump
(e.g. rt release -- --prerelease beta). Exit 1 with a stderr ERROR: on
abort.
rt init {single,monorepo}
Inserts a default [tool.commitizen] section, appends release-toolkit to
[dependency-groups].dev (with a major-version cap derived from the
running CLI), and writes a caller workflow at
<repo-root>/.github/workflows/release[-<name>].yml.
PATH may be a pyproject.toml file or the directory containing one. Each
file is processed independently — warnings keep exit 0, hard errors
(missing file, TOML parse failure, no .git found) flip to exit 1.
If [tool.commitizen] is already present with name = "impacts_cz" or
release-toolkit is already in dev, the step is a no-op. If the section
exists with a different name, the file is left untouched with a warning.
Override the version source with --version-provider <name> (default
pep621); any built-in or third-party
provider
name is written verbatim.
rt increment
rt increment [--config pyproject.toml]
Prints MAJOR / MINOR / PATCH / NONE. Useful for wiring into other
release pipelines: capture stdout, feed to cz bump --increment.
Generated configs
init single writes:
[tool.commitizen]
name = "impacts_cz"
version_provider = "pep621"
tag_format = "v$version"
annotated_tag = true
changelog_file = "CHANGELOG.md"
update_changelog_on_bump = true
changelog_merge_prerelease = true
init monorepo adds per-package fields:
tag_format = "client-v$version"
bump_message = "bump: client $current_version -> $new_version"
impacts = ["client"]
Tune by hand afterwards if needed:
- add a shared tag (e.g.
commons) toimpactsif shared-code commits should bump this package - override the footer name:
impacts_footer = "Affects"
GitHub building blocks
.github/workflows/release-notify.yml
Reusable workflow. Triggered on a release tag push; generates notes from
cz changelog, creates a GitHub Release, optionally posts to Slack. The
caller is generated by rt init; the example below is for reference:
name: CD Client
on:
push:
tags: ['client-v*']
permissions:
contents: read
jobs:
release:
uses: your-org/release-toolkit/.github/workflows/release-notify.yml@v1
with:
package_dir: pylon_client
tag_prefix: client-v
python_version: '3.11'
secrets:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} # omit to disable
permissions:
contents: write
| input | required | default | meaning |
|---|---|---|---|
package_dir |
yes | — | path to the package's pyproject.toml |
tag_prefix |
yes | — | tag prefix preceding the version (e.g. client-v, v) |
python_version |
no | 3.11 |
Python used by cz changelog |
slack_message_prefix |
no | Released |
prefix for the Slack message |
Slack is fully optional: provide SLACK_WEBHOOK_URL to enable, omit to
disable. No extra plugin to install.
.github/actions/setup-python-env
Composite action that installs Python, uv, and nox at pinned versions.
Inputs: python-version (required), uv-version, nox-version.
Examples
examples/monorepo/—pyproject.tomland caller workflow for a monorepo package usinghatch-vcs.examples/single-package/— same idea, noimpacts.
Copy what you need; they are intentionally minimal.
Developing release-toolkit itself
uv sync --group dev
uv run pytest
uv run ruff check .
uv run pyright
Layout:
src/release_toolkit/
cz_plugin.py # ImpactsCz, build_changelog_pattern
helpers.py # find_filtered_increment, load_config
installer.py # CommitizenConfig, install_into_document
workflow_installer.py # WorkflowConfig, render_workflow
cli.py # argparse + I/O (entry point)
release_runner.py # run_release (subprocess orchestration)
github/
actions/setup-python-env/
workflows/release-notify.yml
The plugin is registered through the commitizen.plugin entry point in
pyproject.toml; do not import it from release_toolkit/__init__.py —
that would re-enter the package during Commitizen's entry-point discovery
and deadlock.
FAQ
rt increment prints NONE but I just merged something. No commits
match the package's Impacts: filter since the last package tag. Either
the commit is missing the footer, or it lists tags this package does not
subscribe to.
cz bump wants to bump but increment says NONE. That is the bug
this toolkit fixes — vanilla cz bump ignores changelog_pattern for
increment computation. Use rt release (or feed --increment to cz bump
yourself) so the filter is honored.
Is the plugin compatible with bump_pattern / breaking-change detection?
Yes — ImpactsCz is a thin subclass of ConventionalCommitsCz that only
rewrites changelog_pattern. Everything else is inherited as-is.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file release_toolkit-0.2.1.tar.gz.
File metadata
- Download URL: release_toolkit-0.2.1.tar.gz
- Upload date:
- Size: 79.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6b67fb057b65fae0cbd3e0b1b4c3145c054dd07a394ebf10066a6db829594394
|
|
| MD5 |
e7e26d0bcc156ac916a7d0b90126fcde
|
|
| BLAKE2b-256 |
7415b4cdaac884337f9486fb1f0107a1b70c43272f9bcd542872805c3f4b427d
|
Provenance
The following attestation bundles were made for release_toolkit-0.2.1.tar.gz:
Publisher:
release.yml on reef-technologies/release-toolkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
release_toolkit-0.2.1.tar.gz -
Subject digest:
6b67fb057b65fae0cbd3e0b1b4c3145c054dd07a394ebf10066a6db829594394 - Sigstore transparency entry: 1459189281
- Sigstore integration time:
-
Permalink:
reef-technologies/release-toolkit@98087dd144e22a9a669ce555e47004b6311125de -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/reef-technologies
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@98087dd144e22a9a669ce555e47004b6311125de -
Trigger Event:
push
-
Statement type:
File details
Details for the file release_toolkit-0.2.1-py3-none-any.whl.
File metadata
- Download URL: release_toolkit-0.2.1-py3-none-any.whl
- Upload date:
- Size: 23.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6c493179193b53fb3c710553105f19092e48a3a55f798b0e877ecda5c56fa109
|
|
| MD5 |
5183452ae564f912353fa3842fda97ee
|
|
| BLAKE2b-256 |
6bc88a8a009b1e2da41f1679a8344e7ce628d6360fbd5d6c5026c70309db04b6
|
Provenance
The following attestation bundles were made for release_toolkit-0.2.1-py3-none-any.whl:
Publisher:
release.yml on reef-technologies/release-toolkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
release_toolkit-0.2.1-py3-none-any.whl -
Subject digest:
6c493179193b53fb3c710553105f19092e48a3a55f798b0e877ecda5c56fa109 - Sigstore transparency entry: 1459189520
- Sigstore integration time:
-
Permalink:
reef-technologies/release-toolkit@98087dd144e22a9a669ce555e47004b6311125de -
Branch / Tag:
refs/tags/v0.2.1 - Owner: https://github.com/reef-technologies
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@98087dd144e22a9a669ce555e47004b6311125de -
Trigger Event:
push
-
Statement type: