From 60b23dbb0fa554994efb6a07d98a8a71706b25f9 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Tue, 1 Sep 2026 11:17:03 +0800 Subject: [PATCH] fix(preview): make Pages own website build - use Website checks only as the orchestration gate - checkout and build the exact pull-request head in Pages preview - remove CI preview artifact production --- .github/workflows/pages-preview.yml | 113 ++++++---------------------- .github/workflows/website-check.yml | 9 --- website/README.md | 17 +++-- 3 files changed, 32 insertions(+), 107 deletions(-) diff --git a/.github/workflows/pages-preview.yml b/.github/workflows/pages-preview.yml index c937df5..ef08ee3 100644 --- a/.github/workflows/pages-preview.yml +++ b/.github/workflows/pages-preview.yml @@ -24,7 +24,6 @@ jobs: branch: ${{ steps.identity.outputs.branch }} head_sha: ${{ steps.identity.outputs.head_sha }} pull_number: ${{ steps.identity.outputs.pull_number }} - run_id: ${{ steps.identity.outputs.run_id }} steps: - name: Resolve exact internal pull request id: identity @@ -38,7 +37,7 @@ jobs: run_id: runId, }) if (run.name !== 'Website checks' || run.path !== '.github/workflows/website-check.yml') { - core.setFailed('Preview artifact must come from the trusted Website checks workflow.') + core.setFailed('Preview must be orchestrated by the trusted Website checks workflow.') return } if (run.conclusion !== 'success' || run.event !== 'pull_request') { @@ -69,7 +68,6 @@ jobs: core.setOutput('branch', `preview/docs/pr-${pull.number}`) core.setOutput('head_sha', run.head_sha) core.setOutput('pull_number', String(pull.number)) - core.setOutput('run_id', String(runId)) deploy: name: Deploy isolated pull-request preview @@ -78,12 +76,13 @@ jobs: group: pages-preview-docs-${{ needs.identity.outputs.pull_number }} cancel-in-progress: true permissions: - actions: read contents: read deployments: write - pull-requests: read runs-on: ubuntu-latest timeout-minutes: 15 + environment: + name: preview + url: ${{ steps.pages.outputs.pages-deployment-alias-url }} steps: - name: Checkout the trusted preview controller uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -92,73 +91,29 @@ jobs: path: controller persist-credentials: false - - name: Set up Node - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 + - name: Checkout the exact pull-request head + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - node-version-file: controller/website/package.json + ref: ${{ needs.identity.outputs.head_sha }} + path: candidate + persist-credentials: false - - name: Download the exact checked artifact - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + - name: Install the pinned pnpm release + uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 with: - name: inkcre-website-dist - path: .pages-preview/dist - run-id: ${{ needs.identity.outputs.run_id }} - github-token: ${{ secrets.GITHUB_TOKEN }} + package_json_file: candidate/website/package.json - - name: Reverify pull-request identity before delivery - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - PREVIEW_BRANCH: ${{ needs.identity.outputs.branch }} - PREVIEW_HEAD_SHA: ${{ needs.identity.outputs.head_sha }} - PULL_NUMBER: ${{ needs.identity.outputs.pull_number }} + - name: Set up Node + uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 with: - script: | - const expectedBranch = `preview/docs/pr-${process.env.PULL_NUMBER}` - if (process.env.PREVIEW_BRANCH !== expectedBranch) { - core.setFailed(`Unexpected Pages preview branch: ${process.env.PREVIEW_BRANCH}`) - return - } - const { data: pull } = await github.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: Number(process.env.PULL_NUMBER), - }) - if ( - pull.state !== 'open' || - pull.base.ref !== 'main' || - pull.head.sha !== process.env.PREVIEW_HEAD_SHA || - pull.head.repo?.full_name !== `${context.repo.owner}/${context.repo.repo}` - ) { - core.setFailed('Pull-request identity changed after artifact selection.') - } + node-version-file: candidate/website/package.json + cache: pnpm + cache-dependency-path: candidate/website/pnpm-lock.yaml - - name: Register the pull-request deployment - id: github-deployment - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - PREVIEW_HEAD_SHA: ${{ needs.identity.outputs.head_sha }} - PULL_NUMBER: ${{ needs.identity.outputs.pull_number }} - with: - script: | - const { data: deployment } = await github.rest.repos.createDeployment({ - owner: context.repo.owner, - repo: context.repo.repo, - ref: process.env.PREVIEW_HEAD_SHA, - environment: 'preview', - description: `Cloudflare Pages preview for PR #${process.env.PULL_NUMBER}`, - auto_merge: false, - required_contexts: [], - transient_environment: true, - production_environment: false, - }) - core.setOutput('deployment_id', String(deployment.id)) - await github.rest.repos.createDeploymentStatus({ - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: deployment.id, - state: 'in_progress', - log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, - }) + - name: Build the exact-head website preview + run: | + pnpm --dir candidate/website install --frozen-lockfile + pnpm --dir candidate/website check - name: Deploy to the isolated Pages preview branch id: pages @@ -168,9 +123,9 @@ jobs: accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} packageManager: npm wranglerVersion: 4.114.0 - workingDirectory: .pages-preview + workingDirectory: candidate/website command: >- - pages deploy dist + pages deploy .vitepress/dist --project-name=${{ vars.CLOUDFLARE_PAGES_PROJECT }} --branch=${{ needs.identity.outputs.branch }} --commit-hash=${{ needs.identity.outputs.head_sha }} @@ -182,25 +137,3 @@ jobs: CLOUDFLARE_PAGES_DEPLOYMENT_ID: ${{ steps.pages.outputs.pages-deployment-id }} CLOUDFLARE_PAGES_DEPLOYMENT_URL: ${{ steps.pages.outputs.pages-deployment-alias-url }} INKCRE_PAGES_SMOKE_MODE: preview - - - name: Report the pull-request deployment - if: ${{ always() && steps.github-deployment.outputs.deployment_id != '' }} - uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 - env: - DEPLOYMENT_ID: ${{ steps.github-deployment.outputs.deployment_id }} - JOB_STATUS: ${{ job.status }} - PREVIEW_URL: ${{ steps.pages.outputs.pages-deployment-alias-url }} - with: - script: | - const success = process.env.JOB_STATUS === 'success' - await github.rest.repos.createDeploymentStatus({ - owner: context.repo.owner, - repo: context.repo.repo, - deployment_id: Number(process.env.DEPLOYMENT_ID), - state: success ? 'success' : 'failure', - description: success ? 'Pull-request preview is ready' : 'Pull-request preview failed', - log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, - ...(success && process.env.PREVIEW_URL - ? { environment_url: process.env.PREVIEW_URL } - : {}), - }) diff --git a/.github/workflows/website-check.yml b/.github/workflows/website-check.yml index 4a8ef13..d117ecb 100644 --- a/.github/workflows/website-check.yml +++ b/.github/workflows/website-check.yml @@ -44,12 +44,3 @@ jobs: - name: Verify the website contract run: pnpm --dir website check - - - name: Upload the checked preview artifact - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 - with: - name: inkcre-website-dist - path: website/.vitepress/dist - if-no-files-found: error - include-hidden-files: true - retention-days: 7 diff --git a/website/README.md b/website/README.md index fdc8243..d3a8492 100644 --- a/website/README.md +++ b/website/README.md @@ -65,14 +65,15 @@ an artificial Hub mirror. `Website checks` validates pull-request candidates and supports manual diagnostics. It proves that the website can be built and that the generated site satisfies the repository contract, but it owns -neither the canonical production artifact nor production delivery. A successful same-repository pull -request may hand its checked artifact to a trusted controller for an isolated, deterministic, -short-lived preview. Fork pull requests receive no preview credentials, preview origins remain -`noindex`, and closing the pull request replaces the live preview with a trusted closed-preview -tombstone. The stable `preview-docs-pr-N` branch alias is the user-facing preview URL and is -recorded against the pull-request head in GitHub; Cloudflare retains the underlying immutable -deployments in its history. If automatic retirement fails, the cleanup workflow can be run manually -for the closed pull-request number. A preview artifact is never promoted to production. +neither a preview delivery input nor canonical production delivery. After a successful +same-repository run, the trusted Preview workflow checks out that exact head, builds it itself, and +publishes an isolated, deterministic, short-lived preview. Fork pull requests receive no preview +credentials, preview origins remain `noindex`, and closing the pull request replaces the live +preview with a trusted closed-preview tombstone. The stable `preview-docs-pr-N` branch alias is the +user-facing preview URL and is recorded against the pull-request head in GitHub; Cloudflare retains +the underlying immutable deployments in its history. If automatic retirement fails, the cleanup +workflow can be run manually for the closed pull-request number. A preview build is never promoted +to production. Protected `main` is the publication authority. `Pages deployment` runs for a push to `main`; failed runs can be rerun for the same commit, while rollback starts by reverting `main` through a pull