From 90c09a60b963a975701902ad3b588b9b215c5aa4 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 5 Oct 2026 10:03:43 +0100 Subject: [PATCH] Publish to PyPI from the release workflow using trusted publishing (#17) Co-Authored-By: Claude Sonnet 5.5 Claude-Session: https://claude.ai/code/session_01Cs1BoS2rKycdxjt8tTMk9h --- .github/workflows/release.yml | 43 +++++++++++++++++++++++++++++++---- docs/releasing.md | 19 ++++++++++------ 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 05d9cf1..fbc9af0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,9 @@ name: Release +# Pushing a tag such as v0.2.0 builds the package, creates the GitHub release and publishes to PyPI. +# Publishing uses PyPI trusted publishing (no token): on pypi.org add a publisher for project +# `ctxlogkit` with owner `markbac`, repository `py-logkit`, workflow `release.yml`, environment `pypi`. + on: push: tags: ["v*"] @@ -8,11 +12,9 @@ permissions: contents: read jobs: - release: - name: Build and create the GitHub release + build: + name: Build the package runs-on: ubuntu-latest - permissions: - contents: write steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 @@ -28,7 +30,40 @@ jobs: - run: python -m pip install build twine - run: python -m build - run: twine check dist/* + - uses: actions/upload-artifact@v4 + with: + name: dist + path: dist/ + + release: + name: Create the GitHub release + needs: build + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: actions/checkout@v4 + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist/ - name: Create the GitHub release env: GH_TOKEN: ${{ github.token }} run: gh release create "$GITHUB_REF_NAME" dist/* --generate-notes --title "$GITHUB_REF_NAME" + + publish: + name: Publish to PyPI + needs: build + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/ctxlogkit + permissions: + id-token: write + steps: + - uses: actions/download-artifact@v4 + with: + name: dist + path: dist/ + - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/docs/releasing.md b/docs/releasing.md index 452c661..5159991 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -17,13 +17,18 @@ Releases follow [Semantic Versioning](https://semver.org/). The version lives in ``` Pushing a `v*` tag runs `.github/workflows/release.yml`. It checks that the tag matches -`__version__`, builds the sdist and wheel, runs `twine check`, and attaches both to a GitHub release -whose notes are generated from the merged pull requests. +`__version__`, builds the sdist and wheel, runs `twine check`, attaches both to a GitHub release +whose notes are generated from the merged pull requests, and publishes them to PyPI. ## Publishing to PyPI -The workflow does not publish to PyPI yet. The name `ctxlogkit` was checked and was free when the project -was renamed from `pylogkit` (issue #44). To publish, reserve it on PyPI and then -add a publish job that uses -[trusted publishing](https://docs.pypi.org/trusted-publishers/) with the `id-token: write` -permission, so that no API token is stored in the repository. +Publishing uses [trusted publishing](https://docs.pypi.org/trusted-publishers/), so no API token is +stored in the repository. Set it up once, before the first release: + +1. On pypi.org, go to *Your projects* then *Publishing* and add a pending publisher for the project + name `ctxlogkit`. A pending publisher reserves the name and creates the project on the first upload. +2. Use owner `markbac`, repository `py-logkit`, workflow `release.yml` and environment `pypi`. +3. In the repository settings, create an environment called `pypi`. Adding a required reviewer there + makes each publish wait for an approval. + +The name `ctxlogkit` was checked and was free when the project was renamed from `pylogkit` (issue #44).