Repository navigation
230 lines (217 loc) · 10.1 KB
/
Copy pathpull-ci.yml
File metadata and controls
230 lines (217 loc) · 10.1 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
name: Pull CI
on:
pull_request:
# The defaults, plus ready_for_review: a draft defers the Kind smoke (see
# kind_paths), and marking it ready runs it on the same head.
types: [opened, synchronize, reopened, ready_for_review]
permissions:
contents: read
concurrency:
group: pull-ci-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
# Inventory only; kept outside required aggregate dependencies.
quarantine_backlog:
if: github.repository == 'perplexityai/SPACE'
uses: ./.github/workflows/quarantine-ci.yml
permissions:
contents: read
# Both reusable workflows read the CI image from this repository's GHCR
# package; see ci/scripts/ci-image.sh.
rust_static:
if: github.repository == 'perplexityai/SPACE'
uses: ./.github/workflows/rust-static-ci.yml
# pull-requests: read is for archcheck's reviewdog annotations.
permissions:
contents: read
packages: read
pull-requests: read
# Each check skips when the change touches nothing it reads
# (ci/check-scopes/README.md).
with:
scope_base: ${{ github.event.pull_request.base.sha }}
common:
if: github.repository == 'perplexityai/SPACE'
uses: ./.github/workflows/common-ci.yml
permissions:
contents: read
packages: read
with:
base_sha: ${{ github.event.pull_request.base.sha }}
scope_base: ${{ github.event.pull_request.base.sha }}
# The Kind smoke runs only when the PR changes a path it exercises
# (ci/kind-pull-paths.txt). Selecting it here rather than with a workflow
# `paths:` filter lets the required space-pull-ci check depend on it: a
# filtered-out workflow reports nothing, which a required check cannot use.
#
# A draft defers it: most Kind runs were drafts' intermediate pushes, each
# taking a large runner per shard. A deferred run fails space-pull-ci, so a
# pull request cannot merge on a run that skipped Kind; marking it ready
# runs the smoke on that head. The kind-smoke label opts a draft in; the
# label is read from the event, so it applies from the next push.
kind_paths:
if: github.repository == 'perplexityai/SPACE'
name: Select Kind smoke
runs-on: ubuntu-24.04
timeout-minutes: 5
outputs:
needed: ${{ steps.select.outputs.needed }}
console: ${{ steps.select.outputs.console }}
placement: ${{ steps.select.outputs.placement }}
record: ${{ steps.record.outputs.name }}
steps:
- name: Check out SPACE
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# The synthetic merge and both of its parents.
fetch-depth: 2
persist-credentials: false
- name: Decide whether this PR needs the Kind smoke
id: select
env:
PULL_REQUEST_HEAD: ${{ github.event.pull_request.head.sha }}
SPACE_KIND_PULL_DRAFT: ${{ github.event.pull_request.draft }}
SPACE_KIND_PULL_OPT_IN: ${{ contains(github.event.pull_request.labels.*.name, 'kind-smoke') }}
# The admin console smoke: off until the Kind runners carry
# Playwright (`uv sync --group console`) and its Chromium. Off, the
# console paths are not read, select nothing, and run no Kind smoke;
# `on` requires the local.console_* scenarios when a path in
# ci/kind-console-paths.txt changes, and runs the Kind smoke for it:
# a runner without the browser then fails the smoke, never skips.
SPACE_KIND_CONSOLE_SMOKE: 'off'
run: |
set -euo pipefail
needed="$(bash ci/scripts/kind-pull-needed.sh "${PULL_REQUEST_HEAD}")"
placement="$(SPACE_KIND_PULL_PATHS=ci/kind-placement-paths.txt \
bash ci/scripts/kind-pull-needed.sh "${PULL_REQUEST_HEAD}")"
if [[ "${needed}" == false ]]; then
needed="${placement}"
fi
console=false
case "${SPACE_KIND_CONSOLE_SMOKE}" in
on)
# A console change needs the Kind smoke as any Kind path does,
# deferred on a draft alike.
console="$(SPACE_KIND_PULL_PATHS=ci/kind-console-paths.txt \
bash ci/scripts/kind-pull-needed.sh "${PULL_REQUEST_HEAD}")"
if [[ "${needed}" == false ]]; then
needed="${console}"
fi
;;
off) ;;
*) echo "SPACE_KIND_CONSOLE_SMOKE must be on or off, not '${SPACE_KIND_CONSOLE_SMOKE}'." >&2; exit 1 ;;
esac
printf 'needed=%s\nconsole=%s\nplacement=%s\n' "${needed}" "${console}" "${placement}" >>"${GITHUB_OUTPUT}"
# Named here, where the synthetic merge is checked out; space-pull-ci
# records it once every check passed (ci/scripts/pull-ci-reuse.py).
- name: Name the trees this run tests
id: record
continue-on-error: true
run: |
set -euo pipefail
# Assigned first: a failure inside printf's arguments would not stop
# the step, and would record nothing without saying so.
name="$(python3 -I ci/scripts/pull-ci-reuse.py name)"
printf 'name=%s\n' "${name}" >>"${GITHUB_OUTPUT}"
# Includes same-repository PRs: no package write token. The read token
# reaches the third-party image mirror and the main-produced layer cache;
# once both are public, forks read them anonymously. A missing or
# inaccessible cache can use the existing read-only Actions cache bridge; if
# both miss, build cold. Neither case permits publication from PRs.
kind_smoke:
needs: kind_paths
if: github.repository == 'perplexityai/SPACE' && needs.kind_paths.outputs.needed == 'true'
uses: ./.github/workflows/kind-ci.yml
permissions:
actions: read
contents: read
packages: read
with:
console_scenarios: ${{ needs.kind_paths.outputs.console == 'true' }}
placement_scenarios: ${{ needs.kind_paths.outputs.placement == 'true' }}
space-pull-ci:
if: always() && github.repository == 'perplexityai/SPACE'
name: space-pull-ci
runs-on: ubuntu-24.04
# actions: read lets a cancelled run look for the run that replaced it.
permissions:
actions: read
needs:
- rust_static
- common
- kind_paths
- kind_smoke
steps:
- name: Require every pull-request check
env:
RUST_STATIC_RESULT: ${{ needs.rust_static.result }}
COMMON_RESULT: ${{ needs.common.result }}
KIND_PATHS_RESULT: ${{ needs.kind_paths.result }}
KIND_NEEDED: ${{ needs.kind_paths.outputs.needed }}
KIND_SMOKE_RESULT: ${{ needs.kind_smoke.result }}
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
RUN_ID: ${{ github.run_id }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
PR_NUMBER: ${{ github.event.pull_request.number }}
run: |
set -euo pipefail
# Two pull_request events for one head start two runs at once, and
# the concurrency group cancels one. This job still runs there
# (always()), and its failure can post after the other run's
# success and turn the pull request red. When every job was
# cancelled, pass only if another run of this workflow for the same
# pull request and head has already succeeded; otherwise fail as
# before, so a cancelled run never stands in for the checks.
if [ "${RUST_STATIC_RESULT}" = cancelled ] && [ "${COMMON_RESULT}" = cancelled ] &&
[ "${KIND_PATHS_RESULT}" = cancelled ]; then
passed="$(gh api "repos/${REPO}/actions/runs?head_sha=${HEAD_SHA}&event=pull_request&status=success&per_page=100" \
--jq "[.workflow_runs[] | select(.id != ${RUN_ID} and .path == \".github/workflows/pull-ci.yml\"
and any(.pull_requests[]; .number == ${PR_NUMBER}))] | first | .id // empty")"
if [ -n "${passed}" ]; then
echo "This run was cancelled; run ${passed} for the same head passed."
exit 0
fi
fi
test "${RUST_STATIC_RESULT}" = success
test "${COMMON_RESULT}" = success
# An unknown selection fails rather than skipping Kind.
test "${KIND_PATHS_RESULT}" = success
case "${KIND_NEEDED}" in
true) test "${KIND_SMOKE_RESULT}" = success ;;
false) test "${KIND_SMOKE_RESULT}" = skipped ;;
# A run, or a rerun, that skipped Kind on a draft never passes.
deferred)
echo "The Kind smoke was deferred on this draft: mark the pull request ready for review, or add the kind-smoke label and push." >&2
exit 1 ;;
*) echo "Kind smoke selection returned '${KIND_NEEDED}'" >&2; exit 1 ;;
esac
# The merge queue skips its copies of rust_static and common for an
# entry whose base and merge trees match a record (merge-queue-ci.yml).
# A day covers a PR enqueued after its last push; older records expire.
# Only reuse depends on it, so a failed upload does not fail the check.
- name: Record that this run passed these trees
# The results the record certifies, stated here as well as implied by
# the gate above.
if: >-
needs.kind_paths.outputs.record != '' &&
needs.rust_static.result == 'success' && needs.common.result == 'success'
env:
RECORD: ${{ needs.kind_paths.outputs.record }}
run: printf '%s\n' "${RECORD}" >"${RUNNER_TEMP}/pull-ci-passed.txt"
- name: Publish the record
if: >-
needs.kind_paths.outputs.record != '' &&
needs.rust_static.result == 'success' && needs.common.result == 'success'
continue-on-error: true
# This job made no network call before; a stalled upload must not
# hold the required check.
timeout-minutes: 2
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: ${{ needs.kind_paths.outputs.record }}
path: ${{ runner.temp }}/pull-ci-passed.txt
retention-days: 1
if-no-files-found: error
# A rerun of this job records the same trees again.
overwrite: true