fix: split preview workflow so fork PRs can deploy to gh-pages#906
Conversation
The previous single `preview.yml` ran entirely under the `pull_request` event, which gives forks a read-only GITHUB_TOKEN — causing the gh-pages push to fail with a 403. The fix uses the standard two-workflow pattern: - `preview.yml` (renamed name: "Quarto Preview Build") runs on `pull_request` with `contents: read`. It builds the site and uploads a `pr-preview-site` artifact containing the rendered site plus PR metadata (PR number, deploy/remove action). - `preview-deploy.yml` triggers via `workflow_run` on completion of the build workflow. It runs in the base-repo context (full write access), downloads the artifact, and pushes to gh-pages / posts PR comments. The PR number is embedded in the artifact (`meta/pr-number.txt`) because `github.event.workflow_run.pull_requests` is empty for fork PRs. https://claude.ai/code/session_01CjeVhx6eX7p8W5kLdmMNht
|
Claude finished @d-morrison's task in 3m 20s —— View job Code Review: PR #906 — Split preview workflow for fork PR gh-pages access
Overall verdictThe approach is correct — the Critical bug — artifact path mismatch for remove case
For the # preview.yml:175 (remove case)
path: _preview_upload/meta/
But the deploy workflow always reads: # preview-deploy.yml:34
echo "pr-number=$(cat _preview_download/meta/pr-number.txt)" >> "$GITHUB_OUTPUT"After download to Fix: Change - path: _preview_upload/meta/
+ path: _preview_upload/Because Minor —
|
- Fix critical path mismatch: upload `_preview_upload/` (not `_preview_upload/meta/`) for the remove case so the artifact preserves the `meta/` subdirectory that preview-deploy.yml expects - Add `mkdir -p _preview_upload/site/` before `cp` to avoid relying on GNU cp's implicit directory creation - Remove redundant "Delete old preview comment" step; `recreate: true` on the following step already handles delete-then-create https://claude.ai/code/session_01CjeVhx6eX7p8W5kLdmMNht
|
Claude finished @d-morrison's task in 3m 56s —— View job Code Review: PR #906 — Split preview workflow for fork PR gh-pages access
Status of prior findings (commit
|
- Add concurrency group to preview-deploy.yml using head_repository.id + head_branch to serialize gh-pages pushes for the same PR branch and avoid non-fast-forward failures from concurrent deploy runs; cancel-in-progress: false queues rather than kills to avoid mid-push corruption - Guard "Remove preview comment" on deployment-action == 'remove' so the comment only fires when rossjrw/pr-preview-action actually removed a preview (not when closing a PR that never had one) - Remove preview-deploy.yml from the paths filter in preview.yml; changes to the deploy workflow alone don't require a Quarto rebuild https://claude.ai/code/session_01CjeVhx6eX7p8W5kLdmMNht
|
Claude finished @d-morrison's task in 2m 40s —— View job Code Review: PR #906 — Split preview workflow for fork PR gh-pages access
Status of prior findings (commit
|
echo does not interpret \n as a newline on bash without -e. Carried over from the original preview.yml. https://claude.ai/code/session_01CjeVhx6eX7p8W5kLdmMNht
|
Claude finished @d-morrison's task in 3m 3s —— View job Code Review: PR #906 — Split preview workflow for fork PR gh-pages access
Status of all prior findingsAll findings from rounds 1–3 are confirmed resolved in the current code:
New findingsMinor — Deploy workflow fires on skipped-build runs, artifact download fails
When a PR with matching The fix is to add an early-exit job or use the Observation —
|
When all jobs in a workflow are skipped (e.g. an unrecognized label on a PR that touches preview paths), GitHub still reports workflow conclusion == 'success'. Without a guard, the deploy workflow fires and fails on artifact download. Introduce a cheap `gate` job that checks via the GitHub API whether the pr-preview-site artifact was actually uploaded. The `deploy` job only runs when `gate` outputs `has-artifact: true`, so skipped-build runs produce a clean no-op rather than a noisy failure. https://claude.ai/code/session_01CjeVhx6eX7p8W5kLdmMNht
|
Claude finished @d-morrison's task in 6m 2s —— View job Code Review: PR #906 — Split preview workflow for fork PR gh-pages access
Status of all prior findings (rounds 1–4)All findings from rounds 1–4 are confirmed resolved in the current code:
New findingsMinor —
|
rossjrw/pr-preview-action outputs deployment-action: 'deploy' on first deploy and 'update' on refreshes. The previous condition (== 'deploy') silently skipped the comment step on every subsequent push, leaving the 'Built at' timestamp stale. Changing to != 'none' updates the comment on both deploy and update, while still suppressing it when no action was taken. https://claude.ai/code/session_01CjeVhx6eX7p8W5kLdmMNht
|
Claude finished @d-morrison's task in 2m 15s —— View job Code Review: PR #906 — Split preview workflow for fork PR gh-pages access
Status of all prior findings (rounds 1–5)All findings through round 5 are confirmed resolved in the current code:
New findingsNo new critical, medium, or minor issues found. Carry-over informational items (unchanged, not blockers)Informational — Gate job The GitHub API returns up to 30 items per page by default. In practice a single build run will never accumulate more than 1 artifact with this name, so this is a non-issue in any realistic scenario. Fix this → Informational — Floating version tags in privileged deploy workflow (
Observation — Stale preview on edge-case close ( The Overall verdictThe design is correct, the security posture is sound, and all critical/medium/minor findings from all prior rounds are resolved. The |
|
Claude finished @d-morrison's task in 2m 21s —— View job Code Review: PR #906 — Split preview workflow for fork PR gh-pages access
Status of all prior findings (rounds 1–5)All findings from the six prior review rounds are confirmed resolved in the merged code:
New findingsNo new critical or medium issues found. The security posture is sound: PR metadata is written before Informational — Floating version tags in privileged deploy workflow (carry-over from R3)
Informational —
|
2026-06-16 17:06 UTC |
Summary
preview.ymlran entirely underpull_request, giving fork PRs a read-onlyGITHUB_TOKENthat can't push togh-pages(403 error seen in PR #846).workflow_runpattern:preview.yml(name: Quarto Preview Build) — triggers onpull_request,contents: readonly. Builds the site and uploads apr-preview-siteartifact with the rendered site + PR metadata (meta/pr-number.txt,meta/action.txt).preview-deploy.yml(name: Quarto Preview Deploy) — triggers viaworkflow_runon build completion. Runs in the base-repo context withcontents: write, downloads the artifact, pushes togh-pages, and posts PR comments.github.event.workflow_run.pull_requestsis empty for fork PRs (GitHub strips it for security).Test plan
Quarto Preview Buildpasses andQuarto Preview Deploysuccessfully pushes the preview and posts the preview URL commenthttps://claude.ai/code/session_01CjeVhx6eX7p8W5kLdmMNht
Generated by Claude Code