Release workflow¶
This document describes how pymqrest versions are managed and published to PyPI.
Version management¶
The version is stored statically in pyproject.toml under
[project].version. It follows semantic versioning (MAJOR.MINOR.PATCH).
After each release, the publish workflow automatically opens a PR to
bump the patch version on develop. This default can be overridden at
any time by changing the version to a minor or major bump instead.
Release flow¶
- Develop — All feature work merges into
develop. Ensure the version inpyproject.tomlis set to the desired release version. - Prepare release — Run the release preparation script from
develop:
The script automates everything needed to get a release PR open:
- Validates preconditions (on develop, clean tree, tools available)
- Creates a release/X.Y.Z branch from develop
- Generates the changelog via git-cliff
- Commits the changelog update on the release branch
- Pushes the branch and creates a PR to main
- Enables auto-merge (regular merge, delete branch)
- Merge to main — The PR merges automatically once CI passes
using a regular merge commit (not squash). This preserves shared
ancestry between
mainanddevelop, avoiding history divergence. If auto-merge is not enabled on the repository, merge manually with--merge. - Automatic publish — The
publish.ymlworkflow fires on push tomainand: - Extracts the version from
pyproject.toml - Skips if the version is already on PyPI (idempotent)
- Builds sdist and wheel with
uv build - Publishes to PyPI via OIDC trusted publishing
- Creates an annotated git tag (
vX.Y.Z) - Creates a
develop-vX.Y.Zlightweight tag ondevelopfor git-cliff boundary tracking - Creates a GitHub Release with install instructions and dist artifacts
- Opens a PR against
developto bump the patch version (e.g.1.0.0→1.0.1), assuming the next release is a patch
Automatic version bump¶
After each successful publish, the workflow creates a PR to increment
the patch version on develop. This keeps the working version ahead of
the last release and ready for the next patch. The bump PR also
refreshes all dependencies to their latest compatible versions via
uv lock --upgrade and re-exports requirements.txt and
requirements-dev.txt.
If the next release should be a minor or major bump instead, simply
change the version in pyproject.toml at any point during the
development cycle — the automated PR is just a default starting point.
The bump PR is skipped if develop already has the expected next
version (e.g. if someone bumped it manually first).
Changelog¶
The project changelog is maintained in CHANGELOG.md using
git-cliff, configured via cliff.toml at
the repository root.
git-cliff is a local developer tool (not required in CI). Install it with Homebrew:
How it works¶
git-cliff uses develop-vX.Y.Z lightweight tags as version boundary
markers. These tags point to commits on develop and are created
automatically by the publish workflow after each release. They allow
git-cliff to determine which commits belong to each version when run
on develop or a release branch.
To regenerate the changelog from scratch:
To generate the changelog with a new version heading (used during the release flow):
CI validation¶
The release-gates CI job validates that CHANGELOG.md contains an
entry matching the version in pyproject.toml for PRs targeting
main. This ensures the changelog is always updated before a release.
CI version gates¶
Pull requests trigger additional version checks:
- PRs targeting main: Version must not already exist on PyPI, must
be greater than the latest published version, and
CHANGELOG.mdmust contain an entry for the version. - PRs targeting develop: Version must differ from the version on
main(prevents accidental no-op releases).
PyPI trusted publisher setup (one-time)¶
Before the first release, the repository owner must configure OIDC trusted publishing on PyPI:
- Go to https://pypi.org/manage/account/publishing/.
- Add a pending publisher:
- Project name:
pymqrest - Owner:
wphillipmoore - Repository:
pymqrest - Workflow name:
publish.yml - Environment: (leave blank)
- The first publish will claim the package name.
See the PyPI trusted publisher documentation for details.
Troubleshooting¶
Version already exists on PyPI¶
The publish workflow skips publishing if the version already exists. To
release a new version, bump the version in pyproject.toml and go
through the release flow again.
Tag already exists¶
The publish workflow skips tag creation if the tag already exists. This is expected when re-running a failed workflow.
Publish fails¶
Check the workflow logs for OIDC authentication errors. Ensure the
trusted publisher is configured correctly on PyPI. The workflow only
triggers on push to main, so the id-token: write permission is
scoped to that branch.