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.