From d66e7a549e6a29f93e2870003392c13c052e1453 Mon Sep 17 00:00:00 2001 From: Simone Bortolin Date: Fri, 9 Oct 2026 18:35:46 +0200 Subject: [PATCH] Build PR previews on pull_request and publish them on workflow_run preview-pr now runs on pull_request, so the PR code is built with no secrets and a read-only token, and no longer needs pull_request_target, which GitHub restricts by default from November 2, 2026. preview-deploy runs from the default branch: after the manual approval for forks it checks that the PR number matches the built commit, uploads the built files to Cloudflare Pages and comments the link on the PR. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/preview-deploy.yaml | 69 +++++++++++++++++++++++++++ .github/workflows/preview-pr.yaml | 45 ++++------------- 2 files changed, 78 insertions(+), 36 deletions(-) create mode 100644 .github/workflows/preview-deploy.yaml diff --git a/.github/workflows/preview-deploy.yaml b/.github/workflows/preview-deploy.yaml new file mode 100644 index 00000000..254bfd56 --- /dev/null +++ b/.github/workflows/preview-deploy.yaml @@ -0,0 +1,69 @@ +# Publish the site built by preview-pr.yaml to Cloudflare Pages. It runs from +# the default branch with the secrets, and never runs the PR code: it only +# uploads the files built by preview-pr.yaml. +name: preview-deploy + +on: + workflow_run: + workflows: [preview-pr] + types: [completed] + +permissions: + contents: read + +jobs: + # PRs from forks wait for a manual approval of the "external" environment + authorize: + if: github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success' + environment: + ${{ github.event.workflow_run.head_repository.full_name != github.repository && + 'external' || 'internal' }} + runs-on: ubuntu-latest + steps: + - run: "true" + + deploy: + needs: authorize + runs-on: ubuntu-latest + permissions: + actions: read + pull-requests: write + # Shows the preview link on the job, like the Pages deploy + environment: + name: preview + url: ${{ steps.preview-pages.outputs.deployment-url }} + env: + GH_TOKEN: ${{ github.token }} + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + run-id: ${{ github.event.workflow_run.id }} + github-token: ${{ github.token }} + # The artifacts come from the PR code: make sure the number is really + # the PR of the commit that was built + - name: Find the PR + id: pr + env: + HEAD_SHA: ${{ github.event.workflow_run.head_sha }} + run: | + number=$(cat pr-number/pr-number) + [[ "$number" =~ ^[0-9]+$ ]] || { echo "Invalid PR number"; exit 1; } + sha=$(gh api "repos/$GITHUB_REPOSITORY/pulls/$number" --jq .head.sha) + [[ "$sha" == "$HEAD_SHA" ]] || { echo "PR #$number is not at $HEAD_SHA"; exit 1; } + echo "number=$number" >> "$GITHUB_OUTPUT" + - name: Extract site + run: mkdir dist && tar -xf github-pages/artifact.tar -C dist + - name: Publish to Cloudflare Pages + id: preview-pages + uses: cloudflare/wrangler-action@v3 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT }} + command: pages deploy dist --project-name=hack-gpon-preview --branch=preview + - name: Comment on the PR + env: + URL: ${{ steps.preview-pages.outputs.deployment-url }} + run: | + gh pr comment "${{ steps.pr.outputs.number }}" --repo "$GITHUB_REPOSITORY" \ + --body "Preview of the website obtained from the PR: $URL" diff --git a/.github/workflows/preview-pr.yaml b/.github/workflows/preview-pr.yaml index 4e35c168..cb1b8e53 100644 --- a/.github/workflows/preview-pr.yaml +++ b/.github/workflows/preview-pr.yaml @@ -1,53 +1,26 @@ +# Build the site of a PR. It runs the PR code, so it has no secrets and a +# read-only token: preview-deploy.yaml publishes the result. name: preview-pr on: - pull_request_target: + pull_request: types: [opened, reopened, synchronize] permissions: contents: read jobs: - authorize: - environment: - ${{ github.event_name == 'pull_request_target' && - github.event.pull_request.head.repo.full_name != github.repository && - 'external' || 'internal' }} - runs-on: ubuntu-latest - steps: - - run: "true" - - # The PR code is built without access to any secret build: - needs: authorize uses: ./.github/workflows/build.yml with: ref: ${{ github.event.pull_request.head.sha }} - deploy: - needs: build + # Tells preview-deploy.yaml which PR to comment on + pr-number: runs-on: ubuntu-latest - permissions: - pull-requests: write - # Shows the preview link on the job and in the PR, like the Pages deploy - environment: - name: preview - url: ${{ steps.preview-pages.outputs.deployment-url }} steps: - - name: Download artifact - uses: actions/download-artifact@v4 - with: - name: github-pages - - name: Extract site - run: mkdir dist && tar -xf artifact.tar -C dist - - name: Publish to Cloudflare Pages - id: preview-pages - uses: cloudflare/wrangler-action@v3 - with: - apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} - accountId: ${{ secrets.CLOUDFLARE_ACCOUNT }} - command: pages deploy dist --project-name=hack-gpon-preview --branch=preview - - uses: thollander/actions-comment-pull-request@v2 + - run: echo "${{ github.event.pull_request.number }}" > pr-number + - uses: actions/upload-artifact@v4 with: - message: | - Preview of the website obtained from the PR: ${{ steps.preview-pages.outputs.deployment-url }} + name: pr-number + path: pr-number