Docs Preview Deploy #2160
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Docs Preview Deploy | |
| on: | |
| workflow_run: | |
| workflows: ["Docs Preview Build"] | |
| types: [completed] | |
| permissions: | |
| actions: read | |
| contents: read | |
| pull-requests: read | |
| jobs: | |
| deploy: | |
| name: Deploy Docs & Snippets | |
| runs-on: ubuntu-latest | |
| if: ${{ github.event.workflow_run.conclusion == 'success' }} | |
| environment: docs-development | |
| steps: | |
| # Derive PR identity from the trusted workflow_run event, not from build-job artifacts. | |
| - id: meta | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| HEAD_BRANCH: ${{ github.event.workflow_run.head_branch }} | |
| HEAD_SHA: ${{ github.event.workflow_run.head_sha }} | |
| REPO: ${{ github.repository }} | |
| # A single SHA can belong to multiple PRs, so disambiguate by the trusted head branch instead of taking .[0]. | |
| # | |
| # Read the (untrusted) branch via jq's env builtin so it is treated as data. Interpolating $HEAD_BRANCH into | |
| # the jq program would let a branch name containing a double quote break out of the string literal and inject | |
| # jq (e.g. forge pr_number, or read env via the env builtin). | |
| run: | | |
| echo "full_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT" | |
| echo "sha=${HEAD_SHA:0:7}" >> "$GITHUB_OUTPUT" | |
| ESCAPED="${HEAD_BRANCH//\//-}" | |
| echo "branch=$ESCAPED" >> "$GITHUB_OUTPUT" | |
| PR=$(gh api "repos/$REPO/commits/$HEAD_SHA/pulls" \ | |
| --jq 'first(.[] | select(.state == "open" and .head.ref == env.HEAD_BRANCH) | .number)') | |
| echo "pr_number=$PR" >> "$GITHUB_OUTPUT" | |
| # Deploy Snippets | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: docs-snippets-build | |
| path: ./docs-snippets--build | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| run-id: ${{ github.event.workflow_run.id }} | |
| - uses: cloudflare/wrangler-action@v4 | |
| id: publish-docs-snippets | |
| with: | |
| apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| accountId: ${{ vars.CLOUDFLARE_ACCOUNT_ID }} | |
| command: >- | |
| pages deploy ./docs-snippets--build | |
| --project-name=${{ vars.CLOUDFLARE_SNIPPETS_PROJECT_NAME }} | |
| --branch=${{ steps.meta.outputs.branch }}-${{ steps.meta.outputs.sha }} | |
| # Deploy docs | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: main | |
| sparse-checkout: | | |
| docs/package.json | |
| docs/pnpm-lock.yaml | |
| docs/wrangler.jsonc | |
| docs/open-next.config.ts | |
| .github/deployment_preview_template.md | |
| # The docs-build tarball is produced by the untrusted build job, so it can contain arbitrary files. Download it to | |
| # an isolated path (NOT ./docs) and copy only the .open-next directory into place. Extracting it directly into | |
| # ./docs would let it plant a malicious package.json / .pnpmfile.cjs / .npmrc beside the trusted files that the | |
| # later `pnpm install` reads. | |
| - uses: actions/download-artifact@v8 | |
| with: | |
| name: docs-build | |
| path: ./_artifact | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| run-id: ${{ github.event.workflow_run.id }} | |
| - name: Extract docs build in isolation | |
| run: | | |
| mkdir _scratch | |
| tar -xf ./_artifact/docs-build.tar -C _scratch | |
| rm -rf ./docs/.open-next | |
| cp -r _scratch/.open-next ./docs/.open-next | |
| - uses: actions/setup-node@v6 | |
| with: | |
| node-version: 24 | |
| - uses: pnpm/action-setup@v6 | |
| with: | |
| version: 11 | |
| - name: Deploy docs to Cloudflare Workers | |
| id: publish-docs | |
| working-directory: ./docs | |
| env: | |
| CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }} | |
| run: | | |
| pnpm install | |
| set +e | |
| OUTPUT=$(pnpm exec opennextjs-cloudflare upload -- --env dev 2>&1) | |
| EXIT_CODE=$? | |
| echo "$OUTPUT" | |
| PREVIEW_URL=$(echo "$OUTPUT" | grep "Version Preview URL:" | awk '{print $NF}') | |
| echo "preview-url=$PREVIEW_URL" >> $GITHUB_OUTPUT | |
| exit $EXIT_CODE | |
| # Create/update comment with link to preview | |
| - uses: actions/create-github-app-token@v3 | |
| id: generate-token | |
| with: | |
| app-id: ${{ secrets.AUTO_MAID_APP_ID }} | |
| private-key: ${{ secrets.AUTO_MAID_PRIVATE_KEY }} | |
| - uses: peter-evans/find-comment@v4 | |
| id: find-comment | |
| with: | |
| issue-number: ${{ steps.meta.outputs.pr_number }} | |
| comment-author: 'auto-maid[bot]' | |
| - uses: chuhlomin/render-template@v1.12 | |
| id: render-markdown | |
| with: | |
| template: .github/deployment_preview_template.md | |
| vars: | | |
| sha: ${{ steps.meta.outputs.full_sha }} | |
| url: ${{ steps.publish-docs.outputs.preview-url }} | |
| - uses: peter-evans/create-or-update-comment@v5 | |
| with: | |
| token: ${{ steps.generate-token.outputs.token }} | |
| comment-id: ${{ steps.find-comment.outputs.comment-id }} | |
| issue-number: ${{ steps.meta.outputs.pr_number }} | |
| body: ${{ steps.render-markdown.outputs.result }} | |
| edit-mode: replace | |
| # Check that all relative URLs are working | |
| - uses: actions/setup-go@v6 | |
| with: | |
| go-version: '1.26' | |
| - run: go install github.com/raviqqe/muffet/v2@latest | |
| - run: muffet ${{ steps.publish-docs.outputs.preview-url }} --buffer-size=32768 --exclude="(\/cdn-cgi\/)|(github.com)|(pub.dev)|(shadcn.com)" |