|
| 1 | +# ADR 0006: PyPI Release Strategy for `codetracer-python-recorder` |
| 2 | + |
| 3 | +- **Status:** Proposed |
| 4 | +- **Date:** 2025-10-13 |
| 5 | +- **Deciders:** Codetracer Runtime & Tooling Leads |
| 6 | +- **Consulted:** Release Engineering, Developer Experience, Platform Reliability |
| 7 | +- **Informed:** Product Management, Support, Security |
| 8 | + |
| 9 | +## Context |
| 10 | + |
| 11 | +We are ready to publish the first public release of the Rust-backed `codetracer-python-recorder` |
| 12 | +module to PyPI. The business goal is to distribute an officially supported recording module for |
| 13 | +Python 3.12 and 3.13 across Linux, macOS, and Windows, with both binary wheels and a source |
| 14 | +distribution that downstream teams can audit and rebuild. |
| 15 | + |
| 16 | +A repository review shows that: |
| 17 | + |
| 18 | +- Packaging metadata in `codetracer-python-recorder/pyproject.toml` still targets Python 3.8+, |
| 19 | + omits Trove classifiers for supported versions and platforms, and does not expose project URLs |
| 20 | + or the README as the long description. |
| 21 | +- The `Justfile` and CI only support developer builds (`maturin develop`) and Linux test jobs; |
| 22 | + there is no automated release workflow and no multi-platform wheel builds. |
| 23 | +- `tool.maturin` configuration does not yet declare source-distribution rules, exclude build |
| 24 | + artefacts, or ensure that `Cargo.toml` / `pyproject.toml` versions stay synchronized. |
| 25 | +- There is no documented path for staging releases on TestPyPI or for securely authenticating a CI |
| 26 | + workflow to PyPI. |
| 27 | + |
| 28 | +We consulted the Python Packaging User Guide packaging flow |
| 29 | +([packaging.python.org](https://packaging.python.org/en/latest/flow/)) and the maturin distribution |
| 30 | +guide ([maturin.rs](https://www.maturin.rs/distribution.html)). Key takeaways include: |
| 31 | + |
| 32 | +- Every release must produce both wheels and an sdist, validate metadata with tooling, and verify |
| 33 | + installability before uploading. |
| 34 | +- PyPI now recommends OpenID Connect “Trusted Publishing” for CI-driven uploads instead of storing |
| 35 | + long-lived API tokens. |
| 36 | +- maturin provides first-class support for building manylinux, macOS universal2, and Windows wheels, |
| 37 | + plus TestPyPI/PyPI uploads from CI runners. |
| 38 | + |
| 39 | +## Decision |
| 40 | + |
| 41 | +1. **Metadata hardening:** Update `pyproject.toml` to `requires-python = ">=3.12,<3.14"`, include |
| 42 | + the project README as the long description, add platform-specific Trove classifiers (Linux, |
| 43 | + macOS, Windows; CPython 3.12/3.13; Rust), and publish canonical URLs (homepage, repository, |
| 44 | + issues). Mirror the version in `Cargo.toml` and add a guard that compares Rust and Python |
| 45 | + versions during CI. |
| 46 | +2. **Distribution artefacts:** Continue to use maturin as the build backend. For the initial public |
| 47 | + release, build per-version wheels (`cp312` and `cp313`) for |
| 48 | + - manylinux2014 `x86_64` and `aarch64`, |
| 49 | + - macOS universal2 (`x86_64` + `arm64`), |
| 50 | + - Windows `amd64`. |
| 51 | + Produce a source distribution via `maturin sdist`, ensuring `Cargo.lock`, Rust sources, and Python |
| 52 | + shim modules are included while excluding wheel artefacts (`target/`, compiled `.so` files). |
| 53 | + Evaluate enabling the `pyo3/abi3-py312` feature after the first release to collapse per-version |
| 54 | + wheels. |
| 55 | +3. **Pre-release verification:** Extend the release pipeline to run unit tests against the built |
| 56 | + artefacts, execute smoke installs (`pip install` from the local wheel and sdist), and run the CLI |
| 57 | + (`python -m codetracer_python_recorder --help`) before any upload step. |
| 58 | +4. **Trusted publishing workflow:** Create a dedicated GitHub Actions workflow triggered by |
| 59 | + annotated tags (e.g., `recorder-v*`). The workflow will: |
| 60 | + - Build and test wheels on each platform matrix job. |
| 61 | + - Upload artefacts to a staging job that performs TestPyPI publishing via maturin. |
| 62 | + - Require a manual approval (environment protection) before promoting the same artefacts to the |
| 63 | + production PyPI repository. |
| 64 | + Configure the PyPI project as a Trusted Publisher for the repository so uploads rely on OIDC |
| 65 | + tokens instead of stored secrets. |
| 66 | +5. **Versioning & change management:** Adopt a documented version-bump process that updates both |
| 67 | + `pyproject.toml` and `Cargo.toml`, updates the changelog/release notes, and tags releases using |
| 68 | + `recorder-vMAJOR.MINOR.PATCH`. Enforce semantic-versioning semantics via review, and block |
| 69 | + accidental reuse of versions by asserting that the requested tag matches the metadata. |
| 70 | +6. **Documentation & support:** Add a release checklist to the repository (under `design-docs`) that |
| 71 | + references PyPI’s packaging flow steps (metadata validation, TestPyPI verification, final |
| 72 | + release), and document how downstream consumers install the wheel (platform notes, supported |
| 73 | + Python versions). |
| 74 | + |
| 75 | +## Alternatives Considered |
| 76 | + |
| 77 | +- **Manual, developer-driven uploads:** Rejected because manual wheel builds are error-prone, |
| 78 | + difficult to reproduce across platforms, and conflict with PyPI’s recommendation to use trusted |
| 79 | + CI publishing. |
| 80 | +- **cibuildwheel-backed workflow:** Considered but rejected for this release; maturin already owns |
| 81 | + the build backend, integrates with PyO3, and provides the required cross-platform coverage with |
| 82 | + less indirection. |
| 83 | +- **Limiting support to Linux and source distributions:** Rejected because product requirements call |
| 84 | + for macOS and Windows parity from day one, and maturin’s cross-platform build support removes the |
| 85 | + main barrier to doing so. |
| 86 | + |
| 87 | +## Consequences |
| 88 | + |
| 89 | +- **Positive:** Reproducible, tested release artefacts; reduced risk of shipping mismatched metadata; |
| 90 | + streamlined release process that matches the official packaging flow; improved supply-chain |
| 91 | + posture through OIDC trusted publishing. |
| 92 | +- **Negative:** Longer CI pipelines (multi-platform builds) and the operational overhead of |
| 93 | + configuring PyPI Trusted Publishing. macOS universal2 builds increase macOS runner usage, and |
| 94 | + cross-compiling for `aarch64` may extend Linux build times. |
| 95 | +- **Risks & Mitigations:** maturin cross-build failures are possible—mitigate by caching Rust |
| 96 | + dependencies and adding smoke tests that catch platform-specific regressions early. If Trusted |
| 97 | + Publishing is unavailable during initial setup, fall back temporarily to a scoped PyPI API token |
| 98 | + stored in GitHub environments while tracking completion of the OIDC configuration. |
0 commit comments