Skip to content

Commit 4422bb2

Browse files
Rick Valdesclaude
andcommitted
Add the utmstack release workflow
Tagging v* builds the branded binaries for macOS and Linux and publishes them with a checksums.txt the installer verifies against. Each build asserts the artifact is actually shippable before it is uploaded: the reported version matches the tag, the help output is branded, a clean config directory gets seeded, the embedded skills and agents extract, and the default config references utmstack-mcp. A binary that fails any of these never reaches a release. Upstream's own workflows are left untouched. They all key on dev / production / beta / ci, so none of them fire on main — but creating a dev branch on this fork would start firing deploy.yml and publish.yml against upstream's infrastructure. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent efb4f9c commit 4422bb2

1 file changed

Lines changed: 134 additions & 0 deletions

File tree

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
name: utmstack-release
2+
3+
# Builds the branded `utmstack` binaries and publishes them as release assets.
4+
#
5+
# The installer downloads "$APP-$target" (e.g. utmstack-linux-x64.tar.gz), so
6+
# every variant the installer can ask for must exist here. A missing -baseline
7+
# or -musl asset makes the install 404 on non-AVX2 cloud VMs and on Alpine.
8+
9+
on:
10+
push:
11+
tags: ["v*"]
12+
workflow_dispatch:
13+
inputs:
14+
version:
15+
description: "Version to build (without the leading v)"
16+
required: true
17+
18+
permissions:
19+
contents: write
20+
21+
jobs:
22+
build:
23+
name: ${{ matrix.target }}
24+
runs-on: ${{ matrix.runner }}
25+
strategy:
26+
fail-fast: false
27+
matrix:
28+
include:
29+
- { runner: macos-14, target: darwin-arm64 }
30+
- { runner: macos-13, target: darwin-x64 }
31+
- { runner: ubuntu-22.04, target: linux-x64 }
32+
- { runner: ubuntu-22.04-arm, target: linux-arm64 }
33+
34+
steps:
35+
- uses: actions/checkout@v4
36+
37+
- uses: oven-sh/setup-bun@v2
38+
with:
39+
bun-version: 1.3.14
40+
41+
- name: Resolve version
42+
id: version
43+
shell: bash
44+
run: |
45+
if [ -n "${{ github.event.inputs.version }}" ]; then
46+
echo "value=${{ github.event.inputs.version }}" >> "$GITHUB_OUTPUT"
47+
else
48+
echo "value=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
49+
fi
50+
51+
- name: Install dependencies
52+
run: bun install
53+
54+
- name: Build
55+
working-directory: packages/opencode
56+
env:
57+
OPENCODE_VERSION: ${{ steps.version.outputs.value }}
58+
run: bun run script/build.ts --single
59+
60+
- name: Verify the binary is branded and self-contained
61+
shell: bash
62+
working-directory: packages/opencode
63+
run: |
64+
set -eu
65+
BIN=$(find dist -type f -name utmstack | head -1)
66+
[ -n "$BIN" ] || { echo "no utmstack binary produced"; exit 1; }
67+
echo "binary: $BIN"
68+
69+
# Version must match what we asked for.
70+
got=$("$BIN" --version)
71+
[ "$got" = "${{ steps.version.outputs.value }}" ] || {
72+
echo "version mismatch: got '$got'"; exit 1; }
73+
74+
# The CLI must present itself as utmstack, not opencode.
75+
"$BIN" --help 2>&1 | grep -q "utmstack completion" || {
76+
echo "help output is not branded"; exit 1; }
77+
78+
# First run must seed config and extract the embedded skills/agents
79+
# into a clean config directory.
80+
TMPCFG=$(mktemp -d)
81+
XDG_CONFIG_HOME="$TMPCFG" "$BIN" --help >/dev/null 2>&1 || true
82+
XDG_CONFIG_HOME="$TMPCFG" "$BIN" mcp list >/dev/null 2>&1 || true
83+
test -f "$TMPCFG/utmstack/utmstack.json" || {
84+
echo "default config was not seeded"; exit 1; }
85+
skills=$(ls "$TMPCFG/utmstack/skills" 2>/dev/null | wc -l | tr -d ' ')
86+
agents=$(ls "$TMPCFG/utmstack/agent"/*.md 2>/dev/null | wc -l | tr -d ' ')
87+
echo "seeded config, $skills skills, $agents agents"
88+
[ "$skills" -gt 0 ] || { echo "no skills extracted"; exit 1; }
89+
[ "$agents" -gt 0 ] || { echo "no agents extracted"; exit 1; }
90+
91+
# The shipped default must point at the utmstack MCP server.
92+
grep -q '"utmstack-mcp"' "$TMPCFG/utmstack/utmstack.json" || {
93+
echo "default config does not reference utmstack-mcp"; exit 1; }
94+
95+
- name: Package
96+
shell: bash
97+
working-directory: packages/opencode
98+
run: |
99+
set -eu
100+
mkdir -p ../../out
101+
for dir in dist/*/; do
102+
name=$(basename "$dir")
103+
asset=$(echo "$name" | sed 's/^opencode-/utmstack-/')
104+
# COPYFILE_DISABLE / --no-xattrs keep macOS AppleDouble files and
105+
# the com.apple.provenance xattr out of the archive; without them
106+
# Linux tar warns on every extracted file.
107+
env COPYFILE_DISABLE=1 tar --no-xattrs -czf "../../out/${asset}.tar.gz" -C "$dir/bin" .
108+
done
109+
ls -lh ../../out/
110+
111+
- uses: actions/upload-artifact@v4
112+
with:
113+
name: ${{ matrix.target }}
114+
path: out/*
115+
116+
release:
117+
needs: build
118+
runs-on: ubuntu-22.04
119+
if: startsWith(github.ref, 'refs/tags/v')
120+
steps:
121+
- uses: actions/download-artifact@v4
122+
with: { path: artifacts }
123+
124+
- name: Collect and checksum
125+
run: |
126+
mkdir -p out
127+
find artifacts -type f -name '*.tar.gz' -exec cp {} out/ \;
128+
cd out && sha256sum * > checksums.txt
129+
cat checksums.txt
130+
131+
- uses: softprops/action-gh-release@v2
132+
with:
133+
files: out/*
134+
generate_release_notes: true

0 commit comments

Comments
 (0)