Skip to content

Commit c65fa35

Browse files
authored
Merge pull request #14 from dAppCore/ci/pr-gate-tag-release
ci: three-OS PR test gate + tag-on-main versioned releases
2 parents c7e5f1a + 0cf6721 commit c65fa35

2 files changed

Lines changed: 99 additions & 25 deletions

File tree

.github/workflows/build.yml

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ name: Build
1616
on:
1717
push:
1818
branches: [dev, main]
19+
tags: ['v*'] # a version tag publishes the REAL release (guarded on-main)
1920
workflow_dispatch:
2021

2122
permissions:
@@ -66,7 +67,7 @@ jobs:
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 }}

.github/workflows/ci.yml

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
# Portable CI for go-inference — the default-tag (no-GPU) test + coverage lane.
2-
# go-inference is a Metal/CGO project; the FULL lem build (engine/metal, the
3-
# metallibs) needs macOS 26 / Metal 4 and lives in build.yml on a self-hosted
4-
# runner. This lane runs the portable suite (Taskfile `test`/`cover`) on any OS.
1+
# PR gate + push CI for go-inference — the model-free test surface on all three
2+
# desktop OSes. The suite is testable without a model loaded (engine/metal skips
3+
# cleanly without MLX_METALLIB_PATH; engine/hip's contract tests are host-side),
4+
# so this lane is the go/no-go for PRs into dev: linux + macos are REQUIRED
5+
# checks; windows is EXPERIMENTAL (continue-on-error) until the cgo-on windows
6+
# graph is proven — its logs name the real portability offenders either way.
7+
# The full artifact build (and the metal lane) lives in build.yml.
58
name: CI
69

710
on:
@@ -13,29 +16,59 @@ on:
1316
permissions:
1417
contents: read
1518

19+
env:
20+
GO_VERSION: "1.26"
21+
1622
jobs:
1723
test:
18-
name: Portable test + coverage
19-
runs-on: ubuntu-latest
24+
name: tests · ${{ matrix.os_name }}
25+
runs-on: ${{ matrix.runner }}
26+
continue-on-error: ${{ matrix.experimental }}
27+
strategy:
28+
fail-fast: false
29+
matrix:
30+
include:
31+
- { runner: ubuntu-latest, os_name: linux, experimental: false }
32+
- { runner: macos-latest, os_name: macos, experimental: false }
33+
- { runner: windows-latest, os_name: windows, experimental: true }
2034
env:
21-
GOWORK: "off" # resolve deps from go/go.mod tags, not the workspace
22-
CGO_ENABLED: "1" # go/ links duckdb (go-duckdb/v2 ships prebuilt linux libs)
35+
CGO_ENABLED: "1" # go/ links duckdb (prebuilt libs for all three OSes)
2336
steps:
2437
- uses: actions/checkout@v4
2538

2639
- uses: actions/setup-go@v5
2740
with:
28-
go-version: "1.26"
29-
# The module root is go/ (go.sum lives there, not at the repo root); without
30-
# this, setup-go's cache aborts with "Dependencies file is not found ...
31-
# Supported file pattern: go.sum". This lane only compiles the go/ module.
32-
cache-dependency-path: go/go.sum
41+
go-version: ${{ env.GO_VERSION }}
42+
cache-dependency-path: |
43+
go/go.sum
44+
cli/go.sum
3345
34-
- name: Portable tests + coverage (default tags — engine/metal excluded)
46+
# The module suite resolves from go.mod tags (GOWORK=off) — proves the
47+
# published dependency surface, not the workspace.
48+
- name: Module suite (default tags — engine/metal skips without a metallib)
3549
working-directory: go
50+
env:
51+
GOWORK: "off"
52+
shell: bash
3653
run: go test -count=1 -covermode=atomic -coverprofile=coverage.out ./...
3754

55+
# cli + examples need the workspace (cli requires the LOCAL go/ tree; the
56+
# examples module is the acceptance surface — every public feature ships
57+
# with its example, so compiling them all catches API breakage model-free).
58+
- name: TUI suite (workspace)
59+
working-directory: cli
60+
shell: bash
61+
run: go test -count=1 ./tui/...
62+
63+
- name: Examples compile + vet (workspace — the acceptance surface)
64+
working-directory: examples
65+
shell: bash
66+
run: |
67+
go build ./...
68+
go vet ./...
69+
3870
- name: Upload coverage to Codecov
71+
if: matrix.os_name == 'linux'
3972
uses: codecov/codecov-action@v5
4073
with:
4174
files: go/coverage.out

0 commit comments

Comments
 (0)