Skip to content

🚀 Add tag-driven release workflow with PyPI Trusted Publishers#13

Merged
dariocazzani merged 1 commit into
mainfrom
feat/release-workflow
May 3, 2026
Merged

🚀 Add tag-driven release workflow with PyPI Trusted Publishers#13
dariocazzani merged 1 commit into
mainfrom
feat/release-workflow

Conversation

@dariocazzani
Copy link
Copy Markdown
Contributor

What does this PR do?

Adds a tag-driven release workflow that publishes devol to PyPI (or TestPyPI for prereleases) via GitHub Actions using Trusted Publishers (OIDC), so no API tokens are stored anywhere. The tag's shape picks the destination, version consistency is enforced against pyproject.toml, and both destinations are gated by GitHub Environments that require manual approval.

Details

  • .github/workflows/release.yml triggers on tags matching v*.*.* (PyPI), v*.*.*rc*, v*.*.*a*, v*.*.*b* (TestPyPI).
  • validate job classifies the tag and fails fast if the tag version does not match pyproject.toml.
  • build job runs uv build and twine check, uploads artifacts for downstream jobs.
  • publish-testpypi / publish-pypi jobs publish via pypa/gh-action-pypi-publish@release/v1 using OIDC; each is attached to its own GitHub Environment for approval gating.
  • github-release job extracts the matching CHANGELOG.md section and publishes a GitHub Release with the sdist + wheel attached (final tags only).
  • devol.__version__ now reads from importlib.metadata.version("devol") with a dev-checkout fallback, making pyproject.toml the single source of truth.
  • CONTRIBUTING.md documents the release flow and the "bump → cut changelog → tag → approve" sequence.

Manual setup required before the first release

These steps can only be done through the PyPI and GitHub web UIs — automation cannot create the trust relationship from scratch. Complete them before pushing the first tag:

  1. TestPyPI pending publisher: https://test.pypi.org/manage/account/publishing/ — add a pending publisher for:
    • Project name: devol
    • Owner: LabStrangeLoop
    • Repository: devol
    • Workflow: release.yml
    • Environment: testpypi
  2. PyPI pending publisher: https://pypi.org/manage/account/publishing/ — same fields, but environment: pypi.
  3. GitHub environments: Settings → Environments → create testpypi and pypi. For each, enable "Required reviewers" and add yourself.

Suggested first release

Dry run against TestPyPI first:

git tag v0.1.0rc1
git push origin v0.1.0rc1

Once the TestPyPI upload looks right, bump to the final tag:

git tag v0.1.0
git push origin v0.1.0

- Add .github/workflows/release.yml triggered by v*.*.* tags.
- Route tag shape to destination: final tags (v0.1.0) publish to
  PyPI; prerelease tags (rc/a/b) publish to TestPyPI, enabling
  dry runs without burning a real version.
- Verify tag matches pyproject.toml version before building.
- Publish via OIDC (pypa/gh-action-pypi-publish). No stored
  credentials. Requires PyPI-side Trusted Publisher + GitHub
  environments (pypi, testpypi) with approval gates.
- Create GitHub Release with built artifacts and the matching
  CHANGELOG section as release notes on final tags only.
- Read devol.__version__ dynamically from package metadata so
  pyproject.toml is the single source of truth.
- Document the release flow in CONTRIBUTING.md.
@dariocazzani dariocazzani merged commit 7a460a5 into main May 3, 2026
6 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