Releasing¶
workspace.package.version in Cargo.toml sets the
version of both Rust crates and the Python package. Maturin reads it through
the dynamic version in pyproject.toml; Cargo.lock records the same value.
The Rust crates are internal and are not published to crates.io.
The release build targets CPython 3.12–3.15 on Linux with glibc 2.17 or newer
(x86-64 and arm64), macOS (Intel and Apple silicon), and Windows x86-64,
plus one source distribution. The Python classifiers and license-files in
pyproject.toml define the expected distributions.
Publication requires that every configured wheel builds and passes its
installation checks. The Intel macOS wheels are built on Apple-silicon runners
and checked on Intel runners. PyPy, free-threaded CPython, musllinux, Windows
ARM64, abi3 wheels and conda are outside this release.
Repository setup¶
Before the first release, check these settings:
- Make the repository public and enable the protections below.
- Give the Codecov GitHub App access to the repository. The coverage upload
uses OIDC for the badge and is best-effort. CI enforces coverage independently
from the saved reports; a Codecov upload failure does not fail
CI Success. - Register pending trusted publishers on TestPyPI and PyPI for
yaugenst/treams-rs, workflowpublish-release.yml, with environmentstestpypiandpypirespectively. Existing projects use the same publishers. - Create the
testpypi,pypiandreleaseGitHub environments. All three accept deployments only frommain, excluding tags. Require a release operator's approval forrelease; a sole operator needs self-review enabled. - Protect
v*tags: only release operators may create them, and updates, force pushes and deletion are forbidden. - Set GitHub Pages Source to GitHub Actions. The documentation workflow
publishes the complete version tree through a Pages artifact;
gh-pagesstores the version history used by mike. - Enable private vulnerability reporting.
- Ensure the release operator can send a repository dispatch with contents-write access.
Prepare a version¶
- Set the version in
Cargo.toml, then runcargo check --workspaceto updateCargo.lock. - Finish the release entry in
CHANGELOG.md, set its date, and add an emptyUnreleasedsection. Set the matchingversionanddate-releasedinCITATION.cff. - Follow Development to install the locked tools and framework
dependencies. Run
just ci,just check-wheel,just licenses-check,just denyandjust formal. - Commit the version and release notes, land them on
main, and wait forCI Successon that exact push. Check that the version is unused on TestPyPI, PyPI and in Git tags.
Publish¶
Dispatch from an authorized GitHub CLI session after main CI passes. The version tag must not exist yet:
gh api --method POST repos/yaugenst/treams-rs/dispatches \
-f event_type=release \
-f 'client_payload[tag]=vX.Y.Z'
The publication workflow
fixes the candidate to the current main commit and requires a successful
CI Success from a push to that commit. It builds and checks the complete
set of wheels and source distribution, checks metadata and local-path removal,
and smoke-tests every distribution in clean environments. It then uploads the
candidate to TestPyPI and tests a clean installation from there. That step is
advisory: TestPyPI has no service-level agreement, so a failed upload or
installation there is reported in the workflow summary but does not block
promotion. To skip it, add -f 'client_payload[skip_testpypi]=true' to the
dispatch.
When Approve production release starts waiting, use the candidate revision
in the workflow summary to create and push the annotated tag:
git tag -a vX.Y.Z CANDIDATE_SHA -m "treams-rs X.Y.Z"
git push origin vX.Y.Z
Then approve the release environment. The workflow checks that the tag
still points to the tested candidate before publishing versioned docs, the
GitHub Release and the same distributions on PyPI. It checks a clean PyPI
installation afterward. Do not create the tag before the approval job waits:
the missing tag also prevents publication if environment protection is lost.
Avoid merging to main until publication finishes. Documentation deployments
share a queue; GitHub may cancel an older waiting job when a newer job queues.
If the documentation job is cancelled, rerun failed jobs; the tag check runs
again.
After the workflow finishes, confirm:
- the GitHub Release contains every wheel, one source distribution, checksums and the provenance manifest;
- the clean PyPI installation check passed;
/X.Y.Z/and/latest/serve the released documentation, including rustdoc, and the site root opens the latest release.
Never replace a published file or move a version tag. A candidate whose files reached TestPyPI consumes its version there too, since filenames cannot be reused: if it turns out faulty, fix the issue and choose the next version. A TestPyPI failure before any upload, such as an outage, consumes nothing.
Documentation site¶
The reusable Docs workflow checks pull
requests and publishes dev from main. A release publishes X.Y.Z and
updates latest; the site root follows latest after the first release.
Every version includes its Rust reference and Markdown sources. Source links
refer to the documented commit.
To correct released documentation without changing the package, run
Deploy docs from main. Set version to an
existing release X.Y.Z and source_revision to the full commit SHA of the
correction. The workflow requires the existing release and immutable tag.
It replaces that version's documentation and updates latest only for the
newest release. It does not change the package files or release tag.
Check a wheel locally¶
just check-wheel builds an optimized wheel, checks it for local build paths,
and runs smoke_wheel_install.py in
clean environments with NumPy only, Advect, HIPS Autograd and HDF5. CI runs the same smoke
checks for every configured wheel and for a wheel rebuilt from the source
distribution. Local success does not replace those platform checks.