Release Operator Runbook
This runbook covers validation, publication, verification, and recovery for an
adidt release. The Publish Release workflow builds on manual dispatch but
publishes only when an annotated v* tag is pushed.
One-time setup
PyPI trusted publisher
Before the first release, sign in to PyPI and add a pending trusted publisher with these exact values:
PyPI project name:
adidtOwner:
analogdevicesincRepository:
pyadi-dtWorkflow:
release.ymlEnvironment:
pypi
After the first successful upload, verify that the pending publisher became a publisher for the newly created project.
GitHub environment
Create a GitHub environment named pypi. Require a release reviewer and limit
deployment refs to tags matching v*. The PyPI job requests OIDC only inside
this environment; no PyPI API token is required.
Prepare and validate
Confirm the target version agrees in
pyproject.tomlandadidt/__init__.pyand has a non-empty## [X.Y.Z]section inCHANGELOG.md.Run the local contract and package checks from a clean checkout:
git fetch origin --tags git switch main git pull --ff-only origin main test -z "$(git status --porcelain)" python .github/scripts/release_preflight.py --tag vX.Y.Z pytest rm -rf build dist python -m build twine check dist/*
Run the hosted dry run from
main. The candidate tag does not need to exist yet:gh workflow run release.yml --ref main -f tag=vX.Y.Z gh run watch --exit-status
Confirm the validation, Python 3.10–3.13, build, wheel-install, and CLI smoke-test jobs pass. The GitHub Release and PyPI jobs must be skipped.
Confirm all required
mainworkflows—including hardware, Kuiper/Ubuntu Debian packaging, and native system packaging—are green for the exact commit to be tagged. The native workflow builds on Debian 12, Fedora 42, and macOS 14 rather than cross-packaging those artifacts on Ubuntu.
Tag and publish
Record and inspect the exact release commit before tagging:
git switch main
git pull --ff-only origin main
test -z "$(git status --porcelain)"
RELEASE_SHA=$(git rev-parse HEAD)
git show --stat "$RELEASE_SHA"
git tag -a vX.Y.Z "$RELEASE_SHA" -m "Release vX.Y.Z"
test "$(git cat-file -t refs/tags/vX.Y.Z)" = tag
git push origin refs/tags/vX.Y.Z
The tag push is the only event that permits the workflow’s GitHub Release and
PyPI jobs to run. Approve the pypi environment deployment only after checking
that the run’s tag, commit SHA, version, changelog, tests, and built artifacts
are correct.
Verify the published release
Confirm Publish Release completed successfully for the tagged SHA.
Confirm both packaging workflows completed for the same tag. The release must contain Kuiper/Ubuntu
.debfiles plus the Debian 12.deb, Fedora 42.rpm, and macOS 14.pkgartifacts. Each job installs and smoke-tests its package before upload.Verify the GitHub Release contains the wheel, source distribution, release notes, all native system packages, and the
SHA256SUMSmanifest file.Verify checksum manifest integrity:
gh release download vX.Y.Z -D /tmp/adidt-verify-assets cd /tmp/adidt-verify-assets sha256sum -c SHA256SUMS python .github/scripts/release_manifest.py verify --manifest SHA256SUMS --dir .
Verify PyPI and smoke-test the immutable published package:
python -m venv /tmp/adidt-release-verify /tmp/adidt-release-verify/bin/python -m pip install --no-cache-dir adidt==X.Y.Z /tmp/adidt-release-verify/bin/python -c \ 'import adidt, importlib.metadata as m; assert adidt.__version__ == m.version("adidt") == "X.Y.Z"' /tmp/adidt-release-verify/bin/adidtc --help
Verify the public documentation still serves successfully.
Recover from partial failure
Release files on PyPI are immutable. Never move or reuse a version after any artifact for it has been accepted by PyPI.
Validation/build failed before publication: fix
main, delete the failed remote tag only if neither PyPI nor a release artifact was published, rerun the dry run, and create a new annotated tag on the corrected commit.PyPI upload partially succeeded: rerun the failed jobs. Publishing uses
skip-existing, so accepted files are retained and missing files can resume. Do not rebuild different bytes for the same version.GitHub Release failed after PyPI succeeded: rerun the failed job. The workflow creates a missing release or uploads artifacts to an existing one with
--clobberand updatesSHA256SUMS.System-package attachment failed: rerun the failed Debian or native-system package workflow for the original tag; do not retag.
Checksum manifest out of sync: re-sync the release manifest using the helper script:
python .github/scripts/release_manifest.py upsert-release --tag vX.Y.Z
A bad package was fully published: keep the tag and release as an audit record, document the problem, bump to a new version, and publish a corrective release. PyPI versions cannot be replaced safely.