Repository navigation
366 lines (331 loc) · 14.3 KB
/
Copy pathci.yml
File metadata and controls
366 lines (331 loc) · 14.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
name: CI
on:
push:
branches: [ "main" ]
paths-ignore:
- '**.md'
- 'LICENSE'
pull_request:
branches: [ "main" ]
paths-ignore:
- '**.md'
- 'LICENSE'
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}-${{ github.head_ref || '' }}-${{ github.base_ref || '' }}-${{ github.ref != 'refs/heads/main' || github.sha }}
cancel-in-progress: true
permissions:
contents: read
jobs:
# ===========================================================================
# Style: Checkstyle over the hand-written sources. Own job, not a step of the
# matrix legs - it needs neither the submodule nor a native build, so a
# violation surfaces in about a minute instead of after the 48-minute linux
# compile. `checkstyle:check` is a direct goal invocation and therefore does
# not trigger the generate-sources JavaCPP parser either.
# ===========================================================================
lint:
name: Checkstyle
runs-on: ubuntu-24.04
timeout-minutes: 15
steps:
- name: Checkout code
uses: actions/checkout@v7
- name: Set up JDK 11
uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '11'
cache: maven
- name: Run Checkstyle
run: mvn checkstyle:check -B
# ===========================================================================
# Source Mode: Build zvec C library from submodule, then run full test suite
# ===========================================================================
source-test:
name: Source (${{ matrix.name }})
runs-on: ${{ matrix.runner }}
# Longest observed leg is the linux-x64 zvec build at ~48m; the two extra
# platforms build in about the same time upstream (windows-arm64 ~42m,
# osx-amd64 ~41m). The ceiling exists to stop a hung toolchain from burning
# runner minutes for 6 hours.
timeout-minutes: 120
strategy:
fail-fast: false
matrix:
include:
- name: macos-arm64
runner: macos-15
- name: macos-x64
# Intel macOS, the runner upstream zvec builds its own osx-amd64 SDK
# on (zvec/.github/workflows/_build_macos_x64_sdk.yml).
# macos-15-intel is the last x86_64 macOS image Actions offers and is
# slated for retirement in August 2027; this leg has to be dropped or
# moved to a self-hosted Intel runner then, and the macosx-x86_64
# classifier with it unless upstream keeps shipping that SDK.
runner: macos-15-intel
# Without the deployment target clang aims at the runner's own macOS
# and dyld then refuses to load the dylib on anything older; without
# the architecture an Apple-toolchain default could creep in. Both
# values are the ones upstream uses for this platform.
cmake_platform_args: '-DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0'
- name: linux-x64
runner: ubuntu-24.04
- name: windows-x64
runner: windows-2025
- name: windows-arm64
# Native Windows on ARM, the runner upstream zvec publishes its
# aarch64-pc-windows-msvc SDK from (zvec/_build_prebuilt.yml).
runner: windows-11-arm
msvc_arch: arm64
# Temurin ships no Windows/aarch64 JDK before 21, so this leg cannot
# use the 11 the others do. It only changes the JVM that runs Maven:
# the sources still compile to 1.8 bytecode through
# maven.compiler.source/target in pom.xml.
java_version: '21'
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
submodules: recursive
# --- Set up Java ---
- name: Set up JDK ${{ matrix.java_version || '11' }}
uses: actions/setup-java@v6
with:
distribution: temurin
java-version: ${{ matrix.java_version || '11' }}
cache: maven
# --- Version-anchored cache: keyed by the zvec submodule commit ---
- name: Resolve zvec submodule commit
id: zvec
shell: bash
run: echo "sha=$(git -C zvec rev-parse HEAD)" >> "$GITHUB_OUTPUT"
# Restore-only. The matching save step lives right after the build steps
# and is gated on a marker file they write on success, so a good build
# tree is reused even when a later step (the Maven tests) fails, while a
# half-built tree is never cached.
- name: Restore zvec build cache
id: cache-zvec
uses: actions/cache/restore@v6
with:
path: zvec/build
key: zvec-build-${{ matrix.name }}-${{ steps.zvec.outputs.sha }}
# --- Unix build tools ---
- name: Set up Python (for CMake / Ninja)
if: runner.os != 'Windows' && steps.cache-zvec.outputs.cache-hit != 'true'
uses: actions/setup-python@v7
with:
python-version: '3.10'
- name: Install build tools (Unix)
if: runner.os != 'Windows' && steps.cache-zvec.outputs.cache-hit != 'true'
run: |
python -m pip install --upgrade pip cmake==3.30.0 ninja==1.11.1
echo "$(python -c 'import site; print(site.USER_BASE)')/bin" >> $GITHUB_PATH
shell: bash
# --- Windows build tools ---
- name: Set up MSVC (Windows)
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1 (pinned by SHA; dependabot keeps it current)
with:
# arm64 on the windows-arm64 leg; the action defaults to x64, which
# would silently cross-compile an x64 toolchain on an ARM runner.
arch: ${{ matrix.msvc_arch || 'x64' }}
- name: Install CMake and Ninja (Windows)
if: runner.os == 'Windows' && steps.cache-zvec.outputs.cache-hit != 'true'
run: pip install cmake==3.30.0 ninja==1.11.1
shell: pwsh
# --- Build C-API library ---
- name: Build C-API library (Unix)
if: runner.os != 'Windows' && steps.cache-zvec.outputs.cache-hit != 'true'
env:
ZVEC_PLATFORM_ARGS: ${{ matrix.cmake_platform_args || '' }}
run: |
NPROC=$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 2)
cd zvec
mkdir -p build && cd build
cmake .. \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_C_BINDINGS=ON \
$ZVEC_PLATFORM_ARGS \
-G Ninja
cmake --build . -j$NPROC --target zvec_c_api
touch .zvec-build-ok
shell: bash
- name: Build C-API library (Windows)
if: runner.os == 'Windows' && steps.cache-zvec.outputs.cache-hit != 'true'
run: |
cd zvec
New-Item -ItemType Directory -Force -Path build | Out-Null
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DBUILD_C_BINDINGS=ON -G Ninja
cmake --build . --target zvec_c_api -j $env:NUMBER_OF_PROCESSORS
New-Item -ItemType File -Force -Path .zvec-build-ok | Out-Null
shell: pwsh
# Cache the build tree as soon as it is known good, so a later failure
# does not cost another full C++ build on the next run. The marker file
# written above is the gate: without it the build failed (or was skipped
# on a cache hit), and storing an incomplete tree would poison every
# subsequent run that resolves this exact key — there are no
# restore-keys, so a bad entry cannot self-heal.
# continue-on-error absorbs the 409 that actions/cache/save raises when a
# concurrent run already stored this key — the cache is an optimization,
# never a reason to fail the build.
- name: Save zvec build cache
if: always() && steps.cache-zvec.outputs.cache-hit != 'true' && hashFiles('zvec/build/.zvec-build-ok') != ''
uses: actions/cache/save@v6
continue-on-error: true
with:
path: zvec/build
key: zvec-build-${{ matrix.name }}-${{ steps.zvec.outputs.sha }}
- name: Verify C-API library (Unix)
if: runner.os != 'Windows'
run: |
echo "=== Built libraries ==="
ls -la zvec/build/lib/
shell: bash
- name: Verify C-API library (Windows)
if: runner.os == 'Windows'
run: |
Write-Host "=== Built libraries ==="
Get-ChildItem -Recurse zvec/build/ -Include *.dll,*.lib -ErrorAction SilentlyContinue | ForEach-Object { Write-Host $_.FullName }
shell: pwsh
# --- Add DLL to PATH (Windows runtime) ---
- name: Add C-API library to PATH (Windows)
if: runner.os == 'Windows'
run: |
$dirs = @(
"${{ github.workspace }}\zvec\build\lib\Release",
"${{ github.workspace }}\zvec\build\lib",
"${{ github.workspace }}\zvec\build\bin\Release",
"${{ github.workspace }}\zvec\build\bin"
)
foreach ($d in $dirs) {
if (Test-Path $d) {
echo "$d" >> $env:GITHUB_PATH
Write-Host "Added to PATH: $d"
}
}
shell: pwsh
# --- Run tests (Maven) ---
- name: Run tests (Unix)
if: runner.os != 'Windows'
run: |
LIB_PATH="${{ github.workspace }}/zvec/build/lib"
mvn test -Dzvec.lib.path="$LIB_PATH" -B
shell: bash
- name: Run tests (Windows)
if: runner.os == 'Windows'
run: |
# Locate the built DLL directory
$candidates = @(
"${{ github.workspace }}\zvec\build\lib\Release",
"${{ github.workspace }}\zvec\build\lib"
)
$libPath = $candidates | Where-Object { Test-Path $_ } | Select-Object -First 1
Write-Host "Using lib path: $libPath"
mvn test "-Dzvec.lib.path=$libPath" -B
shell: pwsh
# ===========================================================================
# Vendor Mode: Test with pre-built libraries shipped in lib/ directory
# ===========================================================================
vendor-test:
name: Vendor (${{ matrix.name }})
runs-on: ${{ matrix.runner }}
# No compilation: download the LFS libraries and run the suite.
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
- name: macos-arm64
runner: macos-15
lib_subdir: darwin_arm64
lib_ext: dylib
- name: linux-x64
runner: ubuntu-24.04
lib_subdir: linux_amd64
lib_ext: so
- name: windows-x64
runner: windows-2025
lib_subdir: windows_amd64
lib_ext: dll
steps:
- name: Checkout code
uses: actions/checkout@v7
with:
lfs: true
- name: Set up JDK 11
uses: actions/setup-java@v6
with:
distribution: temurin
java-version: '11'
cache: maven
# --- Check vendor libs availability ---
- name: Verify vendor libraries exist (Unix)
if: runner.os != 'Windows'
run: |
LIB_PATH="lib/${{ matrix.lib_subdir }}"
echo "=== Checking vendor libraries in $LIB_PATH ==="
if [ ! -d "$LIB_PATH" ] || [ -z "$(ls -A "$LIB_PATH" 2>/dev/null)" ]; then
echo "⚠ No vendor libraries found in $LIB_PATH — skipping vendor test"
echo "VENDOR_LIBS_AVAILABLE=false" >> $GITHUB_ENV
else
ls -la "$LIB_PATH/"
echo "VENDOR_LIBS_AVAILABLE=true" >> $GITHUB_ENV
fi
shell: bash
- name: Verify vendor libraries exist (Windows)
if: runner.os == 'Windows'
run: |
$libPath = "lib\${{ matrix.lib_subdir }}"
Write-Host "=== Checking vendor libraries in $libPath ==="
if (-not (Test-Path $libPath) -or (Get-ChildItem $libPath -ErrorAction SilentlyContinue).Count -eq 0) {
Write-Host "⚠ No vendor libraries found in $libPath — skipping vendor test"
echo "VENDOR_LIBS_AVAILABLE=false" >> $env:GITHUB_ENV
} else {
Get-ChildItem $libPath
echo "VENDOR_LIBS_AVAILABLE=true" >> $env:GITHUB_ENV
}
shell: pwsh
# --- Set library search paths ---
- name: Set library path (macOS)
if: runner.os == 'macOS' && env.VENDOR_LIBS_AVAILABLE == 'true'
run: |
LIB_PATH="${{ github.workspace }}/lib/${{ matrix.lib_subdir }}"
echo "DYLD_LIBRARY_PATH=$LIB_PATH:${DYLD_LIBRARY_PATH:-}" >> $GITHUB_ENV
shell: bash
- name: Set library path (Linux)
if: runner.os == 'Linux' && env.VENDOR_LIBS_AVAILABLE == 'true'
run: |
LIB_PATH="${{ github.workspace }}/lib/${{ matrix.lib_subdir }}"
echo "LD_LIBRARY_PATH=$LIB_PATH:${LD_LIBRARY_PATH:-}" >> $GITHUB_ENV
shell: bash
- name: Add vendor library to PATH (Windows)
if: runner.os == 'Windows' && env.VENDOR_LIBS_AVAILABLE == 'true'
run: |
$libPath = "${{ github.workspace }}\lib\${{ matrix.lib_subdir }}"
echo "$libPath" >> $env:GITHUB_PATH
Write-Host "Added to PATH: $libPath"
shell: pwsh
# --- Run tests ---
# JavaCPP still needs to parse c_api.h and compile the JNI glue in vendor
# mode, so point it at the header shipped alongside the pre-built libs
# (lib/include/zvec/c_api.h) and link against the vendored library.
- name: Run tests (Unix, vendor mode)
if: runner.os != 'Windows' && env.VENDOR_LIBS_AVAILABLE == 'true'
run: |
LIB_PATH="${{ github.workspace }}/lib/${{ matrix.lib_subdir }}"
INC_PATH="${{ github.workspace }}/lib/include"
mvn test -Dzvec.lib.path="$LIB_PATH" -Dzvec.include.path="$INC_PATH" -B
shell: bash
- name: Run tests (Windows, vendor mode)
if: runner.os == 'Windows' && env.VENDOR_LIBS_AVAILABLE == 'true'
run: |
$libPath = "${{ github.workspace }}\lib\${{ matrix.lib_subdir }}"
$incPath = "${{ github.workspace }}\lib\include"
mvn test "-Dzvec.lib.path=$libPath" "-Dzvec.include.path=$incPath" -B
shell: pwsh
- name: Skip notice
if: env.VENDOR_LIBS_AVAILABLE == 'false'
run: echo "ℹ Vendor test skipped — no pre-built libraries committed to lib/${{ matrix.lib_subdir }}"
shell: bash