Releasing¶
Releases are deliberate maintainer actions. The Release workflow builds and verifies distributions on pull requests that change code or build inputs, and on every manual run, without publishing. Documentation-only pull requests run the configuration and CI helper checks without building distributions. Publishing a non-prerelease GitHub release also builds and verifies the distributions, then publishes those same artifacts to PyPI through OIDC.
One-time setup¶
Create a GitHub environment named pypi in the repository settings. On PyPI,
configure a pending Trusted Publisher for the first release:
| Field | Value |
|---|---|
| PyPI project name | polars-intervals |
| GitHub owner | jplauri |
| Repository | polars-intervals |
| Workflow filename | release.yml |
| Environment | pypi |
For an existing PyPI project, configure the same Trusted Publisher in its publishing settings. These settings must match the workflow before publishing.
Rehearse without publishing¶
In GitHub Actions, select Release, choose Run workflow, and select the branch to verify. A manual run never publishes, even when run on a release tag.
Review the complete run and download its distribution artifacts. The workflow
is the source of truth for the platform and Python matrix. Every expected wheel
must be present, installed in an isolated environment, and pass the Python tests,
API doctests, and a real overlap_count smoke test. The sdist must independently
build and install outside the checkout and pass its smoke test. Artifact metadata
checks must also pass.
The sdist includes rust-toolchain.toml and Cargo.lock; release builds use the
pinned Rust toolchain and locked dependencies. An import from the checkout is not
evidence that an installed distribution works. Do not advertise a platform until
its artifact verification passes.
Publish a version¶
- Prepare the version and release notes in a reviewed PR.
Update
crates/polars-intervals/Cargo.tomlandcrates/intervals-core/Cargo.tomlto the same release version. The Python package version comes from the former manifest; the workflow does not bump versions. Describe user-visible changes, installation, and compatibility. - Run the development checks
and
uv lock --check. Preserve the locked Rust checks and strict Rust documentation check, as well as the Python and strict MkDocs checks. Merge the reviewed changes, require normal CI to pass on the finalmastercommit, and complete a manual release rehearsal for that commit. - Create the tag at that exact reviewed commit. Its name must be
vX.Y.Z, matching the package version exactly:v0.1.0for0.1.0. Publish a GitHub release using that tag and the release notes. Leave Set as a pre-release unchecked. Pushing a tag alone does not publish to PyPI. - Watch the release workflow. Only a published, non-prerelease GitHub release
can reach the
pypipublishing job, after successful artifact verification. That job downloads the verified artifacts and publishes them without rebuilding. - Verify the published version from PyPI as described below. Inspect its project page and distribution files as well as the installation result.
Repeat these steps for future releases, updating versions, release notes, and documentation before tagging. Do not change API behavior as part of the release process itself.
Verify the PyPI installation¶
After publishing, run this outside the repository using a supported Python version. It creates an isolated environment and verifies actual overlap counts:
uv run --isolated --no-project --with polars-intervals==0.1.0 python -c "import polars as pl; import polars_intervals as pi; df = pl.DataFrame({'start': [1, 3, 2, 2], 'end': [3, 5, 4, 2]}); actual = df.select(pi.overlap_count('start', 'end')).to_series().to_list(); assert actual == [1, 1, 2, 0], actual; print(actual)"
Use the newly published version in place of 0.1.0 for subsequent releases.