Release Workflow (Maintainers Only)
The release workflow includes two tools to help automate the process.
Towncrier aggregates all files in newsfragments/ into CHANGELOG.md, then deletes the used fragment files.
Bump My Version updates the version in the appropriate files.
This workflow produces:
one release commit (version bumps + changelog),
one git tag (
vX.Y.Z).
Note:
Do not run this on forks of the project
This requires tag permissions
Pre-Release Actions
When it is determined that a new release should be made, these steps should be taken.
Ensure all tests are passing
Ensure all documentation is generated
Ensure all examples run
Prerequisites
Make sure the working tree is ready for a release
Up to date with upstream
mainVerify tests and basic install/use
Release environment available (uv, towncrier, bump-my-version)
Decide on the type of release (
patch,minor, ormajor)Review/edit fragment wording for clarity
Call out breaking changes explicitly (if any)
Ensure release notes are understandable to users
Step-By-Step Release
At release time, the following steps need to be completed.
1) Sync and create a release branch
git checkout main
git pull --ff-only
git checkout -b release/next
2) Verify news fragments exist
uv run towncrier check
This should report no problems.
If this reports any problems, add/fix fragments in newsfragments/ before continuing.
3) Check clean git tree and bump the version (updates files, no commit/tag yet)
Check to make sure the git tree is ready for release. If the following command prints anything, fix it before continuing:
git status --porcelain
Choose one based on the type of release:
major release:
uv run bump-my-version bump major --no-commit --no-tagminor release:
uv run bump-my-version bump minor --no-commit --no-tagpatch release:
uv run bump-my-version bump patch --no-commit --no-tag
This updates the version in all configured files (e.g. pyproject.toml, sphinx/source/conf.py).
4) Read the new version from pyproject.toml
NEW_VERSION="$(python - <<'PY'
import tomllib
with open("pyproject.toml","rb") as f:
print(tomllib.load(f)["project"]["version"])
PY
)"
echo "Releasing $NEW_VERSION"
5) Preview the changelog (no files modified)
uv run towncrier build --draft --version "$NEW_VERSION"
Review the output for wording and grouping. If needed, edit fragments (or add a missing fragment).
6) Build the changelog (writes project CHANGELOG and removes fragments)
uv run towncrier build --version "$NEW_VERSION" --yes
Optional: specify a date explicitly:
uv run towncrier build --version "$NEW_VERSION" --date 2026-02-13 --yes
NOTE: Towncrier must write to the canonical root ./CHANGELOG.md.
7) Run the Full Check Suite
The following script runs type-checking, linting, and the test suite. Make sure there are no errors or warnings.
./scripts/run_checks.sh
8) Commit the release changes
git add .copier-answers.yml CITATION.cff src/buffalo_example/__init__.py pyproject.toml CHANGELOG.md newsfragments/ sphinx/source/conf.py uv.lock
git commit -m "Bump to new version -> v$NEW_VERSION"
9) Push branch
git push -u origin HEAD
10) Create the Codeberg release PR
On Codeberg, create a release PR for tag v$NEW_VERSION from the release branch into main, merge it once CI is green.
Use the CHANGELOG.md section for $NEW_VERSION as the release notes.
11) Tag the release
After PR merged then can tag it.
git checkout main
git pull --ff-only
git tag -a "v$NEW_VERSION" -m "Release v$NEW_VERSION"
git push origin "v$NEW_VERSION"
12) Release to PyPI
If Codeberg/forgejo workflow queues are not clearning quickly then see PyPI Release Workflow for steps to take to manually publish the packages.
13) Publish Documentation
If Codeberg/forgejo workflow queues are not clearing quickly then see Docs Release Workflow for steps to take to manually publish the documentation.