Skip to content

Release

Release #10

Workflow file for this run

name: Release
on:
push:
tags:
- "v*"
workflow_dispatch:
inputs:
tag:
description: Immutable public release tag to package
required: true
default: v0.3.3
type: string
confirm_publish:
description: Type publish-v0.3.3 to enable publication
required: true
type: string
permissions: {}
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
jobs:
create-release:
name: Create draft release
if: ${{ github.event_name == 'push' }}
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
persist-credentials: false
- name: Verify release contract
env:
TAG: ${{ github.ref_name }}
run: cargo run --quiet -p xtask -- release verify --contract-only --expected-tag "$TAG"
- name: Create draft release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
prerelease_flag=""
case "$TAG" in *-*) prerelease_flag="--prerelease" ;; esac
gh release create "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--draft \
$prerelease_flag \
--title "Switchloom $TAG" \
--generate-notes
build:
name: Build ${{ matrix.target }}
needs: create-release
if: ${{ github.event_name == 'push' }}
strategy:
fail-fast: false
matrix:
include:
- target: darwin-arm64
rust_target: aarch64-apple-darwin
runner: macos-14
- target: darwin-x86_64
rust_target: x86_64-apple-darwin
runner: macos-15-intel
- target: linux-x86_64
rust_target: x86_64-unknown-linux-gnu
runner: ubuntu-24.04
- target: linux-arm64
rust_target: aarch64-unknown-linux-gnu
runner: ubuntu-24.04-arm
runs-on: ${{ matrix.runner }}
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
persist-credentials: false
- name: Install Rust target
run: rustup target add ${{ matrix.rust_target }}
- name: Build release archive
env:
TAG: ${{ github.ref_name }}
run: |
cargo run --quiet -p xtask -- release package \
--target "${{ matrix.target }}" \
--cargo-target "${{ matrix.rust_target }}" \
--stage-npm \
--provenance-dir dist/provenance \
--runner "github-actions-${{ matrix.runner }}" \
--git-sha "$GITHUB_SHA" \
--built-at "release-$TAG"
- name: Smoke-test native binary
env:
TAG: ${{ github.ref_name }}
run: test "$(./target/${{ matrix.rust_target }}/release/model-routing --version)" = "model-routing ${TAG#v}"
- name: Upload release archive
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
cp "dist/provenance/${{ matrix.target }}/provenance.json" \
"dist/switchloom-${{ matrix.target }}.provenance.json"
gh release upload "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--clobber \
"dist/switchloom-${{ matrix.target }}.tar.gz" \
"dist/switchloom-${{ matrix.target }}.provenance.json"
finalize:
name: Publish checksums and release
needs: build
if: ${{ github.event_name == 'push' }}
runs-on: ubuntu-24.04
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
persist-credentials: false
- name: Download release archives
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
mkdir assets
gh release download "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--pattern 'switchloom-*.tar.gz' \
--dir assets
- name: Generate aggregate checksums
run: cargo run --quiet -p xtask -- release package --aggregate-checksums-dir assets
- name: Publish release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
gh release upload "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--clobber \
assets/SHA256SUMS
gh release edit "$TAG" --repo "$GITHUB_REPOSITORY" --draft=false
npm-publish:
name: Publish npm package
needs: finalize
if: ${{ github.event_name == 'push' && vars.NPM_PUBLISH_ENABLED == 'true' }}
runs-on: ubuntu-24.04
permissions:
contents: read
id-token: write
steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
registry-url: https://registry.npmjs.org
package-manager-cache: false
- name: Download and verify release archives
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.ref_name }}
run: |
mkdir assets
gh release download "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--pattern 'switchloom-*.tar.gz' \
--pattern 'switchloom-*.provenance.json' \
--pattern SHA256SUMS \
--dir assets
cd assets
sha256sum -c SHA256SUMS
- name: Bundle platform binaries
env:
TAG: ${{ github.ref_name }}
run: |
version="${TAG#v}"
for target in darwin-arm64 darwin-x86_64 linux-arm64 linux-x86_64; do
mkdir -p "extract/$target" "npm/native/$target"
tar -xzf "assets/switchloom-$target.tar.gz" -C "extract/$target"
install -m 755 "extract/$target/model-routing" "npm/native/$target/model-routing"
done
cargo run --quiet -p xtask -- release package \
--assemble-provenance \
--provenance-dir assets \
--git-sha "$(git rev-parse HEAD)" \
--built-at "release-$TAG" \
--generated-by github-actions-release
test "$(./npm/native/linux-x86_64/model-routing --version)" = "model-routing $version"
SWITCHLOOM_NATIVE_BIN="$PWD/npm/native/linux-x86_64/model-routing" node npm/bin/model-routing.js --version
cargo run --quiet -p xtask -- release verify --inventory-only --require-provenance
- name: Publish npm package
env:
TAG: ${{ github.ref_name }}
NODE_AUTH_TOKEN: ""
run: |
case "$TAG" in
*-*) npm publish --access public --provenance --tag next ;;
*) npm publish --access public --provenance ;;
esac
homebrew-tap:
name: Update Homebrew tap
needs: finalize
if: ${{ github.event_name == 'push' && vars.HOMEBREW_TAP_ENABLED == 'true' && !contains(github.ref_name, '-') }}
runs-on: ubuntu-24.04
permissions: {}
steps:
- name: Checkout
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
persist-credentials: false
- name: Download checksums
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
run: |
mkdir assets
gh release download "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--pattern SHA256SUMS \
--dir assets
- name: Generate formula
env:
TAG: ${{ github.ref_name }}
run: scripts/generate-formula.sh "${TAG#v}" assets/SHA256SUMS > switchloom.rb
- name: Push formula to tap
env:
TAP_TOKEN: ${{ secrets.TAP_GITHUB_TOKEN }}
TAG: ${{ github.ref_name }}
run: |
test -n "$TAP_TOKEN"
git clone "https://x-access-token:${TAP_TOKEN}@github.com/instructa/homebrew-tap.git" tap
mkdir -p tap/Formula
cp switchloom.rb tap/Formula/switchloom.rb
cd tap
git config user.name "switchloom-release-bot"
git config user.email "release-bot@users.noreply.github.com"
git add Formula/switchloom.rb
if ! git diff --cached --quiet; then
git commit -m "switchloom ${TAG}"
git push origin HEAD
fi
npm-recovery:
name: Recover npm publication from release assets
if: ${{ github.event_name == 'workflow_dispatch' && inputs.tag == 'v0.3.3' && inputs.confirm_publish == 'publish-v0.3.3' }}
runs-on: ubuntu-24.04
permissions:
contents: read
id-token: write
steps:
- name: Checkout immutable release tag
uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
with:
ref: ${{ inputs.tag }}
persist-credentials: false
- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 24
registry-url: https://registry.npmjs.org
package-manager-cache: false
- name: Refuse an existing npm version
env:
TAG: ${{ inputs.tag }}
run: |
version="${TAG#v}"
if npm view "switchloom@$version" version >/dev/null 2>&1; then
echo "switchloom@$version is already published" >&2
exit 1
fi
- name: Download and verify immutable public release assets
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ inputs.tag }}
run: |
mkdir assets
gh release download "$TAG" \
--repo "$GITHUB_REPOSITORY" \
--pattern 'switchloom-*.tar.gz' \
--pattern SHA256SUMS \
--dir assets
cd assets
sha256sum -c SHA256SUMS
- name: Reconstruct package provenance from verified assets
env:
TAG: ${{ inputs.tag }}
run: |
version="${TAG#v}"
git_sha="$(git rev-parse HEAD)"
expected_members='LICENSE
README.md
SHA256SUMS
model-routing'
validate_archive() {
archive="$1"
members="$(tar -tzf "$archive")"
members="$(printf '%s\n' "$members" | LC_ALL=C sort)"
if [ "$members" != "$expected_members" ]; then
echo "unexpected release archive members in $archive" >&2
printf '%s\n' "$members" >&2
return 1
fi
}
fixture_dir="$(mktemp -d)"
trap 'rm -rf "$fixture_dir"' EXIT HUP INT TERM
mkdir -p "$fixture_dir/good" "$fixture_dir/bad"
for member in LICENSE README.md SHA256SUMS model-routing; do
: > "$fixture_dir/good/$member"
: > "$fixture_dir/bad/$member"
done
: > "$fixture_dir/bad/unexpected"
tar -czf "$fixture_dir/good.tar.gz" -C "$fixture_dir/good" LICENSE README.md SHA256SUMS model-routing
tar -czf "$fixture_dir/bad.tar.gz" -C "$fixture_dir/bad" LICENSE README.md SHA256SUMS model-routing unexpected
validate_archive "$fixture_dir/good.tar.gz"
if validate_archive "$fixture_dir/bad.tar.gz"; then
echo "archive validator accepted an unexpected member" >&2
exit 1
fi
mkdir -p recovery-receipts
for target in darwin-arm64 darwin-x86_64 linux-arm64 linux-x86_64; do
validate_archive "assets/switchloom-$target.tar.gz"
mkdir -p "extract/$target" "npm/native/$target"
tar -xzf "assets/switchloom-$target.tar.gz" -C "extract/$target"
install -m 755 "extract/$target/model-routing" "npm/native/$target/model-routing"
case "$target" in
darwin-arm64) rust_target=aarch64-apple-darwin; runner=macos-14 ;;
darwin-x86_64) rust_target=x86_64-apple-darwin; runner=macos-15-intel ;;
linux-arm64) rust_target=aarch64-unknown-linux-gnu; runner=ubuntu-24.04-arm ;;
linux-x86_64) rust_target=x86_64-unknown-linux-gnu; runner=ubuntu-24.04 ;;
esac
sha256="$(sha256sum "npm/native/$target/model-routing" | awk '{print $1}')"
jq -n \
--arg target "$target" \
--arg rust_target "$rust_target" \
--arg runner "$runner" \
--arg version "model-routing $version" \
--arg sha256 "$sha256" \
--arg git_sha "$git_sha" \
'{target: $target, rust_target: $rust_target, runner: $runner, path: ("npm/native/" + $target + "/model-routing"), version: $version, sha256: $sha256, git_sha: $git_sha, built_at: "recovered-from-public-release"}' \
> "recovery-receipts/switchloom-$target.provenance.json"
done
test "$(./npm/native/linux-x86_64/model-routing --version)" = "model-routing $version"
cargo run --quiet -p xtask -- release package \
--assemble-provenance \
--provenance-dir recovery-receipts \
--git-sha "$git_sha" \
--built-at "recovery-$TAG" \
--generated-by github-actions-release-recovery
cargo run --quiet -p xtask -- release verify --inventory-only --require-provenance
SWITCHLOOM_NATIVE_BIN="$PWD/npm/native/linux-x86_64/model-routing" node npm/bin/model-routing.js --version
- name: Publish npm package
run: npm publish --access public --provenance