1- name : Release
1+ name : Publish npm
22
33on :
44 workflow_dispatch :
5- push :
6- branches : [main]
5+ inputs :
6+ channel :
7+ description : npm channel to publish
8+ required : true
9+ type : choice
10+ options :
11+ - beta
12+ - stable
13+ confirm :
14+ description : Type PUBLISH to confirm
15+ required : true
16+ type : string
717
818concurrency :
9- group : ${{ github.workflow }}-${{ github.ref }}
1019 # Publishing three packages is not atomic. Never cancel a run after the first
11- # package may already have reached npm; the publish script is also idempotent
12- # so a failed run can safely be retried.
20+ # package may already have reached npm; exact versions are safe to retry.
21+ group : npm-publish
1322 cancel-in-progress : false
1423
1524jobs :
16- release :
17- # Missing repository variables resolve to an empty string, so a newly
18- # created repository cannot publish until maintainers explicitly opt in.
19- if : vars.NPM_RELEASE_ENABLED == 'true'
25+ publish :
26+ if : vars.NPM_RELEASE_ENABLED == 'true' && inputs.confirm == 'PUBLISH'
2027 runs-on : ubuntu-latest
28+ environment : npm-release
2129 permissions :
2230 contents : write
2331 id-token : write
24- pull-requests : write
2532 steps :
2633 - uses : actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
2734 with :
@@ -43,22 +50,48 @@ jobs:
4350 - name : Install dependencies
4451 run : bun install --frozen-lockfile
4552
53+ - name : Validate channel, branch, and package versions
54+ id : release
55+ run : >-
56+ bun run scripts/release/channel.ts validate
57+ --channel "${{ inputs.channel }}"
58+ --ref "${{ github.ref_name }}"
59+ --output "$GITHUB_OUTPUT"
60+
4661 - name : Verify release
47- env :
48- BASE : ${{ github.event.before }}
4962 run : bun run verify:release
5063
51- - name : Create Release PR or Publish
52- uses : changesets/action@a45c4d594aa4e2c509dc14a9f2b3b67ba3780d0d # v1.9.0
53- with :
54- version : bun run release:version
55- publish : bun run release:publish
56- commit : " chore: release packages"
57- title : " chore: release packages"
64+ - name : Publish packages with npm Trusted Publishing
5865 env :
59- GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
60- # Bootstrap only: set this secret for the first publication, then remove
61- # and revoke it after npm Trusted Publishers are configured. With the
62- # secret absent, npm authenticates through OIDC trusted publishing.
63- NODE_AUTH_TOKEN : ${{ secrets.NPM_TOKEN }}
6466 NPM_CONFIG_PROVENANCE : " true"
67+ run : bun run release:publish
68+
69+ - name : Create immutable Git tag
70+ env :
71+ VERSION : ${{ steps.release.outputs.version }}
72+ run : |
73+ tag="v${VERSION}"
74+ if git rev-parse --verify --quiet "refs/tags/${tag}"; then
75+ test "$(git rev-list -n 1 "${tag}")" = "$GITHUB_SHA" || {
76+ echo "::error::${tag} already points to another commit"
77+ exit 1
78+ }
79+ else
80+ git tag --annotate "${tag}" --message "${tag}"
81+ git push origin "${tag}"
82+ fi
83+
84+ - name : Create GitHub Release
85+ env :
86+ GH_TOKEN : ${{ github.token }}
87+ VERSION : ${{ steps.release.outputs.version }}
88+ CHANNEL : ${{ steps.release.outputs.channel }}
89+ run : |
90+ tag="v${VERSION}"
91+ if gh release view "${tag}" >/dev/null 2>&1; then
92+ echo "GitHub Release ${tag} already exists; nothing to do."
93+ elif test "${CHANNEL}" = beta; then
94+ gh release create "${tag}" --verify-tag --generate-notes --prerelease --title "${tag}"
95+ else
96+ gh release create "${tag}" --verify-tag --generate-notes --title "${tag}"
97+ fi
0 commit comments