From cbda861ae73b39505e4b3b01bcf7f4e19d36c379 Mon Sep 17 00:00:00 2001 From: DTTerastar Date: Mon, 20 Jul 2026 22:54:44 -0400 Subject: [PATCH] ci: real download links on PRs via nightly.link, one artifact per platform MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The previous comment linked the Actions run page, which is not a download link: the reader still has to find the right row, and GitHub's per-artifact URL (/actions/runs//artifacts/) only resolves with browser session cookies — a token gets a 404 — so it does nothing for a logged-out visitor. GitHub exposes no anonymous artifact URL at all. nightly.link is a third-party redirector that resolves an artifact to an anonymous, no-login download. Verified against the existing artifact: an unauthenticated curl returns 200 and a valid 13.8MB zip. Public repos need no app install (installing it only avoids sharing a global API rate limit, worth doing separately if these links get traffic). Also splits the single bundle into one artifact per platform, so each link is one binary. A Windows user was downloading 33MB of Linux and macOS binaries to get a 6MB .exe. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_013JJnPtEtP97to9Rv2QMoer --- .github/workflows/ci.yml | 30 ++++++++---- .github/workflows/pr-review-binaries.yml | 58 +++++++++++++++++------- 2 files changed, 61 insertions(+), 27 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 628aa56..f2b99c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,10 +49,21 @@ jobs: artifacts: # Cross-compile review binaries for the platforms reviewers actually use. # Goreleaser owns tagged releases; this job exists so a PR's diff can be - # tried end-to-end without a local Go toolchain — download from the run - # page, chmod +x, run. Retention is short (14d) to keep storage tidy. - name: review binaries + # tried end-to-end without a local Go toolchain. + # + # One artifact per platform, not one bundle: the PR comment links each + # artifact directly, and a Windows user shouldn't download 33MB of Linux + # and macOS binaries to get their 6MB .exe. + name: review binary (${{ matrix.goos }}/${{ matrix.goarch }}) runs-on: ubuntu-latest + strategy: + matrix: + include: + - { goos: darwin, goarch: arm64 } + - { goos: darwin, goarch: amd64 } + - { goos: linux, goarch: amd64 } + - { goos: linux, goarch: arm64 } + - { goos: windows, goarch: amd64, ext: .exe } steps: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 @@ -60,18 +71,17 @@ jobs: go-version-file: go.mod cache: true - name: cross-compile + env: + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} run: | mkdir -p dist - for target in darwin/arm64 darwin/amd64 linux/amd64 linux/arm64 windows/amd64; do - os="${target%/*}"; arch="${target#*/}" - ext=""; [ "$os" = "windows" ] && ext=".exe" - GOOS=$os GOARCH=$arch go build -trimpath -ldflags="-s -w" \ - -o "dist/liftoff-export-${os}-${arch}${ext}" . - done + go build -trimpath -ldflags="-s -w" \ + -o "dist/liftoff-export-${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.ext }}" . ls -lh dist/ - uses: actions/upload-artifact@v4 with: - name: liftoff-export + name: liftoff-export-${{ matrix.goos }}-${{ matrix.goarch }} path: dist/ retention-days: 14 if-no-files-found: error diff --git a/.github/workflows/pr-review-binaries.yml b/.github/workflows/pr-review-binaries.yml index feb51a0..4d4f9a6 100644 --- a/.github/workflows/pr-review-binaries.yml +++ b/.github/workflows/pr-review-binaries.yml @@ -1,7 +1,7 @@ name: PR review binaries link -# Posts a download link for the review binaries CI just built, so a PR can be -# tried end-to-end before merge without a local Go toolchain. +# Posts one-click download links for the review binaries CI just built, so a +# PR can be tried end-to-end before merge without a local Go toolchain. # # Why workflow_run and not a step inside CI: contributor PRs come from forks, # and fork PRs get a read-only GITHUB_TOKEN, so a comment step inside CI can't @@ -9,6 +9,13 @@ name: PR review binaries link # It deliberately does NOT check out or execute any PR code — it only reads # the run's metadata and comments — so the writable token never touches # untrusted input. +# +# Why nightly.link: GitHub has no permanent public download URL for an +# artifact. The /actions/runs//artifacts/ endpoint needs browser +# session cookies (a token gets a 404), so a plain link only works for signed-in +# users, and even then only after finding the right row on the run page. +# nightly.link is a third-party redirector that resolves an artifact to an +# anonymous, no-login download. Public repos need no app install. on: workflow_run: workflows: [CI] @@ -41,30 +48,47 @@ jobs: exit 0 fi + # nightly.link addresses artifacts by check-suite, not run. + suite=$(gh api "repos/$REPO/actions/runs/$RUN_ID" --jq '.check_suite_id') + + label() { + case "$1" in + *darwin-arm64*) echo "macOS (Apple silicon)" ;; + *darwin-amd64*) echo "macOS (Intel)" ;; + *linux-amd64*) echo "Linux x86_64" ;; + *linux-arm64*) echo "Linux arm64" ;; + *windows-amd64*) echo "Windows x86_64" ;; + *) echo "$1" ;; + esac + } + + rows="" + while IFS=$'\t' read -r name id; do + [ -n "$name" ] || continue + url="https://nightly.link/$REPO/suites/$suite/artifacts/$id" + rows="${rows}| $(label "$name") | [\`${name}.zip\`]($url) |"$'\n' + done < <(gh api "repos/$REPO/actions/runs/$RUN_ID/artifacts" \ + --jq '.artifacts[] | [.name, .id] | @tsv' | sort) + + if [ -z "$rows" ]; then + echo "run $RUN_ID produced no artifacts; nothing to link" + exit 0 + fi + run_url="https://github.com/$REPO/actions/runs/$RUN_ID" body=$(cat <\`. - - Downloading requires being signed in to GitHub, and artifacts expire 14 days after the run. + ${rows} + Unzip, then on macOS/Linux \`chmod +x\` the binary before running. macOS Gatekeeper blocks unsigned binaries on first run — right-click → Open, or \`xattr -d com.apple.quarantine \`. - Posted automatically. Updated on each push to this PR. + Links are resolved by [nightly.link](https://nightly.link/), a third-party redirector for GitHub Actions artifacts, because GitHub has no anonymous artifact URL of its own. Signed-in users can also [browse the run directly]($run_url#artifacts). Artifacts expire 14 days after the run. Updated on each push to this PR. EOF ) - # Strip the heredoc's leading indentation. body=$(printf '%s\n' "$body" | sed 's/^ //') # Sticky: edit our previous comment rather than stacking one per push.