Repository navigation
329 lines (288 loc) · 14.8 KB
/
Copy pathcheck.yml
File metadata and controls
329 lines (288 loc) · 14.8 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
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
name: "Check"
on:
pull_request: {}
merge_group: {}
# Checking each master commit also fills the compilation cache, which only master pushes may write to
push:
branches:
- master
# Cancel a PR's in-progress checks once a newer commit is pushed to it (other runs are keyed by their commit, so those never cancel each other)
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
# Skip a merge queue run's checks when another Check run already passed them on the exact same content (Git tree)
skip-check:
runs-on: ubuntu-latest
permissions:
# Read the trees of the merge queue commit and of the commits other runs tested
contents: read
# Find the head commit of the PR being merged
pull-requests: read
# List this workflow's other runs
actions: read
outputs:
skip: ${{ steps.check.outputs.skip }}
steps:
- name: 🚦 Check if CI can be skipped
id: check
# A failed or hung step leaves the output unset, which runs the checks
continue-on-error: true
timeout-minutes: 2
env:
GH_TOKEN: ${{ github.token }}
MERGE_GROUP_HEAD_REF: ${{ github.event.merge_group.head_ref }}
MERGE_GROUP_HEAD_SHA: ${{ github.event.merge_group.head_sha }}
run: |
if [ "$GITHUB_EVENT_NAME" != "merge_group" ]; then
echo "skip=false" >> "$GITHUB_OUTPUT"
echo "Not a merge queue run, so the checks will run"
exit 0
fi
# Records the decision and shows its reason on the run's summary page
decide() {
echo "skip=$1" >> "$GITHUB_OUTPUT"
echo "::notice::$2"
exit 0
}
# Prints the tree of a commit, which is the hash of its exact file content
tree_of() {
local tree
tree=$(gh api "$repository_api/git/commits/$1" --jq '.tree.sha') && [[ "$tree" =~ ^[0-9a-f]{40}$ ]] && echo "$tree"
}
repository_api="repos/$GITHUB_REPOSITORY"
workflow_path="${GITHUB_WORKFLOW_REF%%@*}"
workflow_runs_api="$repository_api/actions/workflows/${workflow_path##*/}/runs"
merge_queue_branch="${MERGE_GROUP_HEAD_REF#refs/heads/}"
merge_group_tree=$(tree_of "$MERGE_GROUP_HEAD_SHA") || decide false "Running the checks since the merge queue commit $MERGE_GROUP_HEAD_SHA couldn't be read"
echo "The merge queue commit $MERGE_GROUP_HEAD_SHA has tree $merge_group_tree"
[[ "$merge_queue_branch" =~ ^gh-readonly-queue/.+/pr-([0-9]+)-[0-9a-f]+$ ]] || decide false "Running the checks since the merge queue branch '$merge_queue_branch' doesn't name a PR"
pr_number="${BASH_REMATCH[1]}"
pr_head_sha=$(gh api "$repository_api/pulls/$pr_number" --jq '.head.sha') || decide false "Running the checks since PR #$pr_number couldn't be read"
# The PR's own runs check out the PR merged into its base branch at that moment, which matches this content if the PR was up to date or its base hasn't moved since.
# Each run records the commit it loaded the local build.yml from (called by the build job below), and that is the merge commit it checked out.
export PR_MERGE_REF="refs/pull/$pr_number/merge"
pr_run=$(gh api -X GET "$workflow_runs_api" -f event=pull_request -f head_sha="$pr_head_sha" -f exclude_pull_requests=true -f per_page=100 --jq '
[.workflow_runs[] | select(.conclusion != "cancelled")] | max_by(.created_at) // empty
| "\(.html_url) \(.conclusion // .status) \([.referenced_workflows[]? | select(.ref == $ENV.PR_MERGE_REF) | .sha] | first // "unknown")"
') || decide false "Running the checks since the Check runs of PR #$pr_number couldn't be listed"
if [ -z "$pr_run" ]; then
echo "PR #$pr_number's head commit $pr_head_sha has no Check run that wasn't cancelled"
else
read -r pr_run_url pr_run_result pr_tested_sha <<< "$pr_run"
echo "The newest Check run of PR #$pr_number's head commit $pr_head_sha is $pr_run_url ($pr_run_result), which tested commit $pr_tested_sha"
if [ "$pr_run_result" != "success" ]; then
echo "That run hasn't succeeded"
elif ! pr_tested_tree=$(tree_of "$pr_tested_sha"); then
echo "The commit that run tested couldn't be read"
elif [ "$pr_tested_tree" = "$merge_group_tree" ]; then
decide true "Skipping the checks since $pr_run_url already passed on commit $pr_tested_sha, which has this exact content"
else
echo "That run tested different content (tree $pr_tested_tree)"
fi
fi
# A merge queue branch name pairs the PR with the commit it's built on, so an earlier run with this name may have passed on the same content before the PR was queued again
earlier_runs=$(gh api -X GET "$workflow_runs_api" -f event=merge_group -f status=success -f branch="$merge_queue_branch" -f exclude_pull_requests=true -f per_page=100 --jq '
.workflow_runs[] | select(.id | tostring != $ENV.GITHUB_RUN_ID) | "\(.head_sha) \(.html_url)"
') || decide false "Running the checks since the earlier merge queue runs couldn't be listed"
while read -r earlier_sha earlier_url; do
[ -n "$earlier_sha" ] || continue
if earlier_tree=$(tree_of "$earlier_sha") && [ "$earlier_tree" = "$merge_group_tree" ]; then
decide true "Skipping the checks since $earlier_url already passed on merge queue commit $earlier_sha, which has this exact content"
fi
done <<< "$earlier_runs"
decide false "Running the checks since no successful Check run has tested this exact content"
# Build the web app via the shared build workflow
build:
needs: skip-check
# Always called with the skip decision passed in, since a skipped caller job reports only as `build` and leaves the required `build / web` check missing.
# Like the jobs below, the checks still run if `skip-check` itself fails, since a skipped job counts as passing for required checks.
# Master pushes are left out because `build.yml` builds and deploys those itself.
if: ${{ !cancelled() && github.event_name != 'push' }}
uses: ./.github/workflows/build.yml
# The called workflow's jobs can only narrow these, so this grants the union of what they request
permissions:
actions: write
contents: write
deployments: write
id-token: write
pull-requests: write
secrets: inherit
with:
web: ${{ needs.skip-check.outputs.skip != 'true' }}
merge_queue: ${{ github.event_name == 'merge_group' }}
# Run the Rust tests
test:
needs: skip-check
if: ${{ !cancelled() && needs.skip-check.outputs.skip != 'true' }}
# Fork PRs always run on GitHub's own runners, while the `LINUX_RUNNER` repo variable can point the rest at another provider
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || vars.LINUX_RUNNER || 'ubuntu-latest' }}
permissions:
contents: read
env:
CARGO_INCREMENTAL: 0
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
# Only master pushes write to the compilation cache, so unmerged code can't plant entries that later master builds reuse
SCCACHE_GHA_RW_MODE: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/master') && 'READ_WRITE' || 'READ_ONLY' }}
# NOTICE: keep in sync with the web job in `build.yml`
SCCACHE_VERSION: "v0.19.0"
steps:
- name: 📥 Clone repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: 🦀 Install Rust
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0
with:
toolchain: stable
override: true
cache: false
rustflags: ""
- name: 📦 Install sccache
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
with:
version: ${{ env.SCCACHE_VERSION }}
- name: 🦀 Fetch Rust dependencies
run: cargo fetch --locked
- name: 🧪 Run Rust tests
env:
# `--cfg=web_sys_unstable_apis` mirrors the `[build]` section of `.cargo/config.toml`
RUSTFLAGS: "-Dwarnings --cfg=web_sys_unstable_apis"
run: cargo test --all-features
# The plain `cargo test` above only covers the workspace's default members, which leave these out
- name: 🧪 Run document migration tests
env:
RUSTFLAGS: "-Dwarnings --cfg=web_sys_unstable_apis"
run: >-
cargo test --all-features
--package migration-core
--package migration-runner
--package migration-formats
--package migration-nodes
--package migration-snapshot
--package document-graph-storage
--package document-format
--package graphene-cli
--package regression
# Render the documents of the regression corpus and compare them with their reference images
regression-corpus:
needs: skip-check
if: ${{ !cancelled() && needs.skip-check.outputs.skip != 'true' }}
runs-on: ${{ github.event.pull_request.head.repo.fork && 'ubuntu-latest' || vars.LINUX_RUNNER || 'ubuntu-latest' }}
permissions:
contents: read
env:
CARGO_INCREMENTAL: 0
RUSTC_WRAPPER: sccache
SCCACHE_GHA_ENABLED: "true"
# Only master pushes write to the compilation cache, so unmerged code can't plant entries that later master builds reuse
SCCACHE_GHA_RW_MODE: ${{ (github.event_name == 'push' && github.ref == 'refs/heads/master') && 'READ_WRITE' || 'READ_ONLY' }}
# NOTICE: keep in sync with the test job above and the web job in `build.yml`
SCCACHE_VERSION: "v0.19.0"
RUSTFLAGS: "-Dwarnings --cfg=web_sys_unstable_apis"
steps:
- name: 📥 Clone repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: 📥 Clone regression corpus
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
with:
repository: tagtraumen/graphite-corpus
path: target/regression-corpus
lfs: true
- name: 🦀 Install Rust
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0
with:
toolchain: stable
override: true
cache: false
rustflags: ""
- name: 📦 Install sccache
uses: mozilla-actions/sccache-action@fc920bf0ec8de6ee65d409111f7ec508035751ba # v0.0.11
with:
version: ${{ env.SCCACHE_VERSION }}
# GitHub's runners have no GPU, so rendering falls back to Mesa's software Vulkan driver
- name: 🎮 Install a software Vulkan driver
run: sudo apt-get update && sudo apt-get install --yes mesa-vulkan-drivers
- name: 🖼️ Check the corpus renders against its references
id: corpus
continue-on-error: true
run: cargo run --package regression -- --corpus target/regression-corpus check --output target/regression
- name: ⚠️ Warn about mismatched renders
if: ${{ steps.corpus.outcome == 'failure' }}
run: echo "::warning title=Regression corpus::Some corpus documents render differently from their references. Their renders and diffs are in the regression-mismatches artifact."
- name: 📤 Upload the renders and diffs of mismatches
if: ${{ steps.corpus.outcome == 'failure' }}
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
with:
name: regression-mismatches
path: target/regression
if-no-files-found: ignore
# Stored types, node version lineages, and node APIs against the base commit. Only needs the snapshot tool, so it runs on a GitHub runner
migrations:
needs: skip-check
# Master pushes are left out because they have no base commit, and the PR and merge queue runs already compared against it
if: ${{ !cancelled() && needs.skip-check.outputs.skip != 'true' && github.event_name != 'push' }}
runs-on: ubuntu-latest
permissions:
contents: read
env:
BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.merge_group.base_sha }}
steps:
- name: 📥 Clone repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: 🦀 Install Rust
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0
with:
toolchain: stable
override: true
cache: false
rustflags: ""
- name: 📥 Fetch the base commit
run: git fetch --depth=1 origin "$BASE_SHA"
- name: 🔬 Check migrations against the base commit
id: migrations
continue-on-error: true
run: cargo run --locked --package migration-snapshot -- check --baseline "$BASE_SHA"
- name: ⚠️ Warn about missing migrations
if: ${{ steps.migrations.outcome == 'failure' }}
run: echo "::warning title=Migrations::Some node changes lack a version bump or a migration. The log of the check above lists them."
# Rust format check on GitHub runner
rust-fmt:
needs: skip-check
if: ${{ !cancelled() && needs.skip-check.outputs.skip != 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: 📥 Clone repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: 🦀 Install Rust
uses: actions-rust-lang/setup-rust-toolchain@166cdcfd11aee3cb47222f9ddb555ce30ddb9659 # v1.17.0
with:
toolchain: stable
override: true
cache: false
rustflags: ""
components: rustfmt
- name: 🔬 Check Rust formatting
run: cargo fmt --all -- --check
# License compatibility check on GitHub runner
check-licenses:
needs: skip-check
if: ${{ !cancelled() && needs.skip-check.outputs.skip != 'true' }}
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: 📥 Clone repository
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
- name: 📜 Check crate license compatibility for root workspace
uses: EmbarkStudios/cargo-deny-action@3c6349835b2b7b196a839186cb8b78e02f7b5f25 # v2.1.1
with:
command: check bans licenses sources
- name: 📜 Check crate license compatibility for /libraries/rawkit
uses: EmbarkStudios/cargo-deny-action@3c6349835b2b7b196a839186cb8b78e02f7b5f25 # v2.1.1
with:
command: check bans licenses sources
manifest-path: libraries/rawkit/Cargo.toml