Skip to content

PR review binaries link #14

PR review binaries link

PR review binaries link #14

name: PR review binaries link
# 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
# post. workflow_run runs in the base-repo context with a writable token.
# 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/<id>/artifacts/<id> 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]
types: [completed]
permissions:
contents: read
pull-requests: write
jobs:
comment:
if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'
runs-on: ubuntu-latest
steps:
- name: find the PR and comment
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
RUN_ID: ${{ github.event.workflow_run.id }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
run: |
set -euo pipefail
# workflow_run.pull_requests is empty for fork PRs, so resolve the
# PR from the head SHA instead.
pr=$(gh api "repos/$REPO/commits/$HEAD_SHA/pulls" \
--jq '[.[] | select(.state == "open")][0].number // empty')
if [ -z "$pr" ]; then
echo "no open PR for $HEAD_SHA; nothing to comment on"
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 <<EOF
### Try this PR without building it
Review binaries for commit \`${HEAD_SHA:0:7}\` — direct download, no login required:
| Platform | Download |
|---|---|
${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 <file>\`.
<sub>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.</sub>
EOF
)
body=$(printf '%s\n' "$body" | sed 's/^ //')
# Sticky: edit our previous comment rather than stacking one per push.
# --edit-last fails when there's nothing to edit, so fall back to new.
gh pr comment "$pr" --repo "$REPO" --edit-last --body "$body" \
|| gh pr comment "$pr" --repo "$REPO" --body "$body"