-
Notifications
You must be signed in to change notification settings - Fork 324
164 lines (145 loc) · 6.12 KB
/
Copy pathbuild-check.yml
File metadata and controls
164 lines (145 loc) · 6.12 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
name: Docs Build Check
# Runs the same production build Vercel runs. Vercel's own check only shows
# "This branch had an error being deployed" with no detail in the PR, so this
# job re-runs `yarn build` here, parses well-known Docusaurus failure modes
# (broken links/anchors, unresolved Markdown links, MDX syntax errors) out of
# the log, and posts the specific page/target that needs fixing as a PR
# comment.
on:
pull_request:
paths:
- "docs/**"
- "src/**"
- "static/**"
- "sidebars.js"
- "docusaurus.config.js"
- "vercel.json"
- "package.json"
- "yarn.lock"
- "bin/parse-build-failure.js"
- ".github/workflows/build-check.yml"
permissions:
contents: read
pull-requests: write
jobs:
build-check:
name: Build site
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Set up Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: "24"
cache: "yarn"
# A PR's own ref never has a prior run to restore from, so this exact
# key only ever comes from warm-build-cache.yml's runs on main via
# GitHub's branch fallback (current ref -> PR base branch -> default
# branch). That's what makes a new PR's *first* check fast instead of
# a fully cold install.
- name: Cache installed dependencies
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: |
node_modules
!node_modules/.cache
key: ${{ runner.os }}-node-modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-modules-
# Restore-only: og-images and rspack are large (~1.7GB combined) and
# each save is keyed by run id so it always "changes", so restoring
# them here but only ever *saving* from warm-build-cache.yml (which
# runs once per merge, not once per PR check) avoids re-uploading
# multi-GB caches on every PR push.
- name: Restore OG image render cache
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: node_modules/.cache/og-images
key: og-images-${{ github.run_id }}
restore-keys: |
og-images-
- name: Restore Docusaurus build cache (rspack)
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: node_modules/.cache/rspack
key: rspack-${{ github.run_id }}
restore-keys: |
rspack-
- name: Install dependencies
run: yarn install --frozen-lockfile
- name: Build site
id: build
shell: bash
run: |
set +e
yarn build 2>&1 | tee build-output.log
exit_code=${PIPESTATUS[0]}
echo "exit_code=$exit_code" >> "$GITHUB_OUTPUT"
- name: Parse build failure
if: steps.build.outputs.exit_code != '0'
run: node bin/parse-build-failure.js build-output.log > build-failure-comment.md
- name: Comment on PR
if: always()
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const marker = '<!-- docs-build-check -->';
const exitCode = '${{ steps.build.outputs.exit_code }}';
const buildRan = exitCode !== '';
const failed = buildRan && exitCode !== '0';
// buildRan is false when an earlier step (e.g. yarn install) failed
// before the build could even start; parse-build-failure.js has
// nothing to work with in that case.
let body;
if (!buildRan) {
body = `${marker}\n### ❌ Docs build check failed before the build ran\n\nSee the [workflow run](${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}) for details.`;
} else if (failed) {
body = fs.readFileSync('build-failure-comment.md', 'utf8');
} else {
body = `${marker}\n### ✅ Docs build passed`;
}
const { data: comments } = await github.rest.issues.listComments({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
per_page: 100,
});
const existing = comments.find(
(comment) => comment.user?.login === 'github-actions[bot]' && comment.body?.includes(marker),
);
// Don't post a noisy "build passed" comment when there was never a failure comment to clear.
const cleanPass = buildRan && !failed;
if (cleanPass && !existing) {
core.info('Build passed and no previous failure comment exists; skipping comment.');
return;
}
if (existing) {
await github.rest.issues.updateComment({
owner: context.repo.owner,
repo: context.repo.repo,
comment_id: existing.id,
body,
});
core.info(`Updated existing build check comment (${existing.id}).`);
} else {
const { data: newComment } = await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body,
});
core.info(`Created new build check comment (${newComment.id}).`);
}
- name: Upload build log
if: always() && steps.build.outputs.exit_code != '0'
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: build-output-log
path: build-output.log
retention-days: 7
- name: Fail job if build failed
if: always() && steps.build.outputs.exit_code != '0'
run: exit 1