Repository navigation
438 lines (423 loc) · 20.2 KB
/
Copy pathci-pull.yml
File metadata and controls
438 lines (423 loc) · 20.2 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
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# ============================================================================
# Laige CI — P0 platform matrix on pull request (M0-CI-01)
#
# Roadmap: roadmap/M0-foundations.md, step M0-CI-01
# PRD refs: §6 (P0 platforms, AC-6.1), §14 (cadence), §8.1 (build budget)
#
# Cadence (PRD §14: "one per PR, all per merge"): each pull request runs
# exactly ONE P0 OS, selected by the PR's ci:* label; the default (no
# label) is Linux. Merges to master run ALL P0 OSes via ci.yml, which is
# the "all per merge" half of the cadence.
#
# Label selector (apply at most one per PR; if several are present the
# highest-priority label wins, so exactly one P0 OS always runs):
#
# ci:macos → macos-arm64 + macos-intel jobs
# ci:windows → windows-msvc job
# ci:linux → linux-gcc + linux-clang jobs (also the no-label default)
#
# NOTE: the labels must be created once in the repository settings
# (GitHub does not create labels from workflows). A PR with an unknown
# or missing ci:* label simply falls back to the Linux default.
#
# Jobs, runner images, steps, and the 10-minute budget timeout are the
# same as in ci.yml (see its header for the full matrix documentation
# and the Windows multi-config note).
#
# Sanitizer lanes (M0-CI-02): linux-asan (LAIGE_ASAN=ON) and linux-tsan
# (LAIGE_TSAN=ON) run under the same condition as the default Linux
# jobs — i.e. on every PR that does not select another P0 OS — because
# they are part of the Linux P0 check (PRD §14: one P0 OS per PR). See
# the ci.yml header for the lane semantics (fatal sanitizer reports,
# report archiving, toolchain choice).
#
# Fuzz lane (PRD §14 "every commit (bounded)"; M0-TEST-01): no separate
# fuzz job — the `fuzz_json_parse` ctest entry (1000 deterministic runs
# of laige-fuzz on the json_parse target) runs inside every build
# job's ctest, instrumented in the ASan tree. Seed and nightly-long-run
# conventions: docs/testing.md.
#
# Include-graph lint (M0-CI-03; NFR-8.11, NFR-8.13): the `include-lint`
# job runs on EVERY pull request, independent of the ci:* label selector
# — it is a platform-independent repository check (Python 3 stdlib only),
# not a P0 OS build, so it does not interact with the "one P0 OS per PR"
# cadence. It enforces the PRD §10.1 include rules over src/** (laige-core
# depends on nothing internal; arrows only downward in the module stack;
# vendored deps only included from their deps.lock `owner`) and reports
# the vendored-dependency count, which must stay ≤ 10 (PRD §11).
#
# Fork PRs: this workflow uses the pull_request event, which runs on the
# merge ref with a read-only token; checkout + build + ctest need nothing
# beyond contents:read. On such PRs the artifact upload (needs
# actions:write) fails with a 403, so the upload steps carry
# continue-on-error: true — the reports then remain in the job log and
# the tee'd output instead of the artifact.
# ============================================================================
name: CI (pull request)
on:
pull_request:
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
linux-gcc:
name: Linux x64 (g++)
if: >-
!contains(github.event.pull_request.labels.*.name, 'ci:macos') &&
!contains(github.event.pull_request.labels.*.name, 'ci:windows')
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Install GLFW X11 headers (laige-render)
# GLFW's X11 backend (GLFW_BUILD_WAYLAND=OFF in src/laige-render/
# CMakeLists.txt) needs only the X11 *headers* at configure time
# (GLFW 3.5 dlopens the X11/GL libraries at runtime); the
# ubuntu-24.04 runner image ships none of them. The libegl/libgl
# packages are the RUNTIME GL stack for the headless GL smoke
# (Mesa surfaceless EGL + llvmpipe software GL; the engine and
# GLAD load them by dlopen at runtime) (M2-GL-01).
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq \
libx11-dev libxcursor-dev libxrandr-dev \
libxinerama-dev libxi-dev libxext-dev \
libegl1 libgl1 libegl-mesa0 libglx-mesa0 libgl1-mesa-dri
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=g++
- name: Build
run: cmake --build build -j
- name: Test (unit)
run: ctest --test-dir build --output-on-failure
linux-clang:
name: Linux x64 (clang++)
if: >-
!contains(github.event.pull_request.labels.*.name, 'ci:macos') &&
!contains(github.event.pull_request.labels.*.name, 'ci:windows')
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Install GLFW X11 headers (laige-render)
# GLFW's X11 backend (GLFW_BUILD_WAYLAND=OFF in src/laige-render/
# CMakeLists.txt) needs only the X11 *headers* at configure time
# (GLFW 3.5 dlopens the X11/GL libraries at runtime); the
# ubuntu-24.04 runner image ships none of them. The libegl/libgl
# packages are the RUNTIME GL stack for the headless GL smoke
# (Mesa surfaceless EGL + llvmpipe software GL; the engine and
# GLAD load them by dlopen at runtime) (M2-GL-01).
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq \
libx11-dev libxcursor-dev libxrandr-dev \
libxinerama-dev libxi-dev libxext-dev \
libegl1 libgl1 libegl-mesa0 libglx-mesa0 libgl1-mesa-dri
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++
- name: Build
run: cmake --build build -j
- name: Test (unit)
run: ctest --test-dir build --output-on-failure
linux-asan:
name: Linux x64 ASan+UBSan (clang++)
if: >-
!contains(github.event.pull_request.labels.*.name, 'ci:macos') &&
!contains(github.event.pull_request.labels.*.name, 'ci:windows')
runs-on: ubuntu-24.04
timeout-minutes: 10
# Job-scoped token: the archive step below needs actions:write for
# PRs from the base repository (fork PR tokens stay read-only,
# whatever this declares — see header).
permissions:
contents: read
actions: write
steps:
- uses: actions/checkout@v4
- name: Install GLFW X11 headers (laige-render)
# GLFW's X11 backend (GLFW_BUILD_WAYLAND=OFF in src/laige-render/
# CMakeLists.txt) needs only the X11 *headers* at configure time
# (GLFW 3.5 dlopens the X11/GL libraries at runtime); the
# ubuntu-24.04 runner image ships none of them. The libegl/libgl
# packages are the RUNTIME GL stack for the headless GL smoke
# (Mesa surfaceless EGL + llvmpipe software GL; the engine and
# GLAD load them by dlopen at runtime) (M2-GL-01).
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq \
libx11-dev libxcursor-dev libxrandr-dev \
libxinerama-dev libxi-dev libxext-dev \
libegl1 libgl1 libegl-mesa0 libglx-mesa0 libgl1-mesa-dri
- name: Configure (ASan+UBSan)
run: cmake -S . -B build-asan -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ -DLAIGE_ASAN=ON
- name: Build (ASan+UBSan)
run: cmake --build build-asan -j
- name: Test (unit, ASan+UBSan)
# Every sanitizer report is fatal to the test process: ASan via
# abort_on_error=1:halt_on_error=1 here, UBSan via
# -fno-sanitize-recover=all (wired by CMake). log_path keeps one
# report file per test process for the artifact upload below.
env:
ASAN_OPTIONS: "abort_on_error=1:halt_on_error=1:detect_leaks=1:log_path=${{ github.workspace }}/asan-reports/asan"
run: |
set -o pipefail
ctest --test-dir build-asan --output-on-failure 2>&1 | tee asan-ctest-output.txt
- name: Archive sanitizer reports
# continue-on-error: fork PRs run with a read-only token, so the
# upload 403s there (see header); the reports stay in the job log
# and the tee'd output. The job-level actions:write covers PRs
# from the base repository.
if: always()
continue-on-error: true
uses: actions/upload-artifact@v4
with:
name: linux-asan-reports
path: |
asan-ctest-output.txt
asan-reports/
build-asan/Testing/Temporary/LastTest.log
linux-tsan:
name: Linux x64 TSan (clang++)
if: >-
!contains(github.event.pull_request.labels.*.name, 'ci:macos') &&
!contains(github.event.pull_request.labels.*.name, 'ci:windows')
runs-on: ubuntu-24.04
# 30 min (not 10): TSan is the slowest lane by design (~5-15x
# instrumentation overhead), and the suite has grown past the old
# margin — the M2-ISO-01 10k-scene property suite (iso_depth_key
# entry) plus the M2-GL-02 3000-frame integration run. Evidence:
# the master merge run of PR #60 took 8.8 min (96 entries: setup +
# build ~1.7 min, the 96-entry TSan test step ~7.1 min); the
# M2-ISO-01 PR run needed ~11 min (setup + build 3.7 min on a
# slower runner, the 97-entry test step ~7.2 min — laige-sim_tests
# alone 177 s) and was CANCELLED at the 10-min cap ~50 s before
# completion. 30 min keeps a large margin for runner variance and
# the suite's continued growth without weakening the gate
# (M2-ISO-01, 2026-09-30).
timeout-minutes: 30
# Job-scoped token: the archive step below needs actions:write (see
# the linux-asan job comment).
permissions:
contents: read
actions: write
steps:
- uses: actions/checkout@v4
- name: Install GLFW X11 headers (laige-render)
# GLFW's X11 backend (GLFW_BUILD_WAYLAND=OFF in src/laige-render/
# CMakeLists.txt) needs only the X11 *headers* at configure time
# (GLFW 3.5 dlopens the X11/GL libraries at runtime); the
# ubuntu-24.04 runner image ships none of them. The libegl/libgl
# packages are the RUNTIME GL stack for the headless GL smoke
# (Mesa surfaceless EGL + llvmpipe software GL; the engine and
# GLAD load them by dlopen at runtime) (M2-GL-01).
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq \
libx11-dev libxcursor-dev libxrandr-dev \
libxinerama-dev libxi-dev libxext-dev \
libegl1 libgl1 libegl-mesa0 libglx-mesa0 libgl1-mesa-dri
- name: Configure (TSan)
run: cmake -S . -B build-tsan -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=clang++ -DLAIGE_TSAN=ON
- name: Build (TSan)
run: cmake --build build-tsan -j
- name: Test (unit, TSan)
# TSAN_OPTIONS=halt_on_error=1 is applied per test by tests/
# (M0-BUILD-01), so the first data race report kills the test
# process and ctest fails. The race report is printed to stderr
# and captured by the tee below.
run: |
set -o pipefail
ctest --test-dir build-tsan --output-on-failure 2>&1 | tee tsan-ctest-output.txt
- name: Archive sanitizer reports
# continue-on-error and job-level permissions: same rationale as
# the linux-asan job (fork PRs read-only, base-repo PRs can
# upload).
if: always()
continue-on-error: true
uses: actions/upload-artifact@v4
with:
name: linux-tsan-reports
path: |
tsan-ctest-output.txt
build-tsan/Testing/Temporary/LastTest.log
windows-msvc:
name: Windows x64 (MSVC 2022)
if: >-
contains(github.event.pull_request.labels.*.name, 'ci:windows') &&
!contains(github.event.pull_request.labels.*.name, 'ci:macos')
runs-on: windows-2022
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Configure
# CMAKE_BUILD_TYPE is ignored by the multi-config VS generator; the
# Debug configuration is pinned on the build/test steps below.
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
- name: Build
run: cmake --build build --config Debug -j
- name: Test (unit)
# The trait_compile_* fixtures invoke cl.exe DIRECTLY from a
# generated cmake -P script (execute_process), outside the VS
# generator's toolchain setup, so — unlike every other test in
# this job — they need the MSVC environment (INCLUDE/LIB/PATH)
# to find the CRT/STL headers; the plain runner shell lacks it
# and cl fails with C1083 on <cstdint> etc. This step imports
# the VS development environment into the current PowerShell
# process: vswhere locates the installation, VsDevCmd.bat (the
# canonical vcvars, present in every VS 2017+ install under
# Common7\Tools — called by relative name from that directory,
# so no path quoting is involved) sets it, and its `set` dump
# is imported variable by variable. ctest, cmake -P, and cl all
# inherit it. Everything else in this step is unchanged.
run: |
$vs = & "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" -latest -products * -property installationPath
Push-Location (Join-Path $vs "Common7\Tools")
$envDump = cmd /c "call VsDevCmd.bat -arch=amd64 -host_arch=amd64 >nul && set"
Pop-Location
foreach ($line in $envDump) {
if ($line -match '^([A-Za-z_][A-Za-z0-9_]*)=(.*)$') {
Set-Item -Path "env:$($matches[1])" -Value $matches[2]
}
}
ctest --test-dir build -C Debug --output-on-failure
macos-arm64:
name: macOS arm64 (AppleClang)
if: contains(github.event.pull_request.labels.*.name, 'ci:macos')
runs-on: macos-15
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
- name: Build
run: cmake --build build -j
- name: Test (unit)
run: ctest --test-dir build --output-on-failure
macos-intel:
name: macOS Intel (AppleClang)
if: contains(github.event.pull_request.labels.*.name, 'ci:macos')
runs-on: macos-14
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
- name: Build
run: cmake --build build -j
- name: Test (unit)
run: ctest --test-dir build --output-on-failure
include-lint:
# M0-CI-03: runs on every PR (no ci:* condition). Platform-independent:
# the lint is Python 3 stdlib only (no setup step needed) and checks
# the repository layout, not a compiler-specific build. The CTest
# suite runs it against the real tree in every P0 job as well
# (tests/tools, test `include-lint-real-tree`), so a broken include
# fails even a PR that selects another P0 OS.
name: Include-graph lint + dependency count
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: Lint include graph + report dependency count
run: python3 tools/laige-include-lint
determinism-lint:
# M1-DET-01: runs on every PR (no ci:* condition). The sim-source
# determinism scan (the second half of the G-R8 guarantee; the
# first is the compile-time trait checked by the
# trait_compile_* CTest fixtures): forbids raw float/double and
# unordered containers in src/laige-sim/**, with per-line
# LAIGE-DETERM-EXCEPTION markers as the documented false-positive
# policy (docs/concepts/determinism.md). Platform-independent:
# Python 3 stdlib only, no setup step. The CTest suite runs it
# against fixture trees and the real tree in every P0 job as well
# (tests/tools, tests `determinism-lint-*`).
name: Determinism source scan (sim module)
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: Scan sim sources for raw FP / unordered containers
run: python3 tools/laige-determinism-lint
api-manifest:
# M0-TOOL-01: runs on every PR (no ci:* condition). The checked-in
# public API manifest (laige-api.json, PRD §9.4, NFR-13.1) must stay
# in sync with the public headers: this job regenerates it from the
# current headers with laige-api-scanner and fails on any drift, so
# adding a public symbol without regenerating the manifest fails CI.
# The CTest suite runs the same check against the real tree in every
# P0 job as well (tests/api, test `api-real-tree`).
name: Public API manifest drift
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Install GLFW X11 headers (laige-render)
# GLFW's X11 backend (GLFW_BUILD_WAYLAND=OFF in src/laige-render/
# CMakeLists.txt) needs only the X11 *headers* at configure time
# (GLFW 3.5 dlopens the X11/GL libraries at runtime); the
# ubuntu-24.04 runner image ships none of them. The libegl/libgl
# packages are the RUNTIME GL stack for the headless GL smoke
# (Mesa surfaceless EGL + llvmpipe software GL; the engine and
# GLAD load them by dlopen at runtime) (M2-GL-01).
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq \
libx11-dev libxcursor-dev libxrandr-dev \
libxinerama-dev libxi-dev libxext-dev \
libegl1 libgl1 libegl-mesa0 libglx-mesa0 libgl1-mesa-dri
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
- name: Build scanner
run: cmake --build build --target laige-api-scanner -j
- name: Check manifest drift
run: ./build/bin/laige-api-scanner --root . --check laige-api.json
detcheck:
# M1-DET-04: runs on every PR (no ci:* condition). The determinism
# checker (FR-11.5): the built-in synthetic scenario self-check,
# then the M1-SAMPLE-01 hello scenario asserted against the
# committed per-tick hash baselines (samples/hello/baselines/) on
# BOTH SimMath backends (fixed_point_16_16, float_pinned_32 — ADR
# 0002) with `hello --expect` (the laige-replay --expect contract:
# 0 match, 1 first divergence, 2 baseline read/contract error).
# The PR's P0 OS job's ctest repeats the same baseline assertion on
# its own platform (tests/sample: hello_baseline_fpx /
# hello_baseline_fp32); this tooling job guarantees the check runs
# on every PR, including ones labelled for non-Linux P0 OSes. The
# full two-configuration matrix (g++ vs clang++, Debug+ASan vs
# Release) runs on merges in the detcheck job of ci.yml.
name: Determinism check
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Install GLFW X11 headers (laige-render)
# GLFW's X11 backend (GLFW_BUILD_WAYLAND=OFF in src/laige-render/
# CMakeLists.txt) needs only the X11 *headers* at configure time
# (GLFW 3.5 dlopens the X11/GL libraries at runtime); the
# ubuntu-24.04 runner image ships none of them. The libegl/libgl
# packages are the RUNTIME GL stack for the headless GL smoke
# (Mesa surfaceless EGL + llvmpipe software GL; the engine and
# GLAD load them by dlopen at runtime) (M2-GL-01).
run: |
sudo apt-get update -qq
sudo apt-get install -y -qq \
libx11-dev libxcursor-dev libxrandr-dev \
libxinerama-dev libxi-dev libxext-dev \
libegl1 libgl1 libegl-mesa0 libglx-mesa0 libgl1-mesa-dri
- name: Configure
run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug
- name: Build
run: cmake --build build -j
- name: Synthetic scenario self-check
run: ./build/bin/laige-detcheck --scenario=synthetic
- name: Real scenario vs baselines (M1-SAMPLE-01, both backends)
# The hello template is always built in this job, so both steps
# always execute. Each must exit 0 (a first-divergence report is
# exit 1; a baseline read/contract failure is exit 2) and print
# the 301-line per-tick hash stream.
run: |
./samples/hello/bin/hello \
--expect samples/hello/baselines/fixed_point_16_16/hash_stream.txt
./samples/hello/bin/hello-fp32 \
--expect samples/hello/baselines/float_pinned_32/hash_stream.txt