-
Notifications
You must be signed in to change notification settings - Fork 5
430 lines (420 loc) · 20.3 KB
/
Copy pathvalidate.yml
File metadata and controls
430 lines (420 loc) · 20.3 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
name: validate
on:
pull_request:
paths: ["pkgs/**/*.lua", "tests/**", "README.md", ".github/workflows/validate.yml"]
push:
branches: [main]
schedule:
# nightly full regression — exercises every smoke suite regardless of diff
- cron: "0 6 * * *"
workflow_dispatch:
env:
# 0.0.96: carries the windows scanner symlink-escape crash fix (mcpp#230),
# so all platforms ride the same version again. Older floors of note:
# 0.0.94 fixed feature-gated `sources` under `mcpp test` (mcpp#218);
# 0.0.91 added standard = "c++fly" to the resolver grammar, so c++fly
# descriptors get the lint WARN below, not a hard grammar-parse rejection.
MCPP_VERSION: "0.0.96"
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install lua
run: sudo apt-get install -y --no-install-recommends lua5.4
- name: Lint package descriptors
run: |
fail=0
for f in pkgs/*/*.lua; do
# 1. Lua syntax check — load (= compile) without executing.
# `loadfile(name, 't')` rejects bytecode and parses text only.
if ! lua5.4 -e "assert(loadfile('$f', 't'))" >/dev/null 2>&1; then
echo "::error file=$f::lua syntax error"
fail=1
fi
# 2. xpkg V1 baseline: the file has to populate `package = { ... }`
# with at least `spec`, `name`, and an `xpm` table. Form A vs
# Form B (mcpp = "<path>" / mcpp = { ... }) is descriptor-author
# choice and not enforced here.
for needle in 'spec *=' 'name *=' 'xpm *='; do
if ! grep -q "$needle" "$f"; then
echo "::error file=$f::missing required field ($needle)"
fail=1
fi
done
# 3. Package version identifiers and dependency versions should be
# bare versions ("1.2.3"), not upstream tag names ("v1.2.3").
# Download URLs may still contain refs/tags/v* when upstream
# uses that tag spelling.
if grep -nE '\["v[0-9]+|\["[^"]+"\][[:space:]]*=[[:space:]]*"v[0-9]+' "$f"; then
echo "::error file=$f::version identifiers must not use a leading v"
fail=1
fi
# 4. Mirror table sanity: when a download `url` is written as a
# { GLOBAL=..., CN=... } table, both regions must be present and
# the CN entry must point at the gitcode mcpp-res mirror.
if ! lua5.4 tests/check_mirror_urls.lua "$f"; then
fail=1
fi
# 5. c++fly admission policy (mcpp design 2026-07-14 §11-Q2, v1):
# c++fly means "toolchain's latest level + every experimental
# gate" — deliberately toolchain-dependent, so a published
# package built with it is not reproducible for consumers.
# Policy: WARN (never fail) and observe ecosystem usage before
# deciding whether to tighten. Two spellings: `language = ` is
# the descriptor's inline mcpp-segment key; `standard = ` covers
# mcpp.toml content embedded in heredoc/generated_files blocks.
if grep -nE '\b(language|standard)[[:space:]]*=[[:space:]]*"c\+\+fly"' "$f" >/dev/null; then
echo "::warning file=$f::declares C++ standard \"c++fly\" (experimental playground mode) — toolchain-dependent and non-reproducible for consumers; published packages should pin a concrete standard (c++23/c++26)"
fi
done
[ $fail -eq 0 ] && echo "All package files valid."
exit $fail
# ── Single-source-of-truth grammar check ─────────────────────────
# `mcpp xpkg parse` uses EXACTLY the resolver's parser, so what
# passes here is what builds for users of the pinned MCPP_VERSION.
# Strict by default: unknown mcpp-segment keys fail (they would be
# silently ignored at build time). This also mechanically enforces
# the rollout rule "floor first, new grammar after": descriptors
# needing a newer grammar cannot pass a lint pinned to an older mcpp.
- name: Download pinned mcpp
run: |
curl -L -fsS -o mcpp.tar.gz \
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
tar -xzf mcpp.tar.gz
echo "MCPP=$PWD/mcpp-${MCPP_VERSION}-linux-x86_64/bin/mcpp" >> "$GITHUB_ENV"
- name: Parse descriptors with the resolver grammar (mcpp xpkg parse)
run: |
fail=0
for f in pkgs/*/*.lua; do
if ! "$MCPP" xpkg parse "$f" > /dev/null; then
echo "::error file=$f::mcpp xpkg parse failed (resolver grammar)"
fail=1
fi
done
[ $fail -eq 0 ] && echo "All descriptors parse with mcpp ${MCPP_VERSION}."
exit $fail
mirror-cn-reachable:
# Closed-loop guard for the CN mirror: every CN url referenced by a
# descriptor must be a live, downloadable gitcode release asset.
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install lua
run: sudo apt-get install -y --no-install-recommends lua5.4
- name: Check CN mirror assets are reachable
run: |
fail=0
# collect unique CN urls across all descriptors
: > /tmp/cn.tsv
for f in pkgs/*/*.lua; do
lua5.4 tests/list_cn_urls.lua "$f" >> /tmp/cn.tsv || true
done
sort -u /tmp/cn.tsv -o /tmp/cn.tsv
total=$(grep -c . /tmp/cn.tsv || true)
echo "checking $total CN mirror url(s)"
while IFS=$'\t' read -r url sha; do
[ -z "$url" ] && continue
# follow redirects; gitcode release assets resolve to object storage
code=$(curl -fsSL -o /dev/null -w '%{http_code}' --retry 2 --max-time 60 "$url" || echo "000")
if [ "$code" != "200" ]; then
echo "::error::CN mirror unreachable ($code): $url"
fail=1
else
echo "ok: $url"
fi
done < /tmp/cn.tsv
[ $fail -eq 0 ] && echo "All CN mirror urls reachable."
exit $fail
# ── The whole test surface, as a mcpp workspace ───────────────────────
# mcpp-index is a mcpp [workspace]; every per-library test project under
# tests/examples/ is a member. `mcpp test --workspace` builds + runs each
# member's tests/ (behavioral assertions) on each OS — members self-gate by
# `[target.'cfg(...)']` (e.g. the X11/glfw stack is linux-only, openblas is
# windows-only), so one command covers the matrix with no shell driver.
# The ~/.mcpp/registry cache carries the built compat packages (xpkgs) across
# runs, so repeat builds are fast.
workspace:
name: workspace (${{ matrix.platform }})
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
include:
# Archive names are derived from env.MCPP_VERSION in the Download
# step — bumping the pin is a ONE-line change (hardcoded versions
# here once 404'd a pin bump).
- platform: linux
os: ubuntu-latest
suffix: linux-x86_64
ext: tar.gz
mcpp: bin/mcpp
xlings: registry/bin/xlings
mcpp_version: "0.0.96" # keep in sync with env.MCPP_VERSION
- platform: macos
os: macos-15
suffix: macosx-arm64
ext: tar.gz
mcpp: bin/mcpp
xlings: registry/bin/xlings
mcpp_version: "0.0.96" # keep in sync with env.MCPP_VERSION
- platform: windows
os: windows-latest
suffix: windows-x86_64
ext: zip
mcpp: bin/mcpp.exe
xlings: registry/bin/xlings.exe
mcpp_version: "0.0.96" # keep in sync with env.MCPP_VERSION
env:
MCPP_EFFECTIVE: ${{ matrix.mcpp_version }}
steps:
# Full history: the member-selection step below diffs against the PR
# base to decide which workspace members to test.
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Restore mcpp registry cache
uses: actions/cache@v4
with:
# Holds toolchains AND the built compat packages (data/xpkgs), so a
# repeat `mcpp test` rebuilds little.
path: ~/.mcpp/registry
key: mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-${{ hashFiles('pkgs/**/*.lua', 'tests/**', '.github/workflows/validate.yml') }}
restore-keys: |
mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-
- name: Download mcpp
shell: bash
env:
MCPP_ARCHIVE: mcpp-${{ env.MCPP_EFFECTIVE }}-${{ matrix.suffix }}.${{ matrix.ext }}
MCPP_ROOT: mcpp-${{ env.MCPP_EFFECTIVE }}-${{ matrix.suffix }}
run: |
curl -L -fsS -o "$MCPP_ARCHIVE" \
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_EFFECTIVE}/${MCPP_ARCHIVE}"
case "$MCPP_ARCHIVE" in
*.zip) powershell -NoProfile -Command "Expand-Archive -Force -Path '${MCPP_ARCHIVE}' -DestinationPath '.'" ;;
*) tar -xzf "$MCPP_ARCHIVE" ;;
esac
root="$PWD/$MCPP_ROOT"
mkdir -p "$HOME/.mcpp/registry"
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
if [[ "$RUNNER_OS" == "Windows" ]]; then
echo "MCPP=$(cygpath -m "$root/${{ matrix.mcpp }}")" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$(cygpath -m "$root/${{ matrix.xlings }}")" >> "$GITHUB_ENV"
echo "$(cygpath -m "$root/bin")" >> "$GITHUB_PATH"
else
echo "MCPP=$root/${{ matrix.mcpp }}" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$root/${{ matrix.xlings }}" >> "$GITHUB_ENV"
echo "$root/bin" >> "$GITHUB_PATH"
fi
# compat.ffmpeg carries NASM .asm sources. No host install needed:
# mcpp >= 0.0.95 resolves nasm itself (PATH → sandbox → auto
# `xlings install nasm`), lazily, only when the plan has .asm units —
# same self-bootstrap contract as the llvm toolchain. The sandbox copy
# lands in ~/.mcpp/registry, so the cache carries it across runs.
# The refresh below is needed because release archives vendor an index
# snapshot and the bootstrap is offline-first: 0.0.96 shipped with a
# nasm.lua deployed engines can't resolve — it "installs" empty
# (mcpp#232; fixed in xim-pkgindex#398 after the release was cut).
# One `mcpp index update` (native wrapper over `xlings update` with
# the sandbox env + transient-network retry) lets the bootstrap see
# the fixed descriptor. Drop once a mcpp release vendors a post-#398
# index snapshot.
- name: Refresh sandbox package index (nasm bootstrap, mcpp#232)
if: runner.os == 'Linux'
shell: bash
run: '"$MCPP" index update'
# ── Selective member testing ──────────────────────────────────────
# `mcpp test --workspace` builds every member (opencv, ffmpeg, …) and
# dominates CI wall-clock, while a PR almost always touches one
# package. Map changed files → affected members and test only those:
# pkgs/<x>/<lib>.lua → members whose mcpp.toml references <lib>
# tests/examples/<m>/** → member <m>
# Run the FULL workspace when the change can affect everything:
# non-PR events (push to main, the nightly cron, dispatch), this
# workflow file (it carries the mcpp version pins, so a version bump
# always re-validates every package), the workspace manifest, or
# shared test scripts. Docs-only changes select nothing.
# Note: bash 3.2 on macOS runners — no associative arrays here.
- name: Select affected workspace members
shell: bash
run: |
full() { echo "MEMBERS=__ALL__" >> "$GITHUB_ENV"; echo "full run: $1"; exit 0; }
[ "${{ github.event_name }}" = "pull_request" ] || full "event=${{ github.event_name }}"
base="origin/${{ github.base_ref }}"
changed=$(git diff --name-only "$base"...HEAD)
printf 'changed files vs %s:\n%s\n' "$base" "$changed"
sel=""
add() { case " $sel " in *" $1 "*) ;; *) sel="$sel $1" ;; esac; }
while IFS= read -r f; do
[ -n "$f" ] || continue
case "$f" in
.github/workflows/validate.yml|tests/*.sh|tools/*) full "$f" ;;
mcpp.toml)
# Workspace manifest. Every new-package PR appends to the
# members list, so that alone must NOT force a full run:
# select the added members; anything else in this file
# (indices, settings) affects everyone → full.
if ! diff -q <(git show "$base:mcpp.toml" | grep -v 'tests/examples/') \
<(grep -v 'tests/examples/' mcpp.toml) >/dev/null; then
full "mcpp.toml non-member change"
fi
for p in $(comm -13 <(git show "$base:mcpp.toml" | grep -o 'tests/examples/[A-Za-z0-9._-]*' | sort -u) \
<(grep -o 'tests/examples/[A-Za-z0-9._-]*' mcpp.toml | sort -u)); do
add "${p#tests/examples/}"
done ;;
tests/examples/*)
m=${f#tests/examples/}; m=${m%%/*}
# A deleted/renamed member dir implies a mcpp.toml edit,
# which already forces a full run above.
[ -d "tests/examples/$m" ] && add "$m" ;;
pkgs/*.lua|pkgs/*/*.lua)
lib=$(basename "$f" .lua); lib=${lib#compat.}
hit=0
for mt in tests/examples/*/mcpp.toml; do
if grep -q "$lib" "$mt"; then add "$(basename "$(dirname "$mt")")"; hit=1; fi
done
[ "$hit" = 1 ] || echo "note: no workspace member exercises $f" ;;
*.md|docs/*|.agents/*|.github/*) : ;;
*) full "unclassified change: $f" ;;
esac
done <<EOF
$changed
EOF
sel=${sel# }
echo "MEMBERS=$sel" >> "$GITHUB_ENV"
echo "selected members: ${sel:-<none>}"
- name: mcpp test (workspace or affected members)
shell: bash
env:
MCPP_INDEX_MIRROR: GLOBAL
run: |
"$MCPP" --version
# No `timeout` wrapper: absent on macOS runners; job-level timeout-minutes bounds it.
if [ "$MEMBERS" = "__ALL__" ]; then
"$MCPP" test --workspace
elif [ -z "$MEMBERS" ]; then
echo "No workspace member affected by this change — nothing to test."
else
rc=0
for m in $MEMBERS; do
echo "::group::mcpp test -p $m"
"$MCPP" test -p "$m" || rc=1
echo "::endgroup::"
done
exit $rc
fi
- name: tinyhttps module package smoke
shell: bash
env:
MCPP_INDEX_MIRROR: GLOBAL
run: bash tests/smoke_tinyhttps_module.sh
# ── Exception: the public `imgui` C++23-module package (namespace "") ──
# Not yet a workspace member: its package has an empty namespace (the builtin
# default index), which a workspace member can't point at a local path the way
# namespaced compat.*/nlohmann packages can. Until mcpp can map the default
# namespace to a local index, this one keeps a thin driver that reseeds the
# default index from the repo. Tracked in the rearchitecture design doc.
imgui-module:
runs-on: ubuntu-latest
timeout-minutes: 60
env:
MCPP_EFFECTIVE: "0.0.96" # keep in sync with env.MCPP_VERSION
steps:
- uses: actions/checkout@v4
- name: Restore mcpp registry cache
uses: actions/cache@v4
with:
path: ~/.mcpp/registry
key: mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-${{ hashFiles('pkgs/**/*.lua', 'tests/**', '.github/workflows/validate.yml') }}
restore-keys: |
mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-
- name: Download mcpp
run: |
curl -L -fsS -o mcpp.tar.gz \
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
tar -xzf mcpp.tar.gz
root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64"
mkdir -p "$HOME/.mcpp/registry"
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV"
echo "$root/bin" >> "$GITHUB_PATH"
- name: imgui module package smoke
env:
MCPP_INDEX_MIRROR: GLOBAL
run: |
"$MCPP" --version
timeout 1800 bash tests/smoke_imgui_module.sh
# ── Exception: the public `ffmpeg` C++23-module package (namespace "") ──
# Same default-namespace limitation as imgui-module above — validated via a
# reseeding smoke driver instead of a workspace member. Linux-only: its
# compat.ffmpeg dependency ships a linux-x86_64 configure snapshot (macOS is
# blocked on mcpp#229 dependency cfg-conditional sources).
ffmpeg-module:
runs-on: ubuntu-latest
timeout-minutes: 60
env:
MCPP_EFFECTIVE: "0.0.96" # keep in sync with env.MCPP_VERSION
steps:
- uses: actions/checkout@v4
- name: Restore mcpp registry cache
uses: actions/cache@v4
with:
path: ~/.mcpp/registry
key: mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-${{ hashFiles('pkgs/**/*.lua', 'tests/**', '.github/workflows/validate.yml') }}
restore-keys: |
mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-
- name: Download mcpp
run: |
curl -L -fsS -o mcpp.tar.gz \
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
tar -xzf mcpp.tar.gz
root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64"
mkdir -p "$HOME/.mcpp/registry"
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV"
echo "$root/bin" >> "$GITHUB_PATH"
- name: ffmpeg module package smoke
env:
MCPP_INDEX_MIRROR: GLOBAL
run: |
"$MCPP" --version
timeout 2700 bash tests/smoke_ffmpeg_module.sh
# ── Exception: the public `opencv` C++23-module package (namespace "") ──
# Same default-namespace limitation as imgui-module above — validated via a
# reseeding smoke driver instead of a workspace member. Linux-only: its
# compat.opencv5 dependency ships a linux-x86_64 config snapshot (macOS is
# blocked on mcpp#229 dependency cfg-conditional sources).
opencv-module:
runs-on: ubuntu-latest
timeout-minutes: 60
env:
MCPP_EFFECTIVE: "0.0.96" # keep in sync with env.MCPP_VERSION
steps:
- uses: actions/checkout@v4
- name: Restore mcpp registry cache
uses: actions/cache@v4
with:
path: ~/.mcpp/registry
key: mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-${{ hashFiles('pkgs/**/*.lua', 'tests/**', '.github/workflows/validate.yml') }}
restore-keys: |
mcpp-registry-${{ runner.os }}-${{ env.MCPP_EFFECTIVE }}-
- name: Download mcpp
run: |
curl -L -fsS -o mcpp.tar.gz \
"https://github.com/mcpp-community/mcpp/releases/download/v${MCPP_VERSION}/mcpp-${MCPP_VERSION}-linux-x86_64.tar.gz"
tar -xzf mcpp.tar.gz
root="$PWD/mcpp-${MCPP_VERSION}-linux-x86_64"
mkdir -p "$HOME/.mcpp/registry"
cp -a "$root/registry/." "$HOME/.mcpp/registry/"
echo "MCPP=$root/bin/mcpp" >> "$GITHUB_ENV"
echo "MCPP_VENDORED_XLINGS=$root/registry/bin/xlings" >> "$GITHUB_ENV"
echo "$root/bin" >> "$GITHUB_PATH"
- name: opencv module package smoke
env:
MCPP_INDEX_MIRROR: GLOBAL
run: |
"$MCPP" --version
timeout 2700 bash tests/smoke_opencv_module.sh