-
Notifications
You must be signed in to change notification settings - Fork 1
299 lines (275 loc) · 11.5 KB
/
ci.yml
File metadata and controls
299 lines (275 loc) · 11.5 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
name: ci
on:
push:
branches: [main]
pull_request:
jobs:
build:
name: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# Pinned runner labels so a future GHA image bump doesn't
# silently shift the matrix. `ubuntu-24.04-arm` is the GHA
# ARM64 Linux tier (added 2024); together with `ubuntu-24.04`
# we cover both Linux architectures natively. `macos-14` is
# Apple Silicon. `windows-2022` is x86_64 Windows.
os: [ubuntu-24.04, ubuntu-24.04-arm, macos-14, windows-2022]
runs-on: ${{ matrix.os }}
defaults:
run:
shell: bash
env:
CC: ${{ matrix.os == 'windows-2022' && 'gcc' || 'cc' }}
steps:
- uses: actions/checkout@v4
- name: Compiler version
run: |
$CC --version
# On ubuntu-24.04 the alt-versions are also available; print
# them so a future regression that's gcc-13-specific (or
# 12-specific) is easier to triage.
if [ "${{ matrix.os }}" = "ubuntu-24.04" ] || [ "${{ matrix.os }}" = "ubuntu-24.04-arm" ]; then
for v in 12 13 14; do
if command -v gcc-$v >/dev/null; then
gcc-$v --version | head -1
fi
done
fi
- name: Bootstrap mino
# Generates the bundled-source headers and compiles ./mino in
# one step. Anything beyond bootstrap belongs in `./mino task`.
# Tee stderr so a build failure leaves a captured log for the
# post-step summary below; the live step output stays
# unchanged for anyone with log access.
run: |
set -o pipefail
make 2>&1 | tee /tmp/build.log
- name: Surface build failure
# When the build step above fails, post the captured tail on
# the job summary page so anyone with Actions UI access (incl.
# signed-in external contributors) sees what broke without
# having to download artifacts.
if: failure()
run: |
{
echo "## Build failure (${{ matrix.os }})"
echo ''
echo '```'
tail -60 /tmp/build.log 2>/dev/null || echo '(no build log captured)'
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
- name: Upload build log on failure
# Artifacts are downloadable from the Actions page anonymously
# for public repositories, so this is the path for off-repo
# observers (and for the project bot) to see the actual gcc
# error output without needing log-download permission.
if: failure()
uses: actions/upload-artifact@v4
with:
name: build-log-${{ matrix.os }}
path: /tmp/build.log
retention-days: 7
- name: Test
# Run the suite runner directly so stdout streams. `task test`
# wraps the subprocess in sh!, which buffers output until exit;
# under a hang, no diagnostic ever surfaces.
#
# MINO_TEST_TRACE=1 prints one stderr line per deftest before
# it runs; combined with capturing stderr into a file and
# tee'ing it to the job log, the last visible trace line
# pinpoints any hanging test. The stderr capture is what makes
# an opaque "Test timed out" actionable. Keeps trace off
# locally (env-gated) so a normal `./mino tests/run.clj`
# produces the same output as before.
#
# Watchdog wrapper: GHA's timeout-minutes sends a SIGKILL after
# the cap, which gives no diagnostic at all on a hang. We
# spawn mino in the background, sleep just inside the cap,
# then SIGABRT it -- mino's crash_handler (main.c:711) prints
# a backtrace + gc stats on SIGABRT, so a hang now leaves a
# readable stack in the log instead of a silent kill. mino
# exits non-zero after the dump, which fails the step
# normally (no continue-on-error masking).
env:
MINO_TEST_TRACE: "1"
run: |
set +e
# Pre-create + tail the trace file so its lines stream to
# the live job log as mino emits them. Without the tail,
# the trace only appears via the failure artifact, which
# makes a live `gh run watch` opaque.
: > /tmp/test_trace.log
(tail -F /tmp/test_trace.log 2>/dev/null) &
TAIL_PID=$!
# exec replaces the subshell with mino so $! is mino's
# pid directly -- the watchdog's kill -ABRT then lands
# on mino, not on an outer shell wrapper.
(exec ./mino tests/run.clj) 2> /tmp/test_trace.log &
MINO_PID=$!
# Wake at 7m30s (the cap is 8m) so SIGABRT has time to
# run mino's handler before GHA's own SIGKILL lands.
# mino's crash_handler (main.c:711) prints a backtrace +
# GC stats on SIGABRT, so a hang now leaves a readable
# stack in the log + trace artifact instead of a silent
# kill. mino exits 134 (128 + SIGABRT) after the dump.
(sleep 450; if kill -0 $MINO_PID 2>/dev/null; then
echo "##[warning]Watchdog firing SIGABRT on hung mino (pid $MINO_PID)"
kill -ABRT $MINO_PID
fi) &
WD_PID=$!
wait $MINO_PID
RC=$?
# Give the trace tail a moment to flush mino's last lines.
sleep 1
kill $WD_PID 2>/dev/null || true
kill $TAIL_PID 2>/dev/null || true
exit $RC
# Tests usually finish in seconds; a hang means a deadlock, not
# a slow runner. Cap so we get diagnostic output instead of
# waiting on the 6h job-default timeout. The watchdog above
# fires 30s before this cap so we keep the stack trace.
timeout-minutes: 8
# The Windows test suite has documented divergence: cmd.exe's
# echo emits a trailing space before \n, which the proc-test
# assertions do not strip. Build still must pass; tests are
# informational on Windows until the suite is portable.
continue-on-error: ${{ matrix.os == 'windows-2022' }}
- name: Upload test trace on failure
# The trace captures each deftest entry; the last line shows
# what was running when the timeout fired. Artifacts are
# public on the run page so triage doesn't require log
# download permission.
if: failure()
uses: actions/upload-artifact@v4
with:
name: test-trace-${{ matrix.os }}
path: /tmp/test_trace.log
retention-days: 7
if-no-files-found: ignore
- name: Release gate
# The composite gate -- check-reloc-mirror, check-stencil-
# registry, check-stencils-fresh, the test suite under ASan,
# and 4-way JIT parity (auto / on / off / lean) -- runs on
# every non-Windows matrix entry. Windows skips the gate
# because the gate's ASan step needs a libsanitizer that
# mingw doesn't ship.
if: matrix.os != 'windows-2022'
run: ./mino task release-gate
timeout-minutes: 12
cross-compile:
name: cross-compile (stencil-fresh on every target)
runs-on: macos-14
needs: build
# Cross-compiles every stencil header on macOS via the
# gen-stencils-<arch>-<os> tasks, then asserts the committed
# byte tables match the freshly-generated ones. Catches
# toolchain drift on targets the runtime can't book end-to-end
# from CI (notably x86_64 Darwin, where GHA's Intel Mac runners
# have been retiring).
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Bootstrap mino
run: make
- name: Cross-compile every target's stencils
# gen-stencils-* writes to src/eval/bc/stencils/generated/.
# If the toolchain produces different bytes than what's
# committed, the git diff below trips and the job fails.
run: |
./mino task gen-stencils-arm64-linux
./mino task gen-stencils-x86-64-linux
./mino task gen-stencils-x86-64-darwin
./mino task gen-stencils-x86-64-windows
- name: Verify generated stencils match committed
# The repo never holds stale stencil headers; if the
# toolchain drift produced different output, the diff is
# the diagnostic.
run: |
if ! git diff --exit-code -- src/eval/bc/stencils/generated/; then
echo "::error::Cross-compiled stencil headers diverge from committed bytes"
exit 1
fi
echo "All cross-compiled stencil headers match committed bytes"
external-test-suite:
name: external-test-suite (clojure-test-suite)
runs-on: ubuntu-latest
needs: build
# The external test suite is a snapshot of jank-lang/clojure-test-suite
# run against the current mino build. Each .cljc file runs in its own
# `./mino` sub-process under a 30s timeout (handled by the driver),
# so a segfault or hang in one file doesn't take down the rest.
# Informational: the job reports the supported / failed / errored
# counts but does not gate merges.
continue-on-error: true
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
with:
path: mino
- name: Checkout clojure-test-suite
uses: actions/checkout@v4
with:
repository: jank-lang/clojure-test-suite
path: clojure-test-suite
- name: Bootstrap mino
working-directory: mino
run: make
- name: Run external suite
working-directory: mino
# The driver expects the suite as a sibling of mino/, which the
# checkout layout above already gives us. tee the output so the
# next step can pull the summary without re-running the suite.
run: |
set -o pipefail
./mino tests/clojure_test_suite.clj 2>&1 \
| tee /tmp/external_suite.log
- name: Surface aggregate counts
# Pull the summary block out of the captured log and post it as
# the job summary so the Actions UI shows pass / fail counts
# without scrolling.
if: always()
run: |
{
echo "## External test suite summary"
echo ''
echo '```'
sed -n '/EXTERNAL TEST SUITE REPORT/,/Per-file raw results/p' \
/tmp/external_suite.log 2>/dev/null \
| head -100 || true
echo '```'
} >> "$GITHUB_STEP_SUMMARY"
perf-gate:
name: perf-gate (linux)
runs-on: ubuntu-latest
needs: build
# Shared GitHub-hosted runners are CPU-noisy and the runner image
# itself drifts (ubuntu-latest tracks the newest stable image), so
# the perf-gate is informational here. Local runs and the dedicated
# mino-bench workflow remain the authoritative signal.
continue-on-error: true
steps:
- name: Checkout mino at current SHA
uses: actions/checkout@v4
with:
path: mino-head
- name: Checkout mino-bench
uses: actions/checkout@v4
with:
repository: leifericf/mino-bench
path: mino-bench
submodules: recursive
- name: Override mino submodule to this SHA
working-directory: mino-bench
run: |
rm -rf mino
cp -R ../mino-head mino
- name: Bootstrap mino
working-directory: mino-bench/mino
run: make
- name: Build bench binaries
working-directory: mino-bench
run: ./mino/mino task build
- name: Run perf gate
working-directory: mino-bench
run: ./mino/mino task perf-gate