Skip to content

Phase 6f: add publish-python to release.yml (PyPI via OIDC) - #25

Merged
joaoh82 merged 1 commit into
mainfrom
feat/publish-python
Apr 24, 2026
Merged

joaoh82 merged 1 commit into
mainfrom
feat/publish-python

Conversation

@joaoh82

@joaoh82 joaoh82 commented Apr 24, 2026

Copy link
Copy Markdown
Owner

Summary

Adds three new jobs to release.yml that build + publish sqlrite to PyPI on every release, authenticating via OIDC trusted publishing (no API token).

Job Cells Role
build-python-wheels 4 (Linux x86_64, Linux aarch64, macOS aarch64, Windows x86_64) Build abi3-py38 wheels
build-python-sdist 1 Build source distribution
publish-python 1 Aggregate all wheels + sdist, atomic PyPI upload, cut sqlrite-py-v<V> GitHub Release

Why three jobs, not one matrix with inline upload

If each matrix cell published its own wheel directly to PyPI, a mid-matrix failure would leave PyPI with a partial wave (3 of 4 platforms). The build/publish split lets us fail cleanly — nothing hits PyPI until every platform's wheel is in hand.

Matrix choices

Mirrors publish-ffi + publish-desktop so there's one consistent OS/arch pattern across all publish jobs:

  • Linux x86_64 + aarch64manylinux: auto runs the build inside a manylinux2014 container, so the wheel's glibc is baked old enough to run on any distro shipped since ~2014.
  • macOS aarch64 — Apple Silicon only (universal is still a Phase 6e-style follow-up across all our macOS products).
  • Windows x86_64 — standard.

abi3-py38 means one wheel per platform covers every CPython ≥ 3.8 — no per-Python-version matrix axis. The sdist catches anyone on uncommon platforms (FreeBSD, alpine aarch64, etc.) — pip install sqlrite falls back to source build using their local Rust toolchain.

Authentication

OIDC trusted publishing via pypa/gh-action-pypi-publish@release/v1. The publish-python job has permissions: id-token: write and lives in the release GitHub environment (same required-reviewer gate as publish-crate). PyPI-side config is one-time web-UI registration of joaoh82/rust_sqliterelease.ymlrelease environment as a trusted publisher for the sqlrite project (documented in docs/release-secrets.md).

Wiring

  • tag-all → now pushes sqlrite-py-v<V>
  • finalize.needs → extended with publish-python
  • Umbrella release body → 🐍 Python entry added with PyPI link

Name availability

Unlike sqlrite on crates.io (taken by an unrelated project, forcing the sqlrite-engine rename in PR #17), the name sqlrite is available on PyPI — verified via curl -o /dev/null -w "%{http_code}" https://pypi.org/pypi/sqlrite/json returning 404. pyproject.toml already has name = "sqlrite", no rename needed.

Test plan

  • cargo check -p sqlrite-python — clean
  • python3 -c "import yaml; yaml.safe_load(open('.github/workflows/release.yml'))" — YAML parses
  • PyPI name availability verified (404 on /pypi/sqlrite/json)
  • CI on this PR (existing python-sdk matrix jobs re-exercise the crate)
  • After merge: ONE-TIME PYPI SETUP REQUIRED — log into pypi.org, reserve the sqlrite project name, configure trusted publisher pointing at this repo / release.yml / environment release. Documented in docs/release-secrets.md §2.
  • After that: dispatch release-pr.yml at 0.1.4 → review → merge → approve release env → verify sqlrite 0.1.4 on PyPI + sqlrite-py-v0.1.4 GitHub Release.

Not in scope (Phase 6g–6i follow-ups)

Node.js (npm), WASM (npm), Go (git tag + FFI tarball attachment). Each lands as its own PR.

🤖 Generated with Claude Code

Three new jobs wired into the release pipeline alongside the
existing publish-crate / publish-ffi / publish-desktop chain:

  - build-python-wheels  (matrix, 4 cells)
  - build-python-sdist   (single)
  - publish-python       (aggregate + upload + GitHub Release)

**Why three jobs instead of one matrix with inline upload:**
PyPI expects wheels as a single batch — if each matrix cell
published its own wheel independently, a mid-matrix failure
would leave PyPI with a partial wave of a release, which is
worse than the whole thing failing cleanly. The build/publish
split aggregates every wheel + the sdist into one `dist/`
directory, then uploads atomically via
`pypa/gh-action-pypi-publish`.

**Wheel matrix** mirrors publish-ffi + publish-desktop:

  ubuntu-latest     → linux x86_64    (manylinux2014)
  ubuntu-24.04-arm  → linux aarch64   (manylinux2014)
  macos-latest      → macOS aarch64   (Apple Silicon)
  windows-latest    → windows x86_64

abi3-py38 means one wheel per platform works on every CPython
≥ 3.8 — no per-Python-version axis. An sdist is built alongside
for platforms not covered by the wheel matrix (FreeBSD,
alpine aarch64, etc.); `pip install` falls back to a source
build via the user's local Rust toolchain.

**Authentication via PyPI trusted publishing** (OIDC). Zero
long-lived tokens. The publish-python job has `permissions:
id-token: write` and lives in the `release` GitHub environment
(required-reviewer gate inherited from publish-crate). PyPI-side
config is a one-time web-UI registration documented in
docs/release-secrets.md.

**Wiring:**

  - tag-all   → pushes sqlrite-py-v<V>
  - finalize  → needs publish-python
  - umbrella release body → includes 🐍 Python link pointing
    to the per-product release + PyPI page

Verified locally: `cargo check -p sqlrite-python` clean,
release.yml parses as valid YAML, pyproject.toml already has
name = "sqlrite" (available on PyPI per pypi.org API, no
rename dance like crates.io needed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@joaoh82
joaoh82 merged commit c2e7c48 into main Apr 24, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant