ci: tag-driven release pipeline with TestPyPI RC track#11
Merged
Conversation
Add a Release workflow triggered by tag push. Tag pattern decides the publish target: v0.5.0-rc1, v0.5.0-rc2, ... → TestPyPI (staging / dry-run) v0.5.0 → PyPI + GitHub Release Both publish paths use Trusted Publishing (OIDC) via pypa/gh-action-pypi-publish — no long-lived API tokens. The pypi environment is the recommended place to add a "required reviewers" protection rule so real-PyPI uploads pause for manual approval. Also extend ci.yml with a `uv build` step at the end of the test job. Verifies the package builds on every PR/push so packaging bugs surface before they hit a release tag, not after. First publish from either workflow needs a one-time pending-publisher setup on TestPyPI and PyPI plus the testpypi/pypi GitHub Environments to exist; documented in the PR description.
There was a problem hiding this comment.
Pull request overview
Adds a tag-driven release workflow that builds, tests, and publishes artifacts via PyPI Trusted Publishing (OIDC), with RC tags going to TestPyPI and final tags going to PyPI plus a GitHub Release. It also extends CI to always run a package build so packaging issues are caught before tagging a release.
Changes:
- Introduces
.github/workflows/release.ymlto run tests/build on tag push and publish to TestPyPI for-rctags or to PyPI + GitHub Release for non--rctags. - Uses
pypa/gh-action-pypi-publishwith OIDC (no API token secrets) for both TestPyPI and PyPI publishing. - Appends
uv buildto the main CI test job to validate wheel/sdist packaging on every PR/push.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| .github/workflows/release.yml | New tag-triggered release pipeline with RC → TestPyPI and final → PyPI + GitHub Release. |
| .github/workflows/ci.yml | Adds uv build to CI to detect packaging problems earlier. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Two release-safety fixes: 1. publish-pypi and github-release now gate on `!contains(ref_name, '-')` instead of `!contains(ref_name, '-rc')`. The trigger pattern matches any v[digits].[digits].[digits]* tag, so a `v0.5.0-beta1` tag would previously skip the -rc check and land on real PyPI. Tightening to "no `-` at all" makes any non-rc pre-release tag a no-op (failsafe). 2. Add a "Verify pyproject.toml version matches tag" step at the top of the test job. Reads pyproject's version, compares to the pushed tag (with leading `v` stripped), and fails fast if they don't match. Both sides go through `packaging.version.Version` so PEP 440 equivalences like "0.5.0-rc1" ≡ "0.5.0rc1" are accepted. Catches the "tagged but forgot to bump pyproject" mistake before any build runs.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
Releaseworkflow triggered by tag push. Tag pattern decides the publish target:v0.5.0-rc1,v0.5.0-rc2, ...v0.5.0Both publish paths use Trusted Publishing (OIDC) via
pypa/gh-action-pypi-publish— no long-lived API tokens stored as secrets.Also extends
ci.ymlwith auv buildstep at the end of the test job. Verifies the package builds on every PR/push so packaging bugs surface before they reach a release tag.Release flow once this lands
Each RC iteration burns a fresh number — PyPI/TestPyPI refuse re-uploads of the same version. Iterate
rc1 → rc2 → rc3 → 0.5.0as needed.Test plan
uv buildruns clean locally (producesopenarmature-0.4.0.tar.gz+ wheel).ci.ymltest job still passes; newuv buildstep appended at the end.Notes
v[0-9]*.[0-9]*.[0-9]*— matches bothv0.5.0andv0.5.0-rc1(the trailing-rc1is part of the final*). Job-levelif: contains(github.ref_name, '-rc')splits the two paths.