@@ -16,6 +16,7 @@ name: Build
1616on :
1717 push :
1818 branches : [dev, main]
19+ tags : ['v*'] # a version tag publishes the REAL release (guarded on-main)
1920 workflow_dispatch :
2021
2122permissions :
6667 EXE : ${{ matrix.exe }}
6768 run : |
6869 set -euo pipefail
69- VERSION="dev-${GITHUB_SHA:0:12}"
70+ if [[ "$GITHUB_REF" == refs/tags/v* ]]; then VERSION="$GITHUB_REF_NAME"; else VERSION=" dev-${GITHUB_SHA:0:12}"; fi
7071 mkdir -p bin
7172 go build -trimpath -ldflags "-X main.version=${VERSION}" -o "bin/lem${EXE}" ./cli
7273 test -s "bin/lem${EXE}"
@@ -107,7 +108,7 @@ jobs:
107108 shell : bash
108109 run : |
109110 set -euo pipefail
110- VERSION="dev-${GITHUB_SHA:0:12}"
111+ if [[ "$GITHUB_REF" == refs/tags/v* ]]; then VERSION="$GITHUB_REF_NAME"; else VERSION=" dev-${GITHUB_SHA:0:12}"; fi
111112 task metallib
112113 task build:embed VERSION="${VERSION}"
113114 test -s bin/lem
@@ -119,25 +120,65 @@ jobs:
119120 if-no-files-found : error
120121
121122 # ---- release: package each built binary under BOTH names (build once, package
122- # twice) and publish to the rolling `dev` prerelease. Runs only for dev
123- # pushes; requires cpu to have succeeded and tolerates metal being skipped. ----
123+ # twice). Two publish shapes: a dev push feeds the rolling `dev`
124+ # prerelease; a v* TAG (guarded: the tagged commit must be on main)
125+ # publishes the real versioned release. Requires cpu green; tolerates
126+ # metal skipped. ----
124127 release :
125- name : Zip (Native + Driver) + rolling dev prerelease
128+ name : Zip (Native + Driver) + release
126129 needs : [cpu, metal]
127- if : ${{ !cancelled() && needs.cpu.result == 'success' && github.event_name == 'push' && github.ref == 'refs/heads/dev' }}
130+ if : ${{ !cancelled() && needs.cpu.result == 'success' && github.event_name == 'push' && ( github.ref == 'refs/heads/dev' || startsWith(github.ref, 'refs/tags/v')) }}
128131 runs-on : ubuntu-latest
129132 permissions :
130133 contents : write
131134 steps :
135+ - uses : actions/checkout@v4
136+ with :
137+ fetch-depth : 0 # the tag-on-main ancestry guard needs history
138+
139+ # A tag release only publishes if the tagged commit is reachable from
140+ # main — "a tag hitting main". A tag pushed off-branch fails LOUDLY
141+ # (the run goes red) rather than silently minting a release.
142+ - name : Guard — tag must be on main
143+ if : startsWith(github.ref, 'refs/tags/v')
144+ shell : bash
145+ run : |
146+ set -euo pipefail
147+ git fetch -q origin main
148+ if git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then
149+ echo "tag $GITHUB_REF_NAME is on main — releasing"
150+ else
151+ echo "::error::tag $GITHUB_REF_NAME ($GITHUB_SHA) is NOT on main — refusing to release"
152+ exit 1
153+ fi
154+
155+ - name : Resolve version + release shape
156+ id : shape
157+ shell : bash
158+ run : |
159+ set -euo pipefail
160+ if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
161+ echo "version=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
162+ echo "tag=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
163+ echo "name=$GITHUB_REF_NAME" >> "$GITHUB_OUTPUT"
164+ echo "prerelease=false" >> "$GITHUB_OUTPUT"
165+ else
166+ echo "version=dev-${GITHUB_SHA:0:12}" >> "$GITHUB_OUTPUT"
167+ echo "tag=dev" >> "$GITHUB_OUTPUT"
168+ echo "name=dev (rolling)" >> "$GITHUB_OUTPUT"
169+ echo "prerelease=true" >> "$GITHUB_OUTPUT"
170+ fi
171+
132172 - uses : actions/download-artifact@v4
133173 with :
134174 path : dist # one dir per cell: dist/lem-<backend>-<os>-<arch>/lem[.exe]
135175
136176 - name : Package Native + Driver zips
137177 shell : bash
178+ env :
179+ VERSION : ${{ steps.shape.outputs.version }}
138180 run : |
139181 set -euo pipefail
140- VERSION="dev-${GITHUB_SHA:0:12}"
141182 mkdir -p out
142183 cd dist
143184 # ONLY the binary artifacts (lem-cpu-*, lem-metal-*) — lem-sdks also
@@ -159,12 +200,12 @@ jobs:
159200 done
160201 ls -la ../out
161202
162- - name : Publish rolling dev prerelease
203+ - name : Publish release
163204 uses : softprops/action-gh-release@v2
164205 with :
165- tag_name : dev
166- name : dev (rolling)
167- prerelease : true
206+ tag_name : ${{ steps.shape.outputs.tag }}
207+ name : ${{ steps.shape.outputs.name }}
208+ prerelease : ${{ steps.shape.outputs.prerelease }}
168209 files : out/*.zip
169210 env :
170211 GITHUB_TOKEN : ${{ secrets.GITHUB_TOKEN }}
0 commit comments