Release

Releases follow semantic versioning and use automated workflows to handle version bumping, changelog building, commit creation, and publishing. Maintainers trigger releases through GitHub Actions or run the release script locally for testing.

Changelog Fragments

Contributors add changelog fragments that get collected during releases. Create a file in docs/changelog/ named <pr_number>.<type>.rst where type is feature for new functionality, bugfix for fixes, doc for documentation changes, removal for deprecations, or misc for internal changes. The file should contain a single line describing the change, optionally crediting the author with :user:`username` syntax. For example, 123.feature.rst might contain Add support for custom backends - by :user:`contributor`. These fragments are collected during releases to build the changelog automatically.

Automated Release

Navigate to the pre-release workflow and click Run workflow. Select a version bump type: auto for patch bumps, major for X+1.0.0, minor for X.Y+1.0, or patch for X.Y.Z+1.

The workflow updates the version in src/build/__init__.py, runs towncrier build to collect changelog fragments from docs/changelog/ and incorporate them into CHANGELOG.rst, creates a release commit with message chore: prepare for X.Y.Z, creates an annotated tag, and pushes both to trigger the CD workflow.

The tag push triggers the continuous deployment pipeline which builds the source distribution and wheel, creates a GitHub release with auto-generated notes, generates build attestations for supply chain security, and publishes to PyPI via trusted publishing. The process takes approximately five minutes from workflow trigger to published package.

Local Release

Run the release script locally for testing or manual control. Ensure tox is installed and git identity is configured:

$ pip install tox
$ git config user.name "Your Name"
$ git config user.email "your@email.com"

The script creates annotated git tags without GPG signing. Package authenticity is guaranteed by PyPI attestations, not git tag signatures.

Dry run without pushing

Test the release process locally:

$ tox -e release -- --version auto --no-push

This updates the version file, builds the changelog from fragments, creates the commit and tag locally, but does not push to the remote repository.

Full local release

Specify an explicit version or bump type:

$ tox -e release -- --version 1.5.0
$ tox -e release -- --version patch  # 1.4.0 → 1.4.1
$ tox -e release -- --version minor  # 1.4.0 → 1.5.0
$ tox -e release -- --version major  # 1.4.0 → 2.0.0

The script updates src/build/__init__.py, runs towncrier build to collect changelog fragments, runs pre-commit hooks, creates a commit with message chore: prepare for X.Y.Z, creates an annotated tag, and pushes both to origin. The GitHub Actions CD workflow takes over to build and publish.

See also

PyPI removed PGP signature support in May 2023. Package authenticity is guaranteed through PyPI attestations per PEP 740, which cryptographically link packages to their source repository and build process.

Troubleshooting

Workflow timeout

If the pre-release workflow times out, run the release script locally with --no-push, then manually push with git push && git push --tags. The CD workflow triggers automatically on tag push.

Publishing conflicts

If a version is already published to PyPI, the publish job fails safely. The CD workflow is idempotent except for PyPI publishing. For corrections, create a post-release like X.Y.Z.post1.

Implementation

The automation consists of the pre-release workflow at .github/workflows/pre-release.yml for manual triggering, the CD workflow at .github/workflows/cd.yml that triggers on tag pushes, the release script at tasks/release.py for version bumping and tag creation, and the [env.release] environment in tox.toml providing dependencies.