Skip to content

Commit 79d0d6d

Browse files
committed
ci: keep npm publish and GitHub releases coupled, self-heal release gaps
GitHub releases are created only by the changesets/action step, and that step has not completed cleanly on any release-triggering run since mid-June (last release: @tanstack/ai-react@0.15.5 on 2026-06-15; npm is now at 0.15.12). The "Version Packages" merge runs (#773, #778, #787, #792, #808, #813) passed the test gate and then FAILED at the "Run Changesets" step: CI ran `changeset publish` and npm advanced, but the step died before the tag-push / GitHub-release phase, so no tags (0.15.6-0.15.12 don't exist) and no releases were created. More recent runs (#814, #825) now fail even earlier, at the test gate (test:kiira), so the changesets step is never reached. Either way npm and GitHub drift apart. (The exact in-step error is no longer recoverable - those runs' logs have expired.) Changes: - Split into a `test` gate job and a `release` job (needs: test) so a flaky run blocks BOTH npm and GitHub releases together, never one without the other. - Add a self-heal step that enforces "published to npm => GitHub release exists": for any package version on npm without a release it creates the tag + release from the CHANGELOG. Runs even when the changesets step fails mid-way, so gaps self-heal on the next release run - directly covering the failure mode above. - Set GITHUB_TOKEN explicitly on the changesets step and tighten permissions (top-level contents:read; write scoped to the release job).
1 parent f3144a6 commit 79d0d6d

1 file changed

Lines changed: 58 additions & 6 deletions

File tree

.github/workflows/release.yml

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,41 @@ env:
1212
NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}
1313

1414
permissions:
15-
contents: write
16-
id-token: write
17-
pull-requests: write
15+
contents: read
1816

1917
jobs:
20-
release:
21-
name: Release
18+
test:
19+
name: Test
2220
if: github.repository_owner == 'TanStack'
2321
runs-on: ubuntu-latest
2422
steps:
2523
- name: Checkout
2624
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
2725
with:
2826
fetch-depth: 0
29-
persist-credentials: true # release job pushes version/docs changes
27+
persist-credentials: false
3028
- name: Setup Tools
3129
uses: TanStack/config/.github/setup@190f659075ff0845850e330883eb26d7ffd0671f # main
3230
- name: Run Tests
3331
run: pnpm run test:ci
32+
33+
release:
34+
name: Release
35+
needs: test
36+
if: github.repository_owner == 'TanStack'
37+
runs-on: ubuntu-latest
38+
permissions:
39+
contents: write
40+
id-token: write
41+
pull-requests: write
42+
steps:
43+
- name: Checkout
44+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
45+
with:
46+
fetch-depth: 0
47+
persist-credentials: true
48+
- name: Setup Tools
49+
uses: TanStack/config/.github/setup@190f659075ff0845850e330883eb26d7ffd0671f # main
3450
- name: Run Changesets (version or publish)
3551
id: changesets
3652
uses: changesets/action@6a0a831ff30acef54f2c6aa1cbbc1096b066edaf # v1.7.0
@@ -39,6 +55,42 @@ jobs:
3955
publish: pnpm run changeset:publish
4056
commit: 'ci: Version Packages'
4157
title: 'ci: Version Packages'
58+
env:
59+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
60+
- name: Ensure GitHub releases for published versions
61+
if: ${{ !cancelled() && (steps.changesets.outputs.published == 'true' || steps.changesets.outcome == 'failure') }}
62+
env:
63+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
64+
run: |
65+
set -euo pipefail
66+
for pkg in packages/*/package.json; do
67+
[ "$(jq -r '.private // false' "$pkg")" = "true" ] && continue
68+
name=$(jq -r '.name' "$pkg")
69+
version=$(jq -r '.version' "$pkg")
70+
tag="${name}@${version}"
71+
72+
if gh release view "$tag" >/dev/null 2>&1; then
73+
continue
74+
fi
75+
if ! npm view "${name}@${version}" version >/dev/null 2>&1; then
76+
continue
77+
fi
78+
79+
echo "Backfilling GitHub release for $tag"
80+
if ! git rev-parse -q --verify "refs/tags/${tag}" >/dev/null; then
81+
git tag "$tag" "$GITHUB_SHA"
82+
git push origin "refs/tags/${tag}"
83+
fi
84+
85+
notes=$(mktemp)
86+
changelog="$(dirname "$pkg")/CHANGELOG.md"
87+
if [ -f "$changelog" ]; then
88+
awk '/^## /{n++} n==1{print} n==2{exit}' "$changelog" > "$notes" || true
89+
fi
90+
[ -s "$notes" ] || echo "Release ${tag}" > "$notes"
91+
gh release create "$tag" --title "$tag" --notes-file "$notes"
92+
rm -f "$notes"
93+
done
4294
- name: Generate Docs
4395
if: steps.changesets.outputs.published == 'true'
4496
run: pnpm generate-docs

0 commit comments

Comments
 (0)