name: PR Preview on: pull_request: types: [opened, reopened, synchronize, closed, ready_for_review] paths: - 'content/**' - 'layouts/**' - 'assets/**' - 'data/**' - 'api-docs/**' - 'openapi/**' permissions: contents: write pull-requests: write statuses: write concurrency: group: pr-preview-${{ github.event.number }} cancel-in-progress: true jobs: # Skip draft PRs entirely check-draft: runs-on: ubuntu-latest outputs: should-run: ${{ steps.check.outputs.should-run }} steps: - id: check run: | if [[ "${{ github.event.pull_request.draft }}" == "true" ]]; then echo "should-run=false" >> $GITHUB_OUTPUT echo "Skipping draft PR" else echo "should-run=true" >> $GITHUB_OUTPUT fi # Notify fork PRs that preview is not available fork-notice: needs: check-draft if: | needs.check-draft.outputs.should-run == 'true' && github.event.action != 'closed' && github.event.pull_request.head.repo.full_name != github.repository runs-on: ubuntu-latest steps: - name: Post fork notice comment uses: actions/github-script@v7 with: script: | const { data: comments } = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number }); const marker = ''; const existing = comments.find(c => c.body.includes(marker)); if (!existing) { await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.issue.number, body: `${marker}\n## 📝 PR Preview Not Available\n\nPR previews are not available for pull requests from forks due to GitHub Actions security restrictions.\n\nTo preview your changes locally, run:\n\`\`\`bash\nnpx hugo server\n\`\`\`\n\nOnce merged, your changes will be visible on the production site.` }); } # Build and deploy preview preview: needs: check-draft # Skip fork PRs - GITHUB_TOKEN doesn't have write access to push to gh-pages if: | needs.check-draft.outputs.should-run == 'true' && github.event.action != 'closed' && github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'yarn' - name: Install dependencies run: yarn install --frozen-lockfile - name: Set preview status (pending) uses: actions/github-script@v7 with: script: | await github.rest.repos.createCommitStatus({ owner: context.repo.owner, repo: context.repo.repo, sha: context.sha, state: 'pending', context: 'preview/deploy', description: 'Building preview...', }); - name: Detect preview pages id: detect env: PR_BODY: ${{ github.event.pull_request.body }} BASE_REF: origin/${{ github.base_ref }} run: | if ! node .github/scripts/detect-preview-pages.js; then echo "::warning::detect-preview-pages.js failed — skipping preview." echo "pages-to-deploy=[]" >> "$GITHUB_OUTPUT" echo "has-api-doc-changes=false" >> "$GITHUB_OUTPUT" echo "has-layout-changes=false" >> "$GITHUB_OUTPUT" echo "needs-author-input=false" >> "$GITHUB_OUTPUT" echo "change-summary=Detection failed (possible merge conflicts)" >> "$GITHUB_OUTPUT" fi - name: Post pending comment (needs input) if: steps.detect.outputs.needs-author-input == 'true' uses: actions/github-script@v7 with: script: | const { upsertPreviewComment } = await import('${{ github.workspace }}/.github/scripts/preview-comment.js'); await upsertPreviewComment(github, context, { status: 'pending', needsInput: true, prNumber: context.issue.number }); - name: Skip if no pages to deploy if: steps.detect.outputs.pages-to-deploy == '[]' run: | echo "No pages to deploy - skipping preview" echo "Reason: ${{ steps.detect.outputs.skip-reason || steps.detect.outputs.change-summary }}" - name: Build API documentation scripts if: steps.detect.outputs.has-api-doc-changes == 'true' && steps.detect.outputs.pages-to-deploy != '[]' run: yarn build:api-docs:scripts - name: Build API docs if: steps.detect.outputs.has-api-doc-changes == 'true' && steps.detect.outputs.pages-to-deploy != '[]' run: yarn run build:api-docs - name: Build Hugo site if: steps.detect.outputs.pages-to-deploy != '[]' id: build env: # Set baseURL for GitHub Pages preview subdirectory PREVIEW_BASE_URL: https://influxdata.github.io/docs-v2/pr-preview/pr-${{ github.event.number }}/ run: | START_TIME=$(date +%s) # Use pr-preview environment for path offset config npx hugo --minify --baseURL "$PREVIEW_BASE_URL" -e pr-preview END_TIME=$(date +%s) DURATION=$((END_TIME - START_TIME)) echo "build-time=${DURATION}s" >> $GITHUB_OUTPUT - name: Prepare preview files if: steps.detect.outputs.pages-to-deploy != '[]' run: | node .github/scripts/prepare-preview-files.js \ '${{ steps.detect.outputs.pages-to-deploy }}' \ public \ preview-staging - name: Deploy preview if: steps.detect.outputs.pages-to-deploy != '[]' id: deploy-preview continue-on-error: true uses: rossjrw/pr-preview-action@v1.4.8 with: source-dir: ./preview-staging preview-branch: gh-pages umbrella-dir: pr-preview action: deploy - name: Validate preview deployment if: steps.detect.outputs.pages-to-deploy != '[]' id: validate-deploy run: | DEPLOY_OUTCOME="${{ steps.deploy-preview.outcome }}" DEPLOY_URL="${{ steps.deploy-preview.outputs.deployment-url }}" if [ -z "$DEPLOY_URL" ]; then echo "Deployment step did not produce a preview URL. Failing preview job." exit 1 fi if [ "$DEPLOY_OUTCOME" != "success" ]; then echo "Deployment reported outcome: $DEPLOY_OUTCOME" echo "Preview URL exists; treating as transient post-deploy comment error." fi echo "status=ok" >> "$GITHUB_OUTPUT" - name: Set preview status (success) if: steps.validate-deploy.outputs.status == 'ok' uses: actions/github-script@v7 with: script: | const previewUrl = `https://influxdata.github.io/docs-v2/pr-preview/pr-${context.issue.number}/`; await github.rest.repos.createCommitStatus({ owner: context.repo.owner, repo: context.repo.repo, sha: context.sha, state: 'success', context: 'preview/deploy', description: 'Preview deployed', target_url: previewUrl, }); - name: Set preview status (skipped/failed) if: >- always() && steps.detect.outcome == 'success' && (steps.validate-deploy.outputs.status != 'ok' || steps.detect.outputs.pages-to-deploy == '[]') uses: actions/github-script@v7 with: script: | const description = '${{ steps.detect.outputs.pages-to-deploy }}' === '[]' ? 'No pages to preview' : 'Preview deployment failed'; await github.rest.repos.createCommitStatus({ owner: context.repo.owner, repo: context.repo.repo, sha: context.sha, state: 'failure', context: 'preview/deploy', description, }); - name: Post success comment if: steps.detect.outputs.pages-to-deploy != '[]' && steps.validate-deploy.outputs.status == 'ok' uses: actions/github-script@v7 with: script: | const { upsertPreviewComment } = await import('${{ github.workspace }}/.github/scripts/preview-comment.js'); const pages = JSON.parse('${{ steps.detect.outputs.pages-to-deploy }}'); const previewUrl = `https://influxdata.github.io/docs-v2/pr-preview/pr-${{ github.event.number }}/`; await upsertPreviewComment(github, context, { status: 'success', previewUrl, pages, buildTime: '${{ steps.build.outputs.build-time }}', prNumber: context.issue.number }); - name: Post skipped comment if: steps.detect.outputs.pages-to-deploy == '[]' && steps.detect.outputs.needs-author-input != 'true' uses: actions/github-script@v7 with: script: | const { upsertPreviewComment } = await import('${{ github.workspace }}/.github/scripts/preview-comment.js'); await upsertPreviewComment(github, context, { status: 'skipped', skipReason: '${{ steps.detect.outputs.change-summary }}', prNumber: context.issue.number }); # Cleanup on PR close cleanup: if: github.event.action == 'closed' runs-on: ubuntu-latest steps: - name: Checkout gh-pages uses: actions/checkout@v4 with: ref: gh-pages - name: Remove preview directory run: | PREVIEW_DIR="pr-preview/pr-${{ github.event.number }}" if [ -d "$PREVIEW_DIR" ]; then rm -rf "$PREVIEW_DIR" git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" git add -A git commit -m "Clean up preview for PR #${{ github.event.number }}" || echo "Nothing to commit" git push echo "Cleaned up $PREVIEW_DIR" else echo "No preview directory found for PR #${{ github.event.number }}" fi - name: Checkout scripts for comment deletion uses: actions/checkout@v4 with: path: scripts-checkout - name: Delete preview comment uses: actions/github-script@v7 with: script: | const { deletePreviewComment } = await import('${{ github.workspace }}/scripts-checkout/.github/scripts/preview-comment.js'); await deletePreviewComment(github, context);