1 name: CI
2
3 on:
4 # Branches only — a tag push must NOT fire CI. Release tags point at a commit
5 # that main already validated, so re-running CI on the tag adds 13 macos jobs
6 # that compete with the release workflows for the shared macOS runner pool.
7 push:
8 branches:
9 - "**"
10 pull_request:
11 workflow_dispatch:
12
13 concurrency:
14 group: ci-${{ github.ref }}
15 cancel-in-progress: true
16
17 permissions:
18 contents: read
19
20 jobs:
21 # ── Release metadata ─────────────────────────────────────────────────────
22 # Same gate the release workflows use, minus the tag check. Running it on
23 # ordinary pushes means version drift surfaces while you are still on a
24 # branch, instead of on release day.
25 preflight:
26 uses: ./.github/workflows/release-preflight.yml
27
28 # ── Dart / Flutter SDK validation ────────────────────────────────────────
29 dart-sdk:
30 name: Dart SDK (Flutter)
31 runs-on: ubuntu-latest
32 steps:
33 - uses: actions/checkout@v6
34 - uses: subosito/flutter-action@v2
35 with:
36 flutter-version-file: sdk/dart/.flutter-version
37 channel: stable
38 cache: true
39 - name: Install Dart dependencies
40 working-directory: sdk/dart
41 run: flutter pub get
42 - name: Analyze Dart package
43 working-directory: sdk/dart
44 run: flutter analyze --no-fatal-infos
45 - name: Analyze score-sensitive generated Dart files
46 working-directory: sdk/dart
47 run: |
48 flutter analyze lib/src/frb_generated.dart/api.dart
49 flutter analyze lib/src/frb_generated.dart/frb_generated.dart
50 flutter analyze lib/src/frb_generated.dart/frb_generated.io.dart
51 - name: Verify Apple SwiftPM manifests exist
52 working-directory: sdk/dart
53 run: |
54 test -f ios/onde_inference/Package.swift
55 test -f ios/onde_inference/Sources/onde_inference/OndeInferencePlugin.swift
56 test -f macos/onde_inference/Package.swift
57 test -f macos/onde_inference/Sources/onde_inference/OndeInferencePlugin.swift
58 - name: Run Dart package tests
59 working-directory: sdk/dart
60 run: flutter test
61 - name: Restore generated files modified by flutter pub get
62 working-directory: sdk/dart
63 run: git checkout -- . 2>/dev/null || true
64 - name: Dry-run Dart publish
65 working-directory: sdk/dart
66 run: flutter pub publish --dry-run
67
68 # ── Formatting ────────────────────────────────────────────────────────────
69 fmt:
70 name: Format
71 runs-on: macos-26
72 steps:
73 - uses: actions/checkout@v6
74 - uses: dtolnay/rust-toolchain@stable
75 with:
76 components: rustfmt
77 - run: cargo fmt --all -- --check
78
79 # ── Lint ──────────────────────────────────────────────────────────────────
80 clippy:
81 name: Clippy (macOS)
82 runs-on: macos-26
83 env:
84 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
85 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
86 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
87 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
88 HF_TOKEN: ${{ secrets.HF_TOKEN }}
89 steps:
90 - uses: actions/checkout@v6
91 - uses: dtolnay/rust-toolchain@stable
92 with:
93 components: clippy
94 - uses: Swatinem/rust-cache@v2
95 with:
96 cache-bin: false
97 - run: cargo clippy --all-targets -- -D warnings
98
99 # ── Tests (macOS — the only platform where tests run natively) ────────────
100 test:
101 name: Test (macOS)
102 runs-on: macos-26
103 env:
104 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
105 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
106 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
107 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
108 HF_TOKEN: ${{ secrets.HF_TOKEN }}
109 steps:
110 - uses: actions/checkout@v6
111 - uses: dtolnay/rust-toolchain@stable
112 - uses: Swatinem/rust-cache@v2
113 with:
114 cache-bin: false
115 - run: cargo test --lib
116
117 # ── Cross-compile checks for Darwin platforms (highest priority) ─────────
118 check-macos-arm64:
119 name: Check (macOS arm64)
120 runs-on: macos-26
121 env:
122 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
123 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
124 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
125 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
126 HF_TOKEN: ${{ secrets.HF_TOKEN }}
127 steps:
128 - uses: actions/checkout@v6
129 - uses: dtolnay/rust-toolchain@stable
130 with:
131 targets: aarch64-apple-darwin
132 - uses: Swatinem/rust-cache@v2
133 with:
134 cache-bin: false
135 key: macos-arm64
136 - run: cargo check --target aarch64-apple-darwin
137
138 check-macos-intel:
139 name: Check (macOS x86_64)
140 runs-on: macos-26
141 env:
142 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
143 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
144 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
145 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
146 HF_TOKEN: ${{ secrets.HF_TOKEN }}
147 steps:
148 - uses: actions/checkout@v6
149 - uses: dtolnay/rust-toolchain@stable
150 with:
151 targets: x86_64-apple-darwin
152 - uses: Swatinem/rust-cache@v2
153 with:
154 cache-bin: false
155 key: macos-intel
156 - run: cargo check --target x86_64-apple-darwin
157
158 check-ios:
159 name: Check (iOS device)
160 runs-on: macos-26
161 env:
162 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
163 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
164 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
165 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
166 HF_TOKEN: ${{ secrets.HF_TOKEN }}
167 steps:
168 - uses: actions/checkout@v6
169 - uses: dtolnay/rust-toolchain@stable
170 with:
171 targets: aarch64-apple-ios
172 - uses: Swatinem/rust-cache@v2
173 with:
174 cache-bin: false
175 key: ios
176 - run: cargo check --target aarch64-apple-ios
177
178 check-ios-sim:
179 name: Check (iOS simulator)
180 runs-on: macos-26
181 env:
182 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
183 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
184 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
185 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
186 HF_TOKEN: ${{ secrets.HF_TOKEN }}
187 steps:
188 - uses: actions/checkout@v6
189 - uses: dtolnay/rust-toolchain@stable
190 with:
191 targets: aarch64-apple-ios-sim
192 - uses: Swatinem/rust-cache@v2
193 with:
194 cache-bin: false
195 key: ios-sim
196 - run: cargo check --target aarch64-apple-ios-sim
197
198 check-tvos:
199 name: Check (tvOS device)
200 runs-on: macos-26
201 env:
202 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
203 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
204 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
205 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
206 HF_TOKEN: ${{ secrets.HF_TOKEN }}
207 steps:
208 - uses: actions/checkout@v6
209 - uses: dtolnay/rust-toolchain@nightly
210 with:
211 components: rust-src
212 - uses: Swatinem/rust-cache@v2
213 with:
214 cache-bin: false
215 key: tvos
216 - run: cargo +nightly check -Z build-std --target aarch64-apple-tvos
217
218 check-tvos-sim:
219 name: Check (tvOS simulator)
220 runs-on: macos-26
221 env:
222 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
223 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
224 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
225 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
226 HF_TOKEN: ${{ secrets.HF_TOKEN }}
227 steps:
228 - uses: actions/checkout@v6
229 - uses: dtolnay/rust-toolchain@nightly
230 with:
231 components: rust-src
232 - uses: Swatinem/rust-cache@v2
233 with:
234 cache-bin: false
235 key: tvos-sim
236 - run: cargo +nightly check -Z build-std --target aarch64-apple-tvos-sim
237
238 check-visionos:
239 name: Check (visionOS device)
240 runs-on: macos-26
241 env:
242 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
243 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
244 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
245 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
246 HF_TOKEN: ${{ secrets.HF_TOKEN }}
247 steps:
248 - uses: actions/checkout@v6
249 - uses: dtolnay/rust-toolchain@nightly
250 with:
251 components: rust-src
252 - uses: Swatinem/rust-cache@v2
253 with:
254 cache-bin: false
255 key: visionos
256 - run: cargo +nightly check -Z build-std --target aarch64-apple-visionos
257
258 check-visionos-sim:
259 name: Check (visionOS simulator)
260 runs-on: macos-26
261 env:
262 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
263 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
264 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
265 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
266 HF_TOKEN: ${{ secrets.HF_TOKEN }}
267 steps:
268 - uses: actions/checkout@v6
269 - uses: dtolnay/rust-toolchain@nightly
270 with:
271 components: rust-src
272 - uses: Swatinem/rust-cache@v2
273 with:
274 cache-bin: false
275 key: visionos-sim
276 - run: cargo +nightly check -Z build-std --target aarch64-apple-visionos-sim
277
278 check-watchos:
279 name: Check (watchOS device)
280 runs-on: macos-26
281 env:
282 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
283 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
284 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
285 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
286 HF_TOKEN: ${{ secrets.HF_TOKEN }}
287 steps:
288 - uses: actions/checkout@v6
289 - uses: dtolnay/rust-toolchain@nightly
290 with:
291 components: rust-src
292 - uses: Swatinem/rust-cache@v2
293 with:
294 cache-bin: false
295 key: watchos
296 - run: cargo +nightly check -Z build-std --target aarch64-apple-watchos
297
298 check-watchos-sim:
299 name: Check (watchOS simulator)
300 runs-on: macos-26
301 env:
302 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
303 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
304 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
305 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
306 HF_TOKEN: ${{ secrets.HF_TOKEN }}
307 steps:
308 - uses: actions/checkout@v6
309 - uses: dtolnay/rust-toolchain@nightly
310 with:
311 components: rust-src
312 - uses: Swatinem/rust-cache@v2
313 with:
314 cache-bin: false
315 key: watchos-sim
316 - run: cargo +nightly check -Z build-std --target aarch64-apple-watchos-sim
317
318 # ── Cross-compile checks for Unix-family platforms ────────────────────────
319 check-linux:
320 name: Check (Linux x86_64)
321 runs-on: ubuntu-latest
322 env:
323 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
324 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
325 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
326 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
327 HF_TOKEN: ${{ secrets.HF_TOKEN }}
328 steps:
329 - uses: actions/checkout@v6
330 - uses: dtolnay/rust-toolchain@stable
331 with:
332 targets: x86_64-unknown-linux-gnu
333 - uses: Swatinem/rust-cache@v2
334 with:
335 cache-bin: false
336 key: linux-x86_64
337 - run: cargo check --target x86_64-unknown-linux-gnu
338
339 check-android:
340 name: Check (Android arm64)
341 runs-on: ubuntu-latest
342 env:
343 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
344 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
345 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
346 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
347 HF_TOKEN: ${{ secrets.HF_TOKEN }}
348 CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER: aarch64-linux-android34-clang
349 CC_aarch64_linux_android: aarch64-linux-android34-clang
350 AR_aarch64_linux_android: llvm-ar
351 steps:
352 - uses: actions/checkout@v6
353 - uses: dtolnay/rust-toolchain@stable
354 with:
355 targets: aarch64-linux-android
356 - uses: android-actions/setup-android@v4
357 - name: Configure Android NDK toolchain
358 shell: bash
359 run: |
360 echo "${ANDROID_NDK_LATEST_HOME}/toolchains/llvm/prebuilt/linux-x86_64/bin" >> "$GITHUB_PATH"
361 - uses: Swatinem/rust-cache@v2
362 with:
363 cache-bin: false
364 key: android-arm64
365 - run: cargo check --target aarch64-linux-android
366
367 # ── Cross-compile checks for Windows (lowest priority) ────────────────────
368 check-windows:
369 name: Check (Windows x86_64)
370 runs-on: windows-latest
371 env:
372 GRESIQ_API_KEY_DEV: ${{ secrets.GRESIQ_API_KEY_DEV }}
373 GRESIQ_API_SECRET_DEV: ${{ secrets.GRESIQ_API_SECRET_DEV }}
374 GRESIQ_API_KEY_PRODUCTION: ${{ secrets.GRESIQ_API_KEY_PRODUCTION }}
375 GRESIQ_API_SECRET_PRODUCTION: ${{ secrets.GRESIQ_API_SECRET_PRODUCTION }}
376 HF_TOKEN: ${{ secrets.HF_TOKEN }}
377 steps:
378 - uses: actions/checkout@v6
379 - uses: dtolnay/rust-toolchain@stable
380 with:
381 targets: x86_64-pc-windows-msvc
382 - uses: Swatinem/rust-cache@v2
383 with:
384 cache-bin: false
385 key: windows-x86_64
386 - run: cargo check --target x86_64-pc-windows-msvc