Releasing¶
Project — This page gives maintainers the steps to publish a release, and Compatibility explains what may change between versions.
Maintainer runbook. X.Y.Z is the version being released. Pushing an
annotated tag vX.Y.Z runs
release.yml: the gate job checks the
tag against project.version, runs make verify, builds the sdist and wheel,
installs the wheel into an empty venv and smoke-tests it; only then does the
publish job upload exactly those artifacts to PyPI through trusted publishing.
One-time setup (already done for ontary)¶
PyPI trusted publisher: project ontary, owner ryoochi0112, repository
ontary, workflow release.yml, environment pypi. The pypi environment
exists in the repository settings and is restricted to v* tags. No API token
is stored anywhere.
Action pins¶
Every uses: in the workflows is pinned to a commit SHA with a # vX.Y.Z
comment. Dependabot bumps the SHA and the comment together in a weekly PR;
never edit a uses: line by hand. The workflows job in verify.yml fails
the PR if a pin is missing.
Cutting a release¶
- On a branch, set
project.versioninpyproject.tomltoX.Y.Z. - In
README.md, update the version badge line (version **X.Y.Z**, store schema **vN**), the tag line (annotated tags (`vX.Y.Z`)), both==X.Y.Zpins under## Install(theuv addfence and thepyproject.tomlsample), and the git-ref install fallback line (the one pinned to the release tag). - In
CHANGELOG.md, rename## [Unreleased]to## [X.Y.Z] — YYYY-MM-DD, put the git-ref install fence (theuv add "ontary @ git+…"line from the previous release section, re-pinned tovX.Y.Z) under the heading, and open a fresh empty## [Unreleased]above it.make verifyfails if any of these versioned references is missed. make verify, open the PR, merge it.- Tag the merge commit and push the tag:
git checkout main && git pull --ff-only
git tag -a vX.Y.Z -m "Release vX.Y.Z"
git cat-file -t vX.Y.Z # must print: tag
git push origin vX.Y.Z
- Watch the
releaseworkflow. If a job fails, fix and use Re-run failed jobs, never Re-run all jobs: PyPI refuses a filename it has seen, so a rebuild fails at upload even when the bytes match. - Confirm from an empty environment:
uv venv --python 3.12 /tmp/ontary-pypi-X.Y.Z
VIRTUAL_ENV=/tmp/ontary-pypi-X.Y.Z uv pip install "ontary==X.Y.Z"
/tmp/ontary-pypi-X.Y.Z/bin/python scripts/install_smoke.py
PyPI's index can lag by a minute; retry rather than re-publish.
If GitHub Actions cannot run¶
Build from a clean detached worktree of the tag (uv build --out-dir dist),
run scripts/install_smoke.py against the wheel in an empty venv, and publish
with UV_PUBLISH_TOKEN set to a project-scoped PyPI token that you revoke
afterwards. Never write the token to a file in the repository.