Skip to content

Commit 591a0de

Browse files
committed
fix(delivery): expose and retire pull request previews
- attach preview deployments to the pull request head and surface the stable branch alias - allow manual retirement of a closed pull request without reopening it - keep immutable Cloudflare deployments as implementation history
1 parent 8700a8c commit 591a0de

4 files changed

Lines changed: 99 additions & 12 deletions

File tree

.github/workflows/pages-preview-cleanup.yml

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,27 +6,63 @@ on:
66
- main
77
types:
88
- closed
9+
workflow_dispatch:
10+
inputs:
11+
pull_number:
12+
description: Closed pull request whose preview should be retired
13+
required: true
14+
type: number
915

1016
permissions:
1117
contents: read
18+
pull-requests: read
1219

1320
concurrency:
14-
group: pages-preview-docs-${{ github.event.pull_request.number }}
21+
group: pages-preview-docs-${{ github.event.pull_request.number || inputs.pull_number }}
1522
cancel-in-progress: true
1623

1724
jobs:
1825
cleanup:
1926
name: Retire exact pull-request preview
2027
if: >-
21-
github.event.pull_request.base.ref == 'main' &&
28+
github.event_name == 'workflow_dispatch' ||
29+
(github.event.pull_request.base.ref == 'main' &&
2230
github.event.pull_request.base.repo.full_name == github.repository &&
23-
github.event.pull_request.head.repo.full_name == github.repository
31+
github.event.pull_request.head.repo.full_name == github.repository)
2432
runs-on: ubuntu-latest
2533
timeout-minutes: 10
2634
environment:
2735
name: preview
28-
url: ${{ steps.tombstone.outputs.deployment-url }}
36+
url: ${{ steps.tombstone.outputs.pages-deployment-alias-url }}
2937
steps:
38+
- name: Resolve the closed pull request
39+
id: identity
40+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
41+
env:
42+
REQUESTED_PULL_NUMBER: ${{ github.event.pull_request.number || inputs.pull_number }}
43+
with:
44+
script: |
45+
const pullNumber = Number(process.env.REQUESTED_PULL_NUMBER)
46+
if (!Number.isInteger(pullNumber) || pullNumber < 1) {
47+
core.setFailed('A positive pull-request number is required.')
48+
return
49+
}
50+
const { data: pull } = await github.rest.pulls.get({
51+
owner: context.repo.owner,
52+
repo: context.repo.repo,
53+
pull_number: pullNumber,
54+
})
55+
if (
56+
pull.state !== 'closed' ||
57+
pull.base.ref !== 'main' ||
58+
pull.base.repo.full_name !== `${context.repo.owner}/${context.repo.repo}` ||
59+
pull.head.repo?.full_name !== `${context.repo.owner}/${context.repo.repo}`
60+
) {
61+
core.setFailed('Cleanup only accepts a closed same-repository pull request targeting main.')
62+
return
63+
}
64+
core.setOutput('branch', `preview/docs/pr-${pullNumber}`)
65+
3066
- name: Checkout the trusted cleanup controller
3167
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
3268
with:
@@ -51,6 +87,6 @@ jobs:
5187
command: >-
5288
pages deploy .
5389
--project-name=${{ vars.CLOUDFLARE_PAGES_PROJECT }}
54-
--branch=preview/docs/pr-${{ github.event.pull_request.number }}
90+
--branch=${{ steps.identity.outputs.branch }}
5591
--commit-hash=${{ github.workflow_sha }}
5692
--commit-dirty=false

.github/workflows/pages-preview.yml

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,6 @@ jobs:
8484
pull-requests: read
8585
runs-on: ubuntu-latest
8686
timeout-minutes: 15
87-
environment:
88-
name: preview
89-
url: ${{ steps.pages.outputs.deployment-url }}
9087
steps:
9188
- name: Checkout the trusted preview controller
9289
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@@ -135,6 +132,34 @@ jobs:
135132
core.setFailed('Pull-request identity changed after artifact selection.')
136133
}
137134
135+
- name: Register the pull-request deployment
136+
id: github-deployment
137+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
138+
env:
139+
PREVIEW_HEAD_SHA: ${{ needs.identity.outputs.head_sha }}
140+
PULL_NUMBER: ${{ needs.identity.outputs.pull_number }}
141+
with:
142+
script: |
143+
const { data: deployment } = await github.rest.repos.createDeployment({
144+
owner: context.repo.owner,
145+
repo: context.repo.repo,
146+
ref: process.env.PREVIEW_HEAD_SHA,
147+
environment: 'preview',
148+
description: `Cloudflare Pages preview for PR #${process.env.PULL_NUMBER}`,
149+
auto_merge: false,
150+
required_contexts: [],
151+
transient_environment: true,
152+
production_environment: false,
153+
})
154+
core.setOutput('deployment_id', String(deployment.id))
155+
await github.rest.repos.createDeploymentStatus({
156+
owner: context.repo.owner,
157+
repo: context.repo.repo,
158+
deployment_id: deployment.id,
159+
state: 'in_progress',
160+
log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
161+
})
162+
138163
- name: Deploy to the isolated Pages preview branch
139164
id: pages
140165
uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
@@ -155,5 +180,27 @@ jobs:
155180
run: node controller/website/scripts/verify-pages-deployment.mjs
156181
env:
157182
CLOUDFLARE_PAGES_DEPLOYMENT_ID: ${{ steps.pages.outputs.pages-deployment-id }}
158-
CLOUDFLARE_PAGES_DEPLOYMENT_URL: ${{ steps.pages.outputs.deployment-url }}
183+
CLOUDFLARE_PAGES_DEPLOYMENT_URL: ${{ steps.pages.outputs.pages-deployment-alias-url }}
159184
INKCRE_PAGES_SMOKE_MODE: preview
185+
186+
- name: Report the pull-request deployment
187+
if: ${{ always() && steps.github-deployment.outputs.deployment_id != '' }}
188+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
189+
env:
190+
DEPLOYMENT_ID: ${{ steps.github-deployment.outputs.deployment_id }}
191+
JOB_STATUS: ${{ job.status }}
192+
PREVIEW_URL: ${{ steps.pages.outputs.pages-deployment-alias-url }}
193+
with:
194+
script: |
195+
const success = process.env.JOB_STATUS === 'success'
196+
await github.rest.repos.createDeploymentStatus({
197+
owner: context.repo.owner,
198+
repo: context.repo.repo,
199+
deployment_id: Number(process.env.DEPLOYMENT_ID),
200+
state: success ? 'success' : 'failure',
201+
description: success ? 'Pull-request preview is ready' : 'Pull-request preview failed',
202+
log_url: `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
203+
...(success && process.env.PREVIEW_URL
204+
? { environment_url: process.env.PREVIEW_URL }
205+
: {}),
206+
})

website/README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,10 @@ neither the canonical production artifact nor production delivery. A successful
6969
request may hand its checked artifact to a trusted controller for an isolated, deterministic,
7070
short-lived preview. Fork pull requests receive no preview credentials, preview origins remain
7171
`noindex`, and closing the pull request replaces the live preview with a trusted closed-preview
72-
tombstone. Cloudflare retains prior immutable deployments in its history. A preview artifact is
73-
never promoted to production.
72+
tombstone. The stable `preview-docs-pr-N` branch alias is the user-facing preview URL and is
73+
recorded against the pull-request head in GitHub; Cloudflare retains the underlying immutable
74+
deployments in its history. If automatic retirement fails, the cleanup workflow can be run manually
75+
for the closed pull-request number. A preview artifact is never promoted to production.
7476

7577
Protected `main` is the publication authority. `Pages deployment` runs for a push to `main`; failed
7678
runs can be rerun for the same commit, while rollback starts by reverting `main` through a pull

website/scripts/verify-pages-deployment.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,9 @@ if (process.env.GITHUB_STEP_SUMMARY) {
159159
'## Cloudflare Pages deployment',
160160
'',
161161
`- Deployment ID: \`${deploymentId}\``,
162-
`- Immutable URL: ${pagesOrigin.origin}`,
162+
smokeMode === 'production'
163+
? `- Immutable release URL: ${pagesOrigin.origin}`
164+
: `- Pull-request preview URL: ${pagesOrigin.origin}`,
163165
smokeMode === 'production'
164166
? `- Canonical URL: ${canonicalOrigin.origin}`
165167
: '- Canonical production origin: not contacted by preview validation',

0 commit comments

Comments
 (0)