Release 0.9.16 #41
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: Release | |
| # Tag-driven, because a release is a deliberate act. Pushing `v0.2.0` builds the | |
| # binaries that `install.sh` and `install.ps1` download; nothing else publishes. | |
| on: | |
| push: | |
| tags: ["v*"] | |
| # Runnable by hand to rebuild the binaries without cutting a version. It | |
| # deliberately does not publish: on a branch `github.ref_name` is the branch | |
| # name, so publishing would create a GitHub release called "main" and point | |
| # /releases/latest at it - which is the exact URL every published install | |
| # command reads from. | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| build: | |
| runs-on: ubuntu-latest | |
| strategy: | |
| # One failing target must not cancel the rest: a missing linux build is | |
| # better than a release where three of four platforms silently vanished. | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - target: bun-darwin-arm64 | |
| asset: pew2-darwin-arm64 | |
| - target: bun-darwin-x64 | |
| asset: pew2-darwin-x64 | |
| - target: bun-linux-x64 | |
| asset: pew2-linux-x64 | |
| - target: bun-linux-arm64 | |
| asset: pew2-linux-arm64 | |
| - target: bun-windows-x64 | |
| asset: pew2-windows-x64.exe | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: latest | |
| - run: bun install --frozen-lockfile | |
| # Cross-compiled from one runner: bun downloads the target runtime itself, | |
| # so there is no need for a mac and a windows machine in the matrix. | |
| - name: Compile | |
| run: | | |
| bun build --compile --minify \ | |
| --target=${{ matrix.target }} \ | |
| packages/daemon/src/cli/index.ts \ | |
| --outfile ${{ matrix.asset }} | |
| # The provider manifests are compiled in rather than read from disk, and a | |
| # binary that finds none of them looks exactly like a machine with no | |
| # agents installed. Prove the shipped artifact knows its agents before it | |
| # is published, not after someone reports it as broken. | |
| # | |
| # Only the native target can be executed here; the others are checked by | |
| # the same assertion on their own platform when someone runs them. | |
| - name: Verify the binary finds its agents | |
| if: matrix.target == 'bun-linux-x64' | |
| run: | | |
| # The manifests are compiled into the binary rather than read from | |
| # disk, and a build that lost them reports zero agents - which on a | |
| # user's machine is indistinguishable from "you have nothing | |
| # installed". Catch that here rather than in a bug report. | |
| # | |
| # Uses --json, not the human output: the screen is a designed surface | |
| # that gets reworded, and an earlier version of this check broke | |
| # simply because the list started showing display names instead of | |
| # ids. A release must not fail over a copy change. | |
| found=$(./${{ matrix.asset }} providers list --json | bun -e \ | |
| 'const d = await Bun.stdin.json(); console.log(d.length)') | |
| total=$(bun -e \ | |
| 'import { BUNDLED_MANIFESTS } from "./packages/daemon/src/providers/bundled.ts"; console.log(BUNDLED_MANIFESTS.length)') | |
| echo "providers found: $found of $total" | |
| if [ "$found" -ne "$total" ]; then | |
| echo "::error::The compiled binary reports $found of $total providers." | |
| echo "The bundled manifests did not survive compilation - see packages/daemon/src/providers/bundled.ts" | |
| ./${{ matrix.asset }} providers list | |
| exit 1 | |
| fi | |
| # A binary that cannot be the daemon is not a release, it is a crash loop | |
| # with a version number. | |
| # | |
| # `pew2 service install` wrote a plist naming `pew2 run /$bunfs/server.ts` | |
| # - a subcommand that did not exist, pointing at a path inside the | |
| # executable's own virtual filesystem. launchd started it, pew2 printed | |
| # its help and exited 1, KeepAlive restarted it for ever, and `pew2 setup` | |
| # reported the daemon unreachable with no hint why. Every binary install | |
| # shipped that way; only people running from a source checkout, whose | |
| # plist named a real server.ts, ever had a working daemon. | |
| # | |
| # `providers list` passed the whole time, because listing manifests never | |
| # touches the server module - so this asks the one question that failed: | |
| # does the daemon actually come up and answer. | |
| - name: Verify the binary can run the daemon | |
| if: matrix.target == 'bun-linux-x64' | |
| run: | | |
| set -u | |
| PEW2_HOME=$(mktemp -d) PEW2_PORT=8791 ./${{ matrix.asset }} serve > serve.log 2>&1 & | |
| pid=$! | |
| ok=0 | |
| for _ in $(seq 1 30); do | |
| if curl -fsS -o /dev/null http://127.0.0.1:8791/health; then ok=1; break; fi | |
| # A dead process will never start answering, so stop waiting on one. | |
| kill -0 "$pid" 2>/dev/null || break | |
| sleep 1 | |
| done | |
| kill "$pid" 2>/dev/null || true | |
| if [ "$ok" -ne 1 ]; then | |
| echo "::error::The compiled binary cannot run the daemon." | |
| echo "'pew2 serve' never answered /health - a plist pointing at it would crash-loop." | |
| cat serve.log | |
| exit 1 | |
| fi | |
| echo "daemon answered /health" | |
| - name: Checksum | |
| run: sha256sum ${{ matrix.asset }} > ${{ matrix.asset }}.sha256 | |
| - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 | |
| with: | |
| name: ${{ matrix.asset }} | |
| path: | | |
| ${{ matrix.asset }} | |
| ${{ matrix.asset }}.sha256 | |
| publish: | |
| needs: build | |
| # `always()` so a single target cannot hold the release hostage. | |
| # | |
| # `needs` waits for every matrix job whatever `fail-fast` says, and the jobs | |
| # do not fail evenly: during a GitHub Actions incident the scarcer runner | |
| # pools (linux-arm64 especially) sit queued for hours while the rest build in | |
| # fifteen seconds. That blocked `curl | sh` on Mac and Windows for an entire | |
| # evening over a Linux ARM binary that almost nobody downloads. | |
| # | |
| # The guard against publishing rubble is the explicit check below, which is a | |
| # better rule than "every target succeeded" anyway: what matters is that the | |
| # platforms the install scripts fetch are actually present. | |
| if: always() && startsWith(github.ref, 'refs/tags/') | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4 | |
| with: | |
| path: dist | |
| merge-multiple: true | |
| # Which assets a release cannot go out without. | |
| # | |
| # These are the ones `install.sh` and `install.ps1` resolve by name, so a | |
| # release missing any of them is not a partial release, it is a broken | |
| # install command for everyone on that platform. Linux ARM is deliberately | |
| # absent: it has no installer path of its own and is a download people | |
| # reach for by hand. | |
| - name: Require the platforms the installers fetch | |
| run: | | |
| missing="" | |
| for asset in pew2-darwin-arm64 pew2-darwin-x64 pew2-linux-x64 pew2-windows-x64.exe; do | |
| if [ ! -f "dist/$asset" ] || [ ! -f "dist/$asset.sha256" ]; then | |
| missing="$missing $asset" | |
| fi | |
| done | |
| if [ -n "$missing" ]; then | |
| echo "::error::Refusing to publish without:$missing" | |
| echo "The install scripts fetch these by name, so a release without one" | |
| echo "is a broken install command rather than a smaller release." | |
| exit 1 | |
| fi | |
| echo "Publishing:" | |
| ls -1 dist | |
| # The install scripts read from `/releases/latest/download/<name>`, so the | |
| # asset names are effectively an API: renaming one breaks every install | |
| # command already published. | |
| - name: Publish | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| gh release create "${{ github.ref_name }}" \ | |
| --title "${{ github.ref_name }}" \ | |
| --generate-notes \ | |
| dist/* |