@@ -3,7 +3,6 @@ name: prebuild
33on :
44 push :
55 branches : [master, main]
6- tags : ['v*']
76 pull_request :
87 workflow_dispatch :
98
@@ -139,59 +138,66 @@ jobs:
139138 if-no-files-found : error
140139 retention-days : 30
141140
142- # Gate the release on tag being reachable from master. If the tag was
143- # pushed from a feature branch (or any non-master commit), this job
144- # outputs on_master=false and the release job is skipped (not failed).
145- gate-release :
146- name : gate release on master ancestry
141+ # Release flow: only fires on push to master, only after every matrix
142+ # job succeeded, and only when the package.json version on the new
143+ # commit does not yet have a matching `v<version>` tag on origin.
144+ # That makes the release a function of "merged version bump to master"
145+ # — no manual tagging required.
146+ release :
147+ name : auto-release on version bump
147148 needs : prebuild
148- if : startsWith (github.ref, 'refs/tags/v ')
149+ if : github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main ')
149150 runs-on : ubuntu-latest
150- outputs :
151- on_master : ${{ steps.check.outputs.on_master }}
151+ permissions :
152+ contents : write
152153 steps :
153154 - uses : actions/checkout@v5
154- with :
155- fetch-depth : 0
156- - id : check
155+
156+ - name : Read version from package.json
157+ id : version
158+ run : |
159+ set -euo pipefail
160+ v=$(node -p "require('./package.json').version")
161+ echo "version=$v" >> "$GITHUB_OUTPUT"
162+ echo "tag=v$v" >> "$GITHUB_OUTPUT"
163+ echo "Detected package version: $v (target tag: v$v)"
164+
165+ - name : Check whether tag already exists on origin
166+ id : check_tag
157167 run : |
158168 set -euo pipefail
159- git fetch origin master
160- if git merge-base --is-ancestor "$GITHUB_SHA" origin/master ; then
161- echo "Tag $GITHUB_REF_NAME (commit $GITHUB_SHA) is on master — release will publish "
162- echo "on_master=true" >> "$GITHUB_OUTPUT "
169+ tag="${{ steps.version.outputs.tag }}"
170+ if git ls-remote --tags origin "refs/tags/$tag" | grep -q . ; then
171+ echo "exists=true" >> "$GITHUB_OUTPUT "
172+ echo "Tag $tag already exists on origin — nothing to release. "
163173 else
164- echo "Tag $GITHUB_REF_NAME (commit $GITHUB_SHA) is NOT on master — release will be skipped"
165- echo "Merge your PR to master first, then re-tag the merge commit."
166- echo "on_master=false" >> "$GITHUB_OUTPUT"
174+ echo "exists=false" >> "$GITHUB_OUTPUT"
175+ echo "Tag $tag does not exist yet — will create release."
167176 fi
168177
169- release :
170- name : attach prebuilds to GitHub Release
171- needs : [prebuild, gate-release]
172- if : needs.gate-release.outputs.on_master == 'true'
173- runs-on : ubuntu-latest
174- permissions :
175- contents : write
176- steps :
177- - uses : actions/checkout@v5
178-
179178 - name : Download all prebuild artifacts
179+ if : steps.check_tag.outputs.exists == 'false'
180180 uses : actions/download-artifact@v8
181181 with :
182182 pattern : prebuilds-*
183183 path : artifacts
184184 merge-multiple : true
185185
186186 - name : List downloaded assets
187+ if : steps.check_tag.outputs.exists == 'false'
187188 run : ls -la artifacts/
188189
189- - name : Create / update Release and upload assets
190+ - name : Create tag and Release, upload assets
191+ if : steps.check_tag.outputs.exists == 'false'
190192 uses : softprops/action-gh-release@v2
191193 with :
192- # Auto-uses the tag from github.ref. Idempotent: re-runs on the same
193- # tag will update the existing release and overwrite asset names
194- # that collide.
194+ # softprops/action-gh-release creates the tag itself when given
195+ # `tag_name` + `target_commitish`. It uses GITHUB_TOKEN, so the
196+ # resulting tag push does NOT re-trigger this workflow (GH's
197+ # rule: events from GITHUB_TOKEN don't cascade).
198+ tag_name : ${{ steps.version.outputs.tag }}
199+ target_commitish : ${{ github.sha }}
200+ name : ${{ steps.version.outputs.tag }}
195201 files : artifacts/*.tar.gz
196202 generate_release_notes : true
197203 fail_on_unmatched_files : true
0 commit comments