Skip to content

release: cut [Unreleased] → [v0.4.1] (#167) #3

release: cut [Unreleased] → [v0.4.1] (#167)

release: cut [Unreleased] → [v0.4.1] (#167) #3

Workflow file for this run

name: release-darwin
# darwin/arm64 release on a macos-14 runner. Attaches binaries to the
# existing GitHub Release created by release-go.yml (which only builds
# linux). Runs after the linux release lands so the target Release
# already exists.
#
# Why a separate workflow:
# - release-go.yml runs on ubuntu-latest. CGO + kuzudb won't
# cross-compile cleanly to darwin from linux.
# - macos-14 runners are arm64 (M1+); cross-compile to darwin/arm64
# happens via native CC = clang.
# - The two workflows publish to the same tag → same Release.
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
tag:
description: 'Tag to release (e.g. v0.3.0). Release must already exist.'
required: true
permissions:
contents: write
id-token: write # Sigstore keyless via GitHub OIDC
attestations: write
# Pass the input/ref to the shell via env vars (not inline `${{ }}`
# interpolation) — Semgrep `yaml.github-actions.security.run-shell-injection`
# rule. inputs.tag for workflow_dispatch; GITHUB_REF_NAME for tag pushes.
env:
TAG: ${{ github.event.inputs.tag || github.ref_name }}
jobs:
release-darwin:
name: release (darwin / arm64)
runs-on: macos-14
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: '1.25.10'
cache: true
cache-dependency-path: go.sum
- name: Build darwin/arm64 binary
env:
CGO_ENABLED: '1'
GOOS: darwin
GOARCH: arm64
run: |
VERSION="${TAG#v}"
go build \
-trimpath \
-ldflags "-s -w \
-X 'github.com/randomcodespace/codeiq/internal/buildinfo.Version=${VERSION}' \
-X 'github.com/randomcodespace/codeiq/internal/buildinfo.Commit=$(git rev-parse --short HEAD)' \
-X 'github.com/randomcodespace/codeiq/internal/buildinfo.Date=$(date -u +%Y-%m-%dT%H:%M:%SZ)' \
-X 'github.com/randomcodespace/codeiq/internal/buildinfo.Dirty=false'" \
-o codeiq ./cmd/codeiq
- name: Package archive
run: |
VERSION="${TAG#v}"
ARCHIVE_DIR="codeiq_${VERSION}_darwin_arm64"
mkdir -p "${ARCHIVE_DIR}"
cp codeiq "${ARCHIVE_DIR}/"
cp LICENSE "${ARCHIVE_DIR}/" 2>/dev/null || true
cp README.md "${ARCHIVE_DIR}/" 2>/dev/null || true
cp CHANGELOG.md "${ARCHIVE_DIR}/" 2>/dev/null || true
tar czf "${ARCHIVE_DIR}.tar.gz" "${ARCHIVE_DIR}"
- name: Install Syft (SBOM)
uses: anchore/sbom-action/download-syft@e22c389904149dbc22b58101806040fa8d37a610 # v0.24.0
- name: Generate SBOM
run: |
VERSION="${TAG#v}"
ARCHIVE="codeiq_${VERSION}_darwin_arm64.tar.gz"
syft "$ARCHIVE" --output spdx-json="${ARCHIVE}.sbom.spdx.json"
- name: Install Cosign (signing)
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
- name: Sign archive (Sigstore keyless, bundle format)
run: |
VERSION="${TAG#v}"
ARCHIVE="codeiq_${VERSION}_darwin_arm64.tar.gz"
cosign sign-blob \
--yes \
--bundle "${ARCHIVE}.cosign.bundle" \
"$ARCHIVE"
- name: Upload to GitHub Release
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
run: |
VERSION="${TAG#v}"
# release-go.yml fires on the same tag push and creates the
# Release via goreleaser. With CGO + Kuzu + cosign + SBOM the
# full pipeline typically lands a Release in 4–8 minutes. We
# poll for up to 15 minutes (30 × 30s) and early-bail if the
# upstream release-go run for this tag already concluded as
# failed / cancelled / timed_out so this job's failure message
# is actionable rather than "timeout after 15m".
MAX_RETRIES=30
SLEEP_SECS=30
go_run_failed=0
for i in $(seq 1 "$MAX_RETRIES"); do
if gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1; then
echo "Release $TAG visible after $((i-1)) wait cycles."
gh release upload "$TAG" --repo "$REPO" \
"codeiq_${VERSION}_darwin_arm64.tar.gz" \
"codeiq_${VERSION}_darwin_arm64.tar.gz.sbom.spdx.json" \
"codeiq_${VERSION}_darwin_arm64.tar.gz.cosign.bundle" \
--clobber
exit 0
fi
go_status=$(gh run list --repo "$REPO" \
--workflow release-go.yml \
--event push \
--branch "$TAG" \
--limit 1 \
--json conclusion,status 2>/dev/null || echo '[]')
conclusion=$(printf '%s' "$go_status" | jq -r '.[0].conclusion // ""')
status=$(printf '%s' "$go_status" | jq -r '.[0].status // ""')
case "$conclusion" in
failure|cancelled|timed_out)
go_run_failed=1
echo "::error::release-go.yml for $TAG ended with conclusion=$conclusion — bailing"
break
;;
esac
echo "Release $TAG not yet visible (release-go status=${status:-unknown} conclusion=${conclusion:-pending}); waiting ${SLEEP_SECS}s ($i/$MAX_RETRIES)..."
sleep "$SLEEP_SECS"
done
if [ "$go_run_failed" = "1" ]; then
echo "::error::release-go.yml failed for $TAG; this darwin job cannot proceed"
else
echo "::error::Release $TAG never appeared after $((MAX_RETRIES * SLEEP_SECS))s"
fi
exit 1
- name: Attest darwin archive (build provenance)
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
with:
subject-path: 'codeiq_*_darwin_arm64.tar.gz'