Skip to content

Commit ef8572a

Browse files
josiahsrcclaude
andcommitted
Fix prod desktop release failing to create its tag
GITHUB_TOKEN cannot create a ref to a commit whose workflow files differ from the current branch head (GitHub requires workflows:write, which GITHUB_TOKEN can never hold). Prod promotions tag the older dev-release commit, so the desktop-v0.0.651 promotion 403'd after the Windows updater workflow fix landed between that dev release and the promotion. - Tolerate an existing tag that already points at the target commit so a manually created tag (or a retried promotion) can proceed. - Create the tag with RELEASE_TAG_TOKEN when set, falling back to GITHUB_TOKEN for the same-commit (dev/enterprise) case. - Add workflow_dispatch to the release orchestrator with per-component toggles — failed releases previously could not be re-triggered, since reruns reuse the broken workflow snapshot and a fix-only push matches no path filters. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 313af16 commit ef8572a

2 files changed

Lines changed: 48 additions & 8 deletions

File tree

‎.github/workflows/_release-desktop-impl.yml‎

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,9 +165,14 @@ jobs:
165165
DEV_TAG_NAME="${TARGET_DEV_TAG}"
166166
fi
167167
168-
if git rev-parse -q --verify "refs/tags/${TAG_NAME}" >/dev/null; then
169-
echo "Tag ${TAG_NAME} already exists. Aborting." >&2
170-
exit 1
168+
TAG_EXISTS="false"
169+
if EXISTING_SHA="$(git rev-parse -q --verify "refs/tags/${TAG_NAME}^{commit}")"; then
170+
if [[ "${EXISTING_SHA}" != "${COMMIT_SHA}" ]]; then
171+
echo "Tag ${TAG_NAME} already exists at ${EXISTING_SHA}, expected ${COMMIT_SHA}. Aborting." >&2
172+
exit 1
173+
fi
174+
echo "Tag ${TAG_NAME} already exists at the target commit; reusing it."
175+
TAG_EXISTS="true"
171176
fi
172177
173178
VERSION_PATH="desktop/${RELEASE_ENV}/${VERSION}"
@@ -211,6 +216,7 @@ jobs:
211216
echo "version_path=${VERSION_PATH}"
212217
echo "channel_release_tag=${CHANNEL_RELEASE_TAG}"
213218
echo "release_flavor=${RELEASE_FLAVOR}"
219+
echo "tag_exists=${TAG_EXISTS}"
214220
} >> "$GITHUB_OUTPUT"
215221
216222
- name: Read release notes
@@ -226,12 +232,19 @@ jobs:
226232
body="$(cat "${notes_file}")"
227233
printf 'release_body<<EOF\n%s\nEOF\n' "$body" >> "$GITHUB_OUTPUT"
228234
235+
# GITHUB_TOKEN cannot create a ref to a commit whose workflow files differ
236+
# from the current branch head (GitHub demands workflows:write, which
237+
# GITHUB_TOKEN can never hold). Prod promotions tag the older dev commit,
238+
# so they hit this whenever a workflow changed since that dev release —
239+
# RELEASE_TAG_TOKEN (PAT with contents+workflows write) covers that case.
229240
- name: Create release tag
241+
if: steps.meta.outputs.tag_exists != 'true'
230242
uses: actions/github-script@v7
231243
env:
232244
TAG_NAME: ${{ steps.meta.outputs.tag_name }}
233245
TARGET_SHA: ${{ steps.meta.outputs.commit_sha }}
234246
with:
247+
github-token: ${{ secrets.RELEASE_TAG_TOKEN || secrets.GITHUB_TOKEN }}
235248
script: |
236249
const tagName = process.env.TAG_NAME;
237250
const targetSha = process.env.TARGET_SHA;

‎.github/workflows/release.yml‎

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,36 @@ name: Release (auto)
99
# Promotion: fast-forward merge `main` into `prod` or `enterprise` → this
1010
# workflow runs on that branch and only the components that changed since
1111
# the last release on that branch ship.
12+
#
13+
# Manual dispatch releases the selected components on the chosen branch —
14+
# the recovery path when a push-triggered release fails, since reruns use
15+
# the original (broken) workflow snapshot.
1216

1317
on:
1418
push:
1519
branches: [main, prod, enterprise]
20+
workflow_dispatch:
21+
inputs:
22+
desktop:
23+
description: "Release desktop"
24+
type: boolean
25+
default: false
26+
cli:
27+
description: "Release CLI"
28+
type: boolean
29+
default: false
30+
docs:
31+
description: "Release docs"
32+
type: boolean
33+
default: false
34+
enterprise_admin:
35+
description: "Release enterprise admin"
36+
type: boolean
37+
default: false
38+
enterprise_gateway:
39+
description: "Release enterprise gateway"
40+
type: boolean
41+
default: false
1642

1743
concurrency:
1844
group: release-${{ github.ref_name }}-orchestrator
@@ -30,11 +56,11 @@ jobs:
3056
runs-on: ubuntu-latest
3157
outputs:
3258
channel: ${{ steps.env.outputs.channel }}
33-
cli: ${{ steps.filter.outputs.cli }}
34-
desktop: ${{ steps.filter.outputs.desktop }}
35-
docs: ${{ steps.filter.outputs.docs }}
36-
enterprise_admin: ${{ steps.filter.outputs.enterprise_admin }}
37-
enterprise_gateway: ${{ steps.filter.outputs.enterprise_gateway }}
59+
cli: ${{ github.event_name == 'workflow_dispatch' && inputs.cli || steps.filter.outputs.cli }}
60+
desktop: ${{ github.event_name == 'workflow_dispatch' && inputs.desktop || steps.filter.outputs.desktop }}
61+
docs: ${{ github.event_name == 'workflow_dispatch' && inputs.docs || steps.filter.outputs.docs }}
62+
enterprise_admin: ${{ github.event_name == 'workflow_dispatch' && inputs.enterprise_admin || steps.filter.outputs.enterprise_admin }}
63+
enterprise_gateway: ${{ github.event_name == 'workflow_dispatch' && inputs.enterprise_gateway || steps.filter.outputs.enterprise_gateway }}
3864
steps:
3965
- uses: actions/checkout@v4
4066

@@ -48,6 +74,7 @@ jobs:
4874
esac
4975
5076
- uses: dorny/paths-filter@v3
77+
if: github.event_name == 'push'
5178
id: filter
5279
with:
5380
base: ${{ github.event.before }}

0 commit comments

Comments
 (0)