Cutting a release¶
Step-by-step for tagging, building, and publishing a new version of
ematix-flow to PyPI. The CI pipeline does the heavy lifting; this
checklist captures the human prerequisites + the order to run things
in.
One-time setup¶
These prerequisites must be configured before the first release. Once done they persist.
1. PyPI trusted publisher¶
Add the trusted publisher on https://pypi.org/manage/project/ematix-flow/settings/publishing/:
- Owner:
ryan-evans-git - Repository name:
ematix-flow - Workflow filename:
release.yml - Environment name:
pypi
For the very first release the project doesn't exist yet on PyPI — add the publisher as a "pending publisher" instead, on https://pypi.org/manage/account/publishing/. After the first successful publish the pending record auto-promotes to a real one.
2. GitHub environment¶
Create a pypi environment under
Settings → Environments and add the id-token: write permission.
Optionally restrict the environment to tag pushes matching v*.*.*
so a stray manual workflow run can't publish.
3. GitHub Pages (for the docs site)¶
Settings → Pages → Source = GitHub Actions. The docs.yml
workflow handles deployment.
Per-release checklist¶
Pre-tag¶
- Pull the latest
main. - Confirm
cargo test --workspace --libpasses locally. - Confirm
pytest tests/pythonpasses locally. - Confirm
cargo fmt --all -- --checkandcargo clippy --workspace --all-targets -- -D warningsare clean. - Confirm
cargo auditandpip-audit --skip-editablepass locally - Optional but recommended for production releases: run
bash scripts/local-manylinux-build.sh 3.12to build a wheel inside the samequay.io/pypa/manylinux_2_28_x86_64Docker container the CI uses. Catches CI-only build failures (missing C headers, glibc / C++ ABI mismatches, vendored-lib breakage) without burning Actions minutes. Requires Docker and ≥8 GB RAM allocated to it. (the CI'sverifyjob runs both — seeSECURITY.mdfor what the gates check and the list of accepted advisories). - Bump
versioninpyproject.toml. Match the workspace version in the rootCargo.toml's[workspace.package]block. - Add a new
## [X.Y.Z] — YYYY-MM-DDsection at the top ofCHANGELOG.md, summarizing the changes since the previous release. Move "Unreleased" entries down. - Update
[Unreleased]and the new tag's compare-link footnote at the bottom ofCHANGELOG.md. - Skim
docs/ROADMAP.md: if any P0/P1 items shipped in this release, mark them done (or remove them). - If new features shipped, ensure
docs/USER_GUIDE.mdcovers them and theexamples/directory has at least one demonstrating each.
Tag + push¶
# From a clean working tree on main:
git tag -a v0.1.0 -m "v0.1.0 — first public release"
git push origin v0.1.0
The release.yml workflow fires on tag push:
- Runs the
verifyjob: rustfmt + clippy + tests + cargo audit + ruff + bandit + pip-audit + pytest. Wheels and the sdist only build if this passes — seeSECURITY.mdfor the per-tool gate spec. - Builds wheels for Linux x86_64 (manylinux2014) and macOS
aarch64, across Python 3.11 / 3.12 / 3.13 — 6 wheels
total. (Intel Mac + Python 3.10 wheels were dropped — see the
top-of-file comment in
release.yml. Those users install from sdist, which still works sincerequires-python = ">=3.10".) - Builds the source distribution.
- Uploads everything to https://pypi.org/p/ematix-flow via trusted publishing (no API token required).
The docs.yml workflow on push to main deploys the mkdocs site to
https://ryan-evans-git.github.io/ematix-flow/.
Post-publish¶
- Verify the wheels installed end-to-end:
pip install --no-cache ematix-flow==X.Y.Z, thenpython -c "import ematix_flow; print(ematix_flow.__version__)". - Verify the docs site updated.
- Create a GitHub Release from the tag, copying the relevant
CHANGELOG.mdsection into the release body. - Announce in the relevant places (Slack, mailing list, blog post).
Rollback¶
If a release goes out and a critical bug surfaces:
- Don't yank unless the published wheel is dangerous (auth bug leaking secrets, etc.) — see PEP 592 yanking semantics.
- Cut
vX.Y.(Z+1)with the fix; theskip-existingflag in the publish workflow plus PyPI's immutability guarantee make this safe. - If yanking is required: PyPI web UI → project page → release
detail → "Yank release". Yanked versions stay installable for
pinned consumers but aren't selected by
pip install ematix-flow.
Test releases (TestPyPI)¶
Not currently wired. To add:
# .github/workflows/release.yml — additional job
publish-test:
if: github.event_name == 'workflow_dispatch'
needs: [build-linux, build-macos, build-sdist]
runs-on: ubuntu-latest
environment:
name: testpypi
url: https://test.pypi.org/p/ematix-flow
permissions:
id-token: write
steps:
- uses: actions/download-artifact@v4
with:
path: dist
merge-multiple: true
- uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
skip-existing: true
Add a matching trusted publisher on TestPyPI + a testpypi
GitHub environment. Then workflow_dispatch runs publish to
TestPyPI; tag pushes still go to production PyPI.