Repository navigation
167 lines (153 loc) · 7.65 KB
/
Copy pathdeploy-docs-fork-preview.yml
File metadata and controls
167 lines (153 loc) · 7.65 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
name: Deploy Docs Fork Preview
run-name: 'Deploy docs preview at ${{ github.event.workflow_run.head_sha }} from build #${{ github.event.workflow_run.id }}'
# Fork PRs cannot receive deployment credentials. This workflow runs from
# the default branch, validates the originating workflow and current PR,
# and uploads only static assets. It never checks out or executes fork code.
# This file must be on main before workflow_run can trigger it.
#
# Like publish-preview.yml and publish-preview-register.yml, a label requests
# a secret-free build and a required-reviewer environment gates deployment.
# Maintainer setup: restrict docs-preview to main and configure required
# reviewers with repository write permission. Add the CLOUDFLARE_ACCOUNT_ID
# variable and CLOUDFLARE_API_TOKEN secret there. Scope the token to the Worker
# account with Workers Scripts: Edit permission.
# Enable Preview URLs for viteplus-dev on voidzero-docs.workers.dev.
# Apply docs-preview after reviewing a fork PR's current commit. Remove and
# reapply it after updates, then approve the deployment for that build's SHA.
# The label is rechecked before upload and commenting; removing it cannot undo
# an upload that already started. The PR-controlled build gate is not a security
# boundary. The trusted workflow checks the original actor's write permission
# and requires environment approval for this deployment run, not an old commit.
# An absent or unprotected environment must not silently permit deployment:
# the deploy job also checks GitHub's review history before using credentials.
# Each PR reuses one alias for its docs and installer URLs. An approved upload
# updates that address. Aliases are subject to Cloudflare's retention limits.
on: # zizmor: ignore[dangerous-triggers]
workflow_run:
workflows: ['Build Docs Fork Preview']
types: [completed]
permissions: {}
defaults:
run:
shell: bash
jobs:
authorize:
if: >-
github.event_name == 'workflow_run' &&
github.repository == 'voidzero-dev/vite-plus' &&
github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion == 'success' &&
github.event.workflow_run.path == '.github/workflows/build-docs-fork-preview.yml'
runs-on: ubuntu-latest
timeout-minutes: 5
permissions:
contents: read
actions: read
pull-requests: read
outputs:
pr: ${{ steps.preview.outputs.pr }}
artifact-id: ${{ steps.preview.outputs.artifact-id }}
preview-alias: ${{ steps.preview.outputs.preview-alias }}
preview-url: ${{ steps.preview.outputs.preview-url }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
persist-credentials: false
sparse-checkout: .github/scripts
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
id: preview
with:
script: |
const { authorizePreview } = await import(`${process.env.GITHUB_WORKSPACE}/.github/scripts/docs-fork-preview.mjs`);
await authorizePreview({ github, context, core });
deploy:
name: 'Deploy PR #${{ needs.authorize.outputs.pr }} at ${{ github.event.workflow_run.head_sha }}'
needs: authorize
if: github.event_name == 'workflow_run' && needs.authorize.outputs.pr != ''
runs-on: ubuntu-latest
timeout-minutes: 10
# Serialize uploads per PR and let the running deployment finish.
# Keep only the last queued job; recheck the head before uploading.
concurrency:
group: deploy-docs-fork-preview-${{ needs.authorize.outputs.pr }}
cancel-in-progress: false
environment:
name: docs-preview
url: ${{ needs.authorize.outputs.preview-url }}
permissions:
contents: read
actions: read
pull-requests: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.sha }}
persist-credentials: false
sparse-checkout: |
.github/scripts
docs
- name: Require deployment approval
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
with:
script: |
const { requireDeploymentApproval } = await import(`${process.env.GITHUB_WORKSPACE}/.github/scripts/docs-fork-preview.mjs`);
await requireDeploymentApproval({ github, context });
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: '24'
package-manager-cache: false
# Install only the deployment tool, outside both the checkout and the
# artifact. No PR dependencies, scripts, config, or caches are used here.
- name: Install Wrangler
run: npm install --prefix "$RUNNER_TEMP/docs-preview-tools" --ignore-scripts --no-package-lock wrangler@4.127.1
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
artifact-ids: ${{ needs.authorize.outputs.artifact-id }}
run-id: ${{ github.event.workflow_run.id }}
github-token: ${{ github.token }}
path: ${{ runner.temp }}/docs-preview-assets
merge-multiple: true
- name: Validate static assets
run: node .github/scripts/docs-fork-preview.mjs validate-assets "$RUNNER_TEMP/docs-preview-assets"
- name: Recheck the PR before upload
id: current
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
env:
PR_NUMBER: ${{ needs.authorize.outputs.pr }}
with:
script: |
const { isCurrentPreview } = await import(`${process.env.GITHUB_WORKSPACE}/.github/scripts/docs-fork-preview.mjs`);
core.setOutput('current', await isCurrentPreview({ github, context }, Number(process.env.PR_NUMBER)));
- name: Upload preview version
if: steps.current.outputs.current == 'true'
env:
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
PR_NUMBER: ${{ needs.authorize.outputs.pr }}
HEAD_SHA: ${{ github.event.workflow_run.head_sha }}
PREVIEW_ALIAS: ${{ needs.authorize.outputs.preview-alias }}
WRANGLER_SEND_METRICS: 'false'
WRANGLER_OUTPUT_FILE_PATH: ${{ runner.temp }}/docs-preview-upload.jsonl
run: |
if [[ -z "$CLOUDFLARE_ACCOUNT_ID" || -z "$CLOUDFLARE_API_TOKEN" ]]; then
echo '::error::Configure the CLOUDFLARE_ACCOUNT_ID variable and CLOUDFLARE_API_TOKEN secret in the docs-preview environment.'
exit 1
fi
"$RUNNER_TEMP/docs-preview-tools/node_modules/.bin/wrangler" versions upload \
--config "$GITHUB_WORKSPACE/docs/wrangler.jsonc" \
--assets "$RUNNER_TEMP/docs-preview-assets" \
--preview-alias "$PREVIEW_ALIAS" \
--message "Docs preview for PR #$PR_NUMBER ($HEAD_SHA)"
- name: Comment on the fork PR
if: steps.current.outputs.current == 'true'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9
env:
PR_NUMBER: ${{ needs.authorize.outputs.pr }}
WRANGLER_OUTPUT_FILE_PATH: ${{ runner.temp }}/docs-preview-upload.jsonl
with:
script: |
const { readFile } = await import('node:fs/promises');
const { commentPreview } = await import(`${process.env.GITHUB_WORKSPACE}/.github/scripts/docs-fork-preview.mjs`);
const output = await readFile(process.env.WRANGLER_OUTPUT_FILE_PATH, 'utf8');
await commentPreview({ github, context, core }, Number(process.env.PR_NUMBER), output);