Skip to content

Commit 4cf0e93

Browse files
aksOpsclaude
andcommitted
feat(release): darwin/arm64 release workflow
Adds release-darwin.yml on macos-14 runner. Trigger: same v*.*.* tag push that fires release-go.yml. Builds darwin/arm64 natively (CGO, clang, kuzudb + go-sqlite3 build cleanly), packages a tar.gz, generates SPDX SBOM via Syft, signs the archive directly with Cosign keyless (bundle format — matches the cosign v4 update in #136), then uploads to the existing Release created by release-go.yml. Why a separate workflow: - release-go.yml runs on ubuntu-latest. CGO + kuzudb won't cross-compile to darwin from linux. - macos-14 runners are arm64-native; cross-compile happens via native CC=clang. - Two workflows publish to the same tag → same Release. The upload step retries 3× (30s delay) to handle the race with release-go.yml creating the Release (linux completes first, darwin attaches to that Release). Follow-up: branch protection cleanup. The `build` required check is still satisfied by build-shim.yml; once an admin drops it from required-checks in the UI (Settings → Branches → main), build-shim.yml can be deleted. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ffb3a16 commit 4cf0e93

1 file changed

Lines changed: 122 additions & 0 deletions

File tree

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
name: release-darwin
2+
3+
# darwin/arm64 release on a macos-14 runner. Attaches binaries to the
4+
# existing GitHub Release created by release-go.yml (which only builds
5+
# linux). Runs after the linux release lands so the target Release
6+
# already exists.
7+
#
8+
# Why a separate workflow:
9+
# - release-go.yml runs on ubuntu-latest. CGO + kuzudb won't
10+
# cross-compile cleanly to darwin from linux.
11+
# - macos-14 runners are arm64 (M1+); cross-compile to darwin/arm64
12+
# happens via native CC = clang.
13+
# - The two workflows publish to the same tag → same Release.
14+
15+
on:
16+
push:
17+
tags:
18+
- 'v*.*.*'
19+
workflow_dispatch:
20+
inputs:
21+
tag:
22+
description: 'Tag to release (e.g. v0.3.0). Release must already exist.'
23+
required: true
24+
25+
permissions:
26+
contents: write
27+
id-token: write # Sigstore keyless via GitHub OIDC
28+
attestations: write
29+
30+
jobs:
31+
release-darwin:
32+
name: release (darwin / arm64)
33+
runs-on: macos-14
34+
steps:
35+
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
36+
with:
37+
fetch-depth: 0
38+
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
39+
with:
40+
go-version: '1.25.10'
41+
cache: true
42+
cache-dependency-path: go/go.sum
43+
44+
- name: Build darwin/arm64 binary
45+
working-directory: go
46+
env:
47+
CGO_ENABLED: '1'
48+
GOOS: darwin
49+
GOARCH: arm64
50+
run: |
51+
TAG="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}"
52+
VERSION="${TAG#v}"
53+
go build \
54+
-trimpath \
55+
-ldflags "-s -w \
56+
-X 'github.com/randomcodespace/codeiq/go/internal/buildinfo.Version=${VERSION}' \
57+
-X 'github.com/randomcodespace/codeiq/go/internal/buildinfo.Commit=$(git rev-parse --short HEAD)' \
58+
-X 'github.com/randomcodespace/codeiq/go/internal/buildinfo.Date=$(date -u +%Y-%m-%dT%H:%M:%SZ)' \
59+
-X 'github.com/randomcodespace/codeiq/go/internal/buildinfo.Dirty=false'" \
60+
-o codeiq ./cmd/codeiq
61+
62+
- name: Package archive
63+
working-directory: go
64+
run: |
65+
TAG="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}"
66+
VERSION="${TAG#v}"
67+
ARCHIVE_DIR="codeiq_${VERSION}_darwin_arm64"
68+
mkdir -p "${ARCHIVE_DIR}"
69+
cp codeiq "${ARCHIVE_DIR}/"
70+
cp ../LICENSE "${ARCHIVE_DIR}/" 2>/dev/null || true
71+
cp ../README.md "${ARCHIVE_DIR}/" 2>/dev/null || true
72+
cp ../CHANGELOG.md "${ARCHIVE_DIR}/" 2>/dev/null || true
73+
tar czf "../${ARCHIVE_DIR}.tar.gz" "${ARCHIVE_DIR}"
74+
75+
- name: Install Syft (SBOM)
76+
uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
77+
- name: Generate SBOM
78+
run: |
79+
TAG="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}"
80+
VERSION="${TAG#v}"
81+
ARCHIVE="codeiq_${VERSION}_darwin_arm64.tar.gz"
82+
syft "$ARCHIVE" --output spdx-json="${ARCHIVE}.sbom.spdx.json"
83+
84+
- name: Install Cosign (signing)
85+
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
86+
- name: Sign archive (Sigstore keyless, bundle format)
87+
run: |
88+
TAG="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}"
89+
VERSION="${TAG#v}"
90+
ARCHIVE="codeiq_${VERSION}_darwin_arm64.tar.gz"
91+
cosign sign-blob \
92+
--yes \
93+
--bundle "${ARCHIVE}.cosign.bundle" \
94+
"$ARCHIVE"
95+
96+
- name: Upload to GitHub Release
97+
env:
98+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
99+
run: |
100+
TAG="${GITHUB_REF_NAME:-${{ github.event.inputs.tag }}}"
101+
VERSION="${TAG#v}"
102+
# Retry up to 3 times to handle race with release-go.yml
103+
# creating the Release.
104+
for i in 1 2 3; do
105+
if gh release view "$TAG" >/dev/null 2>&1; then
106+
gh release upload "$TAG" \
107+
"codeiq_${VERSION}_darwin_arm64.tar.gz" \
108+
"codeiq_${VERSION}_darwin_arm64.tar.gz.sbom.spdx.json" \
109+
"codeiq_${VERSION}_darwin_arm64.tar.gz.cosign.bundle" \
110+
--clobber
111+
exit 0
112+
fi
113+
echo "Release $TAG not yet visible, waiting 30s ($i/3)..."
114+
sleep 30
115+
done
116+
echo "::error::Release $TAG never appeared; release-go.yml may have failed"
117+
exit 1
118+
119+
- name: Attest darwin archive (build provenance)
120+
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
121+
with:
122+
subject-path: 'codeiq_*_darwin_arm64.tar.gz'

0 commit comments

Comments
 (0)