44 workflow_dispatch :
55 inputs :
66 version :
7- description : " Version to release (vX.Y.Z format)"
7+ description : " Version to tag and release (vX.Y.Z or vX.Y.Z-prerelease format)"
88 required : true
99 default : " v1.1.0"
10- prerelease :
11- description : " Is this a pre-release?"
12- type : boolean
13- default : false
1410 push :
1511 tags :
1612 - " v*"
1915permissions : read-all
2016
2117jobs :
18+ create-release-tag :
19+ name : Create Release Tag
20+ if : github.event_name == 'workflow_dispatch'
21+ runs-on : ubuntu-26.04
22+ permissions :
23+ contents : read
24+ steps :
25+ - name : Harden Runner
26+ uses : step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
27+ with :
28+ egress-policy : audit
29+
30+ - name : Generate GitHub App token
31+ id : app-token
32+ uses : actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
33+ with :
34+ app-id : ${{ vars.GH_APP_ID }}
35+ private-key : ${{ secrets.GH_APP_PRIVATE_KEY }}
36+
37+ - name : Checkout main
38+ uses : actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
39+ with :
40+ fetch-depth : 0
41+ ref : main
42+ token : ${{ steps.app-token.outputs.token }}
43+ persist-credentials : true
44+
45+ - name : Setup Node.js
46+ uses : actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
47+ with :
48+ node-version : " 26"
49+
50+ - name : Validate version and create tag
51+ env :
52+ RELEASE_VERSION : ${{ inputs.version }}
53+ run : |
54+ if [[ ! "$RELEASE_VERSION" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z][0-9A-Za-z.-]*)?$ ]]; then
55+ echo "::error::Version must use vX.Y.Z or vX.Y.Z-prerelease format."
56+ exit 1
57+ fi
58+ if git ls-remote --exit-code --tags origin "refs/tags/$RELEASE_VERSION" >/dev/null 2>&1; then
59+ echo "::error::Tag $RELEASE_VERSION already exists."
60+ exit 1
61+ fi
62+
63+ npm version "${RELEASE_VERSION#v}" --no-git-tag-version
64+ git config user.name "github-actions[bot]"
65+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
66+ git add package.json package-lock.json
67+ git commit -m "chore(release): bump version to $RELEASE_VERSION"
68+ git tag --annotate "$RELEASE_VERSION" --message "$RELEASE_VERSION"
69+ git push --atomic origin HEAD:main "refs/tags/$RELEASE_VERSION"
70+
2271 prepare :
2372 name : Prepare Release
73+ if : github.event_name == 'push'
2474 runs-on : ubuntu-26.04
25- # Only prepare job needs write permissions for commit and tagging
2675 permissions :
27- contents : write # Required for git auto-commit
76+ contents : read
2877 outputs :
2978 version : ${{ steps.get-version.outputs.version }}
30- is_prerelease : ${{ github.event.inputs.prerelease || 'false' }}
79+ is_prerelease : ${{ contains(steps.get-version.outputs.version, '-') }}
3180 steps :
3281 - name : Harden Runner
3382 uses : step-security/harden-runner@bf7454d06d71f1098171f2acdf0cd4708d7b5920 # v2.20.0
@@ -51,11 +100,7 @@ jobs:
51100 - name : Get version
52101 id : get-version
53102 run : |
54- if [[ "${{ github.event_name }}" == "push" ]]; then
55- VERSION=${GITHUB_REF#refs/tags/}
56- else
57- VERSION=${{ github.event.inputs.version }}
58- fi
103+ VERSION=${GITHUB_REF#refs/tags/}
59104 echo "version=${VERSION}" >> $GITHUB_OUTPUT
60105 echo "Version: ${VERSION}"
61106
@@ -93,20 +138,6 @@ jobs:
93138 - name : Install dependencies
94139 run : npm ci
95140
96- - name : Set Version for release
97- if : github.event_name == 'workflow_dispatch'
98- run : |
99- PLAIN_VERSION="${{ github.event.inputs.version }}"
100- # Remove 'v' prefix if present
101- PLAIN_VERSION="${PLAIN_VERSION#v}"
102- npm version $PLAIN_VERSION --no-git-tag-version
103-
104- - uses : stefanzweifel/git-auto-commit-action@4a55954c782fc1ea30b9056cd3e7a2b40ca8887d # v7.2.0
105- if : github.event_name == 'workflow_dispatch'
106- with :
107- commit_message : " chore(release): bump version to ${{ github.event.inputs.version }}"
108- tagging_message : " ${{ github.event.inputs.version }}"
109-
110141 - name : Check licenses
111142 run : npm run test:licenses
112143
@@ -203,7 +234,7 @@ jobs:
203234 fetch-depth : 0
204235 token : ${{ steps.app-token.outputs.token }}
205236 persist-credentials : true
206- ref : ${{ github.event_name == 'push' && github.ref || github.event_name == 'workflow_dispatch' && github.event.inputs. version || '' }}
237+ ref : ${{ needs.prepare.outputs. version }}
207238
208239 - name : Setup Node.js
209240 uses : actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
@@ -316,7 +347,7 @@ jobs:
316347 fetch-depth : 0
317348 token : ${{ steps.app-token.outputs.token }}
318349 persist-credentials : true
319- ref : main # Always use main branch for deployment
350+ ref : ${{ needs.prepare.outputs.version }}
320351
321352 - name : Download build artifacts
322353 uses : actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
0 commit comments