Repository navigation
405 lines (343 loc) · 15 KB
/
Copy pathci.yaml
File metadata and controls
405 lines (343 loc) · 15 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
name: CI
on:
pull_request:
push:
branches: [main]
# Cancel an in-flight run when a newer push supersedes it. The group is keyed
# on the ref, so a new push to a PR cancels that PR's prior run without
# touching other PRs or master. Limited to pull_request events: each master
# push still runs to completion rather than aborting mid-build.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
# Pin the Docker build-volume name so CI's bind-backed "mx-build" volume
# (created per-job below) is the one the Makefile actually mounts. Without
# this the Makefile computes a CURDIR-hashed name (for worktree isolation)
# that doesn't match the pre-created volume.
env:
DOCKER_VOLUME: mx-build
# Coverage is intentionally absent here -- the instrumented core/api builds are
# expensive and run only on demand from .github/workflows/coverage.yaml (the
# "Run workflow" button or a `/coverage` PR comment).
#
# Every Linux job runs its make targets inside the pinned mx-sdk Docker
# toolchain (ccache baked into the image); the macOS and Windows jobs build
# natively to catch AppleClang and MSVC fallout, kept incremental across runs by
# a content-addressed compiler cache -- ccache on macOS, sccache on Windows.
jobs:
# Cheap up-front diff check so the gen job (generator/audit tests, Go/C
# corert, the ratcheted quality/lint gates, and the gen-quality PR comment)
# only runs -- and only spends a PR comment -- when gen/ actually changed. A
# gen/ change that's md-only (README/AGENTS/DESIGN docs) doesn't move any of
# that, so it's excluded too.
changes:
name: "Detect gen/ changes"
runs-on: ubuntu-latest
outputs:
gen: ${{ steps.filter.outputs.gen }}
steps:
- uses: actions/checkout@v5
- uses: dorny/paths-filter@v3
id: filter
with:
# predicate-quantifier 'every' requires a changed file to match ALL
# patterns to count -- i.e. be under gen/ AND not markdown. Without
# it the patterns are OR'd, and the `!gen/**/*.md` rule then matches
# every non-gen-markdown path in the repo, so the filter fired on
# essentially every PR (the gen job ran even for pure Makefile/C++
# changes). See picomatch negation semantics.
predicate-quantifier: 'every'
filters: |
gen:
- 'gen/**'
- '!gen/**/*.md'
# The deep gate: every C++ suite -- the mx::core substrate (corert + unit)
# and the mx::api product surface (mxtest + examples + corpus round-trip) --
# built once through the pinned mx-sdk toolchain. This is the one place the
# core suites run, so it is the authoritative C++ correctness check.
test-linux:
name: "linux: test-all"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
# Container-driver builder (needed to export the gha layer cache) plus
# the runtime-token export so the Makefile auto-detects
# ACTIONS_RUNTIME_TOKEN and pushes/pulls the Docker layer cache. Keeps
# the toolchain-install layer warm across runs.
- uses: docker/setup-buildx-action@v3
- uses: crazy-max/ghaction-github-runtime@v3
# Back the mx-build volume with a workspace path so actions/cache can
# persist the ccache dir it holds. Not circular: Docker resolves this
# backing dir host-side, and the volume shadows /workspace/build inside
# the container.
- name: Create bind-backed build volume
run: |
mkdir -p build/docker
docker volume create --driver local \
--opt type=none --opt o=bind \
--opt device="$GITHUB_WORKSPACE/build/docker" mx-build
- name: Cache ccache
uses: actions/cache@v4
with:
path: build/docker/.ccache
key: ccache-${{ runner.os }}-test-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-test-
# corert file counts are pinned by an in-suite counts case (see CoreRoundtripTest.cpp).
- name: All C++ suites (core roundtrip + unit, api mxtest + examples + roundtrip)
run: make test-all
# mx::api cross-compiled to WebAssembly via the pinned mx-sdk emsdk install
# (#386) -- denigma (rpatters1/denigma) depends on this path staying green.
emscripten:
name: emscripten
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: docker/setup-buildx-action@v3
- uses: crazy-max/ghaction-github-runtime@v3
- name: Create bind-backed build volume
run: |
mkdir -p build/docker
docker volume create --driver local \
--opt type=none --opt o=bind \
--opt device="$GITHUB_WORKSPACE/build/docker" mx-build
# ccache for mx's own object files; EM_CACHE (below) is Emscripten's
# separate cache for its compiled system libraries.
- name: Cache ccache
uses: actions/cache@v4
with:
path: build/docker/.ccache
key: ccache-${{ runner.os }}-wasm-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-wasm-
- name: Cache EM_CACHE
uses: actions/cache@v4
with:
path: build/docker/.emcache
key: emcache-${{ runner.os }}-wasm-${{ github.sha }}
restore-keys: emcache-${{ runner.os }}-wasm-
- name: mx::api under Node (wasm)
run: make wasm-test
# The api product surface, built natively with AppleClang. macOS is a
# portability check on the product tier only (the core suites run on Linux in
# test-linux); this is the only C++ job off the pinned toolchain, by design,
# to keep finding AppleClang fallout.
#
# Incremental across runs via ccache (content-addressed, like the mx-sdk image
# bakes in for Linux). This replaces an earlier build/-dir cache keyed on
# hashFiles('src/**') -- that key was busted by every source change, so it gave
# nothing on exactly the PRs that recompile.
test-macos:
runs-on: macos-latest
# No Docker on the macOS runners: MX_RUNNING_IN_DOCKER=1 flips the Makefile
# to its direct-invocation branch so the build runs natively. CMake reads the
# *_COMPILER_LAUNCHER env vars as launcher defaults (the Makefile passes no -D
# launcher flag), the same mechanism the mx-sdk image uses for Linux.
env:
MX_RUNNING_IN_DOCKER: 1
CMAKE_C_COMPILER_LAUNCHER: ccache
CMAKE_CXX_COMPILER_LAUNCHER: ccache
steps:
- uses: actions/checkout@v5
- name: ccache
uses: hendrikmuhs/ccache-action@v1.2.18
with:
key: ${{ runner.os }}-api
max-size: 500M
- name: api suite (mxtest + examples)
run: make api-test
- name: api corpus round-trip (regression mode)
run: make api-roundtrip
# The api product surface, built natively with the real MSVC toolchain to keep
# finding Windows portability fallout. Windows has no make/Unix tools, so this
# job drives CMake directly.
#
# Generator is Ninja, not the Visual Studio generator: the VS generator ignores
# CMAKE_<LANG>_COMPILER_LAUNCHER, so sccache (the MSVC-capable compiler cache)
# can't hook in under it. Ninja honors the launcher and is faster besides.
# ilammy/msvc-dev-cmd puts cl.exe + the VS-bundled ninja on PATH via vcvars.
# Debug info is forced to Embedded (/Z7, not the default /Zi): sccache can't
# cache the shared-PDB writes /Zi makes, so /Z7 is what lets the object cache
# actually hit. Ninja is single-config, so binaries land in build/api/ (no
# Debug/ subdir).
test-windows:
runs-on: windows-latest
# Git Bash so multi-command run steps stop on first failure (set -e) and
# forward-slash paths + .exe invocation work uniformly.
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v5
# Puts cl.exe, link.exe, and the VS-bundled ninja on PATH -- exported to
# $GITHUB_ENV, so the later bash steps inherit the MSVC environment.
- uses: ilammy/msvc-dev-cmd@v1
- name: sccache
uses: hendrikmuhs/ccache-action@v1.2.18
with:
variant: sccache
key: ${{ runner.os }}-msvc
max-size: 1G
- name: Configure (MSVC, Ninja, MX_API)
run: >-
cmake -S . -B build/api -G Ninja
-DCMAKE_BUILD_TYPE=Debug
-DMX_API=on
-DCMAKE_C_COMPILER=cl
-DCMAKE_CXX_COMPILER=cl
-DCMAKE_C_COMPILER_LAUNCHER=sccache
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache
-DCMAKE_POLICY_DEFAULT_CMP0141=NEW
-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded
- name: Build
run: >-
cmake --build build/api
--target mx mxtest mxtest-api-roundtrip mxread mxwrite mxhide
--parallel
- name: api examples
run: |
build/api/mxread.exe
build/api/mxwrite.exe build/api/example.musicxml
build/api/mxhide.exe
- name: mxtest suite (api/impl/file/control)
run: build/api/mxtest.exe
- name: api corpus round-trip (regression mode)
run: >-
build/api/mxtest-api-roundtrip.exe regression
data src/private/mxtest/api/roundtrip-baseline.txt
# Proves mx compiles as a Swift package under AppleClang/SPM on every PR --
# the path komp takes when it depends on a sibling mx via `.package(path:)`.
# Runs no test suites; the binary xcframework ships from release-build.yml
# (docs/ai/design/release-process.md), not from CI.
#
# SwiftPM has no compiler-launcher hook, so incremental builds come from caching
# its .build tree: llbuild tracks inputs by content signature, so a restored
# tree rebuilds only what changed. The per-commit key suffix makes each run save
# an updated tree while restore-keys pulls the newest prior one.
swift:
runs-on: macos-latest
steps:
- uses: actions/checkout@v5
- name: Cache SwiftPM build
uses: actions/cache@v4
with:
path: .build
key: ${{ runner.os }}-spm-${{ hashFiles('Package.swift', 'Package.resolved') }}-${{ github.sha }}
restore-keys: |
${{ runner.os }}-spm-${{ hashFiles('Package.swift', 'Package.resolved') }}-
${{ runner.os }}-spm-
- name: Swift toolchain
run: swift --version
- name: Build the Mx Swift package (local-checkout source mode)
run: swift build --product Mx
# Repo-wide, compiles no C++: the clang-format gate plus a generated-output
# drift check (regenerate every target, then fail on any tracked-file diff).
# Always runs -- both apply to the whole repo, not just gen/.
quality:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v5
- uses: docker/setup-buildx-action@v3
- uses: crazy-max/ghaction-github-runtime@v3
- name: Create bind-backed build volume
run: |
mkdir -p build/docker
docker volume create --driver local \
--opt type=none --opt o=bind \
--opt device="$GITHUB_WORKSPACE/build/docker" mx-build
- name: Cache ccache
uses: actions/cache@v4
with:
path: build/docker/.ccache
key: ccache-${{ runner.os }}-quality-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-quality-
- name: fmt-check (clang-format, all C++ under src/)
run: make fmt-check
# The committed generated output must match the generator: regenerate
# every target, then any tracked-file drift fails the build.
- name: Regenerate all targets
run: make gen
- name: Generated output drift check
run: git diff --exit-code
# Generator + audit gates, gated on gen/ changes (see the `changes` job): the
# generator/audit Python tests, the Go and C corert suites (they exercise the
# generator's emitted targets), and the ratcheted quality/lint gates. Also
# stages the gen-quality report as a PR comment, posted by pr-comment.yaml.
gen:
runs-on: ubuntu-latest
needs: changes
if: needs.changes.outputs.gen == 'true'
# Read-only token: this job builds untrusted fork PR code, so it never
# requests write. The gen-quality comment is posted by the pr-comment.yaml
# companion workflow (workflow_run) from the base-repo context instead.
permissions:
contents: read
steps:
- uses: actions/checkout@v5
- uses: docker/setup-buildx-action@v3
- uses: crazy-max/ghaction-github-runtime@v3
- name: Create bind-backed build volume
run: |
mkdir -p build/docker
docker volume create --driver local \
--opt type=none --opt o=bind \
--opt device="$GITHUB_WORKSPACE/build/docker" mx-build
- name: Cache ccache
uses: actions/cache@v4
with:
path: build/docker/.ccache
key: ccache-${{ runner.os }}-gen-${{ github.sha }}
restore-keys: ccache-${{ runner.os }}-gen-
- name: gen unit tests (parser/IR/plates/press)
run: make gen-test
- name: audit tool unit tests (incl. failure classifier)
run: make audit-test
- name: Go corert suite
run: make test-go
- name: C corert suite
run: make test-c
# Static-analysis gates on the gen/ generator. Each fails the build below
# its floor (GEN_QUALITY_FLOOR / GEN_LINT_FLOOR in the Makefile).
- name: gen-quality gate
run: make gen-quality
- name: gen-lint gate
run: make gen-lint
# Surface the score in the run summary. always() so a gate failure still
# reports why.
- name: gen-quality report
if: always()
run: |
{
echo '### gen-quality `gen/`'
echo ''
cat data/testOutput/gen-quality/report.md 2>/dev/null || echo '(no report produced)'
} >> "$GITHUB_STEP_SUMMARY"
# Fork PRs run with a read-only token, so this job can't post the comment
# itself. Stage the body + PR number as an artifact; pr-comment.yaml posts
# it after CI completes. always() so a gate failure still reports why.
# Guarded on the report file existing so the comment-sending job gets no
# artifact -- and gracefully posts nothing -- if gen-quality crashed
# before writing it.
- name: Stage gen-quality PR comment
if: always() && github.event_name == 'pull_request'
run: |
if [ ! -f data/testOutput/gen-quality/report.md ]; then
echo 'No gen-quality report to stage (gate produced nothing).'
exit 0
fi
mkdir -p pr-comment
{
echo '### gen-quality `gen/`'
echo ''
cat data/testOutput/gen-quality/report.md
echo ''
echo 'Commit `${{ github.sha }}`.'
} > pr-comment/body.md
echo '${{ github.event.pull_request.number }}' > pr-comment/number
- name: Upload gen-quality PR comment
if: always() && github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: pr-comment-gen
path: pr-comment/
if-no-files-found: ignore