Release #10
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: 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 |