Fix the release verify picking a musl binary on glibc runners #2
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: utmstack-release | |
| # Builds the branded `utmstack` binaries for every platform the installers can | |
| # request, and publishes them with a checksums.txt the installers verify. | |
| # | |
| # The installer downloads "$APP-$target" (e.g. utmstack-linux-x64.tar.gz), so a | |
| # target missing here is a 404 for those users. The -baseline variants matter: | |
| # without them, any x64 machine lacking AVX2 — which includes a lot of cloud | |
| # VMs — cannot install. | |
| on: | |
| push: | |
| tags: ["v*"] | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: "Version to build (without the leading v)" | |
| required: true | |
| permissions: | |
| contents: write | |
| jobs: | |
| build: | |
| name: ${{ matrix.target }} | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # macOS. Built natively so PyInstaller/Bun ad-hoc signing applies — | |
| # an unsigned arm64 binary will not execute on Apple Silicon. | |
| - { runner: macos-14, target: darwin-arm64, ext: zip } | |
| - { runner: macos-15-intel, target: darwin-x64, ext: zip, baseline: true } | |
| # Linux. x64 builds on 22.04 (glibc 2.35) so it runs on Ubuntu 22.04+ | |
| # and RHEL 9+. arm64 has no 22.04 ARM runner we can rely on, so it | |
| # builds on 24.04 (glibc 2.39) and needs Ubuntu 24.04+ / Debian 13+. | |
| - { runner: ubuntu-22.04, target: linux-x64, ext: tar.gz, baseline: true } | |
| - { runner: ubuntu-24.04-arm, target: linux-arm64, ext: tar.gz } | |
| # Windows, both architectures. | |
| - { runner: windows-2022, target: windows-x64, ext: zip, baseline: true } | |
| - { runner: windows-11-arm, target: windows-arm64, ext: zip } | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: 1.3.14 | |
| - name: Resolve version | |
| id: version | |
| shell: bash | |
| run: | | |
| if [ -n "${{ github.event.inputs.version }}" ]; then | |
| echo "value=${{ github.event.inputs.version }}" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "value=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Install dependencies | |
| run: bun install | |
| - name: Build | |
| working-directory: packages/opencode | |
| shell: bash | |
| env: | |
| OPENCODE_VERSION: ${{ steps.version.outputs.value }} | |
| run: | | |
| # --baseline additionally emits the no-AVX2 variant for x64 targets. | |
| if [ "${{ matrix.baseline }}" = "true" ]; then | |
| bun run script/build.ts --single --baseline | |
| else | |
| bun run script/build.ts --single | |
| fi | |
| ls -la dist/ | |
| - name: Verify the binary is branded and self-contained | |
| shell: bash | |
| working-directory: packages/opencode | |
| run: | | |
| set -eu | |
| # Address the exact matrix target. `find | head -1` picked whichever | |
| # directory sorted first, which on x64 runs was the musl variant — | |
| # a musl-linked binary cannot execute on a glibc runner (missing ELF | |
| # interpreter, which surfaces as "No such file or directory" / 127). | |
| DIST="dist/opencode-${{ matrix.target }}" | |
| BIN="$DIST/bin/utmstack" | |
| [ -f "$BIN" ] || BIN="$DIST/bin/utmstack.exe" | |
| [ -f "$BIN" ] || { echo "no binary at $DIST/bin"; ls -R dist | head -40; exit 1; } | |
| echo "binary: $BIN" | |
| got=$("$BIN" --version | tr -d '\r') | |
| [ "$got" = "${{ steps.version.outputs.value }}" ] || { | |
| echo "version mismatch: got '$got'"; exit 1; } | |
| "$BIN" --help 2>&1 | grep -q "utmstack completion" || { | |
| echo "help output is not branded"; exit 1; } | |
| # First run must seed config and extract the embedded skills/agents. | |
| TMPCFG=$(mktemp -d) | |
| XDG_CONFIG_HOME="$TMPCFG" APPDATA="$TMPCFG" "$BIN" --help >/dev/null 2>&1 || true | |
| XDG_CONFIG_HOME="$TMPCFG" APPDATA="$TMPCFG" "$BIN" mcp list >/dev/null 2>&1 || true | |
| test -f "$TMPCFG/utmstack/utmstack.json" || { | |
| echo "default config was not seeded"; exit 1; } | |
| skills=$(ls "$TMPCFG/utmstack/skills" 2>/dev/null | wc -l | tr -d ' ') | |
| agents=$(ls "$TMPCFG/utmstack/agent"/*.md 2>/dev/null | wc -l | tr -d ' ') | |
| echo "seeded config, $skills skills, $agents agents" | |
| [ "$skills" -gt 0 ] || { echo "no skills extracted"; exit 1; } | |
| [ "$agents" -gt 0 ] || { echo "no agents extracted"; exit 1; } | |
| grep -q '"utmstack-mcp"' "$TMPCFG/utmstack/utmstack.json" || { | |
| echo "default config does not reference utmstack-mcp"; exit 1; } | |
| - name: Package | |
| shell: bash | |
| working-directory: packages/opencode | |
| run: | | |
| set -eu | |
| # Absolute output dir. A relative "../.." from inside dist/<name>/bin | |
| # is five levels from the repo root and is trivially miscounted. | |
| OUT="$GITHUB_WORKSPACE/out" | |
| mkdir -p "$OUT" | |
| for dir in dist/*/; do | |
| name=$(basename "$dir") | |
| [ -d "$dir/bin" ] || continue | |
| # The build emits musl variants for free, but they are untested and | |
| # unadvertised, and the installer refuses musl outright. Publishing | |
| # them would promise support we have not verified. | |
| case "$name" in *-musl*) echo "skipping $name (musl, not published)"; continue ;; esac | |
| asset=$(echo "$name" | sed 's/^opencode-/utmstack-/') | |
| if [ "${{ matrix.ext }}" = "tar.gz" ]; then | |
| tar -czf "$OUT/${asset}.tar.gz" -C "$dir/bin" . | |
| else | |
| # COPYFILE_DISABLE keeps macOS AppleDouble "._*" files out of the | |
| # zip; -X drops extended attributes. Both are no-ops on Windows. | |
| (cd "$dir/bin" && env COPYFILE_DISABLE=1 7z a -tzip "$OUT/${asset}.zip" . >/dev/null) | |
| fi | |
| done | |
| ls -lh "$OUT" | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.target }} | |
| path: out/* | |
| release: | |
| needs: build | |
| runs-on: ubuntu-22.04 | |
| if: startsWith(github.ref, 'refs/tags/v') | |
| steps: | |
| - uses: actions/download-artifact@v4 | |
| with: { path: artifacts } | |
| - name: Collect and checksum | |
| run: | | |
| mkdir -p out | |
| find artifacts -type f \( -name '*.tar.gz' -o -name '*.zip' \) -exec cp {} out/ \; | |
| cd out && sha256sum * > checksums.txt | |
| echo "Publishing:"; cat checksums.txt | |
| - uses: softprops/action-gh-release@v2 | |
| with: | |
| files: out/* | |
| generate_release_notes: true |