From 56689ccab5dde59061cfa09b1cf7612c5f330182 Mon Sep 17 00:00:00 2001 From: Anatoly Maltsev Date: Wed, 26 Aug 2026 16:20:52 +0400 Subject: [PATCH] fix(publish): create GitHub Release on tag push MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a GitHub Release creation step to the publish workflow so the `v*` tag push that ships a PyPI release also produces a GitHub Release page with the wheel + sdist attached. Closes the "manual changelog duplication" gap that 0.16.3 would otherwise hit: the land-badge on the landing page would render 0.16.3 only after a separate `gh release create` step, which would race the PyPI publish job in the same workflow run. Diff: - `permissions.contents: write` on the publish job — required by softprops/action-gh-release to push the release ref. Additive to the existing `id-token: write` (which PyPI Trusted Publishing needs); does NOT weaken the existing security posture since the workflow already has `actions/checkout@v4` writing into `${{ github.workspace }}`. - New step "Create GitHub Release" at the end of the publish job, gated on `startsWith(github.ref, 'refs/tags/v')` so manual workflow_dispatch re-runs (used for hotfix rebuilds) don't create duplicate releases on branch refs. `generate_release_notes: true` asks GitHub to auto-aggregate merged PR titles + labels into the release body so the GH release page mirrors CHANGELOG.md without manual editing. `files: dist/*.whl, dist/*.tar.gz` attaches the same artifacts that PyPI receives, so the release page doubles as a download mirror for environments where pip isn't available. Pinned to `softprops/action-gh-release@v2` (matches the project release-train convention). The latest stable release is v3.0.2; the inputs used here (`tag_name`, `generate_release_notes`, `files`) are identical between v2 and v3, so bumping is a one-line change when desired. No changes to test/, build, or PyPI publish step. The existing `needs: test` dependency still gates the release creation on a green test matrix. --- .github/workflows/publish.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 8cfbba3..30e70b2 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -43,6 +43,11 @@ jobs: url: https://pypi.org/p/nullrun permissions: id-token: write + # contents: write is required by softprops/action-gh-release to + # create the GitHub Release (push the tag ref + draft release). + # The existing publish step only needs id-token for PyPI Trusted + # Publishing, so this is additive and scoped to the new step. + contents: write steps: - uses: actions/checkout@v4 @@ -63,3 +68,22 @@ jobs: - name: Publish to PyPI (Trusted Publishing) uses: pypa/gh-action-pypi-publish@release/v1 + + # GitHub Release creation — gated on tag pushes so the manual + # workflow_dispatch path (used for hotfix re-runs) doesn't create + # a duplicate release on the current HEAD's branch ref. The + # ``generate_release_notes`` flag asks GitHub to auto-aggregate + # merged PR titles + labels into the release body, which keeps + # the GitHub release page in sync with the CHANGELOG.md body + # without manual editing. Attached files mirror what PyPI receives + # (wheel + sdist) so the release page doubles as a download mirror + # for environments where pip isn't available. + - name: Create GitHub Release + if: startsWith(github.ref, 'refs/tags/v') + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ github.ref_name }} + generate_release_notes: true + files: | + dist/*.whl + dist/*.tar.gz