Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ jobs:
runs-on: ubuntu-latest
# Never react to our own release commit.
if: "!contains(github.event.head_commit.message, '[skip ci]')"
env:
# A tag pushed with GITHUB_TOKEN does NOT trigger other workflows, by
# design, to prevent recursion. With a PAT in RELEASE_TOKEN the tag
# triggers Deploy natively; without one we start Deploy explicitly.
HAS_PAT: ${{ secrets.RELEASE_TOKEN != '' }}
steps:
- uses: actions/checkout@v7
with:
Expand Down Expand Up @@ -91,15 +86,21 @@ jobs:
--notes "${{ steps.cut.outputs.notes }}" \
|| echo "::notice::Release already exists."

# Only needed while no PAT is configured; with one, the tag push above
# has already started Deploy.
- name: Start Deploy (no PAT configured)
if: steps.cut.outputs.released == 'true' && env.HAS_PAT != 'true'
# Always dispatch, unconditionally.
#
# This previously only ran when no PAT was configured, on the assumption
# that a PAT-pushed tag would trigger Deploy natively via `on: push:
# tags`. With a PAT present that assumption silently took over and no
# deploy ever happened: the tag was pushed, Release reported success, and
# Deploy had zero runs. Dispatching every time removes the dependency on
# how GitHub attributes the push. Deploy is idempotent -- it builds and
# uploads the same tag -- so a duplicate run is harmless, whereas a
# missed one is invisible.
- name: Start Deploy
if: steps.cut.outputs.released == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "::notice::No RELEASE_TOKEN set, so the tag cannot trigger Deploy. Dispatching it directly."
gh workflow run deploy.yml --ref main -f tag="${{ steps.cut.outputs.tag }}"
run: gh workflow run deploy.yml --ref main -f tag="${{ steps.cut.outputs.tag }}"

- name: Summary
run: |
Expand Down
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

## [Unreleased]

Nothing yet.
### Fixed
- Releases tagged correctly but never deployed. The Release workflow only
started Deploy when no `RELEASE_TOKEN` was configured, assuming a PAT-pushed
tag would trigger it natively. With a PAT present that assumption took over
silently: the tag was pushed, Release reported success, and Deploy had zero
runs. Release now always starts Deploy explicitly.

## [0.2.1] — 2026-09-24

Expand Down
6 changes: 6 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ Merging to `main` then does the rest, automatically:
An empty `[Unreleased]` releases nothing, so a docs-only or refactor merge ships
nothing. That is deliberate: merging and releasing are separate decisions.

Deploy is always started explicitly by Release, never left to the tag event.
A tag pushed by automation may or may not trigger `on: push: tags` depending on
which credential pushed it, and a deploy that silently does not happen looks
exactly like a deploy that succeeded. Dispatching every time is deterministic,
and Deploy is idempotent so a duplicate run is harmless.

Two notes for anyone editing the workflows:

- `### Removed` is deliberately a *patch*, not a major. Inferring a major bump
Expand Down
Loading