From b6d9abf8444d2f02d62bc0cb96e19111a672fba1 Mon Sep 17 00:00:00 2001 From: bitWarrior Date: Tue, 1 Sep 2026 13:50:48 -0700 Subject: [PATCH] Add a manual trigger to the release workflow Publishing the v1.2.0 GitHub Release emitted a ReleaseEvent with action=published, but no run was dispatched for release.yml -- the workflow is active and Actions is enabled, so the event simply did not start a run. That leaves no way to publish without recreating the Release, and no way to retry a failed publish at all. Add workflow_dispatch with a required tag input. Both entry points feed the same tag/version guard, so a manual run cannot publish an artifact whose _version.py disagrees with the tag it claims to be. Also pin the checkout to the tag being released rather than letting it default to the branch, which matters now that a run can start from a dispatch. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_0114gUUe4CxYr8W8oC95ffmD --- .github/workflows/release.yml | 12 +++++++++++- docs/RELEASING.md | 10 ++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 38a0bfd..1312a24 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -3,6 +3,14 @@ name: Release on: release: types: [published] + # A release event does not always dispatch a run, and a failed publish should + # not require recreating the GitHub Release. Both paths use the same guard. + workflow_dispatch: + inputs: + tag: + description: "Tag to publish, e.g. v1.2.0 (must match src/codesnake/_version.py)" + required: true + type: string # Deny by default; each job grants only what it needs. permissions: {} @@ -15,6 +23,8 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: + # Build the tag being released, never whatever the default branch is at. + ref: ${{ github.event.release.tag_name || inputs.tag }} persist-credentials: false - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: @@ -27,7 +37,7 @@ jobs: - name: Verify the built version matches the release tag env: - TAG: ${{ github.event.release.tag_name }} + TAG: ${{ github.event.release.tag_name || inputs.tag }} run: | BUILT=$(python -c "import sys; sys.path.insert(0, 'src'); from codesnake._version import __version__; print(__version__)") echo "tag=$TAG built=$BUILT" diff --git a/docs/RELEASING.md b/docs/RELEASING.md index ba5aad3..5dca413 100644 --- a/docs/RELEASING.md +++ b/docs/RELEASING.md @@ -33,6 +33,16 @@ Consider claiming the name with a release to [TestPyPI](https://test.pypi.org) f 4. Publish a GitHub Release on that tag with notes. Publishing is what starts the workflow. 5. Approve the `pypi` deployment when GitHub asks. +If the release event does not start a run, or a publish failed and you want to retry +without recreating the Release, dispatch it manually with the same tag: + +```bash +gh workflow run release.yml -f tag=v1.3.0 +``` + +Both paths run the identical build, the identical tag/version guard, and the same +environment approval. + The build job refuses to publish when the release tag and `_version.py` disagree, so a `v1.3.0` tag cannot ship a `1.2.0` artifact. ## What protects the release path