better auto gpu selection (#76) #122
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: swift-ci | |
| # Every-PR gates for the Swift binding (TranscribeCpp). Thin per-binding | |
| # workflow on the shared rails: the binding-agnostic C contracts are certified | |
| # in native-ci.yml; this file adds only what the Swift layer introduces. | |
| # | |
| # - swift-gates: the public-ABI drift gate — the pinned hash in | |
| # ABIHash.swift compared against include/transcribe.abihash | |
| # (scripts/ci/swift_abihash_check.py). No native build; fast, | |
| # runs everywhere. (Swift has no generated FFI layer: the | |
| # Clang importer reads the headers directly, so the gate is a | |
| # pinned constant, not a regen check. Version-sync is the git | |
| # tag + the load-time gate, not check_version_sync.py.) | |
| # - swift-macos: build the macOS slice of the xcframework | |
| # (scripts/ci/build_xcframework.sh), then `swift test` the | |
| # no-model tier against the real binaryTarget — the Swift | |
| # analog of Rust's no_model.rs (version/ABI/device discovery). | |
| # - swift-ios: cross-compile the iOS device + simulator slices | |
| # (build-verify only — no iOS runner executes models here). | |
| # | |
| # Two test tiers (requirements §4): the no-model tests always run; the | |
| # model-gated tier (real transcription/streaming/cancel/family ext) un-skips | |
| # only when the canary GGUFs are fetched (fetch-canary + HF_TOKEN). The model | |
| # tier lands with M4 — this workflow ships the no-model tier first. | |
| # | |
| # Path filters follow native-ci.yml's shape: the binding's own tree plus the | |
| # native paths it compiles from (binding behavior depends on the C side). | |
| on: | |
| push: | |
| branches: [main] | |
| paths: &paths | |
| - "bindings/swift/**" | |
| - "src/**" | |
| - "include/**" | |
| - "ggml/**" | |
| - "cmake/**" | |
| - "CMakeLists.txt" | |
| - "CMakePresets.json" | |
| - "scripts/ci/build_xcframework.sh" | |
| - "scripts/ci/swift_abihash_check.py" | |
| - ".github/workflows/swift-ci.yml" | |
| pull_request: | |
| paths: *paths | |
| workflow_dispatch: | |
| concurrency: | |
| group: swift-ci-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| swift-gates: | |
| runs-on: blacksmith-2vcpu-ubuntu-2404 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: astral-sh/setup-uv@v8.2.0 | |
| - name: Public-ABI drift gate (pinned hash vs include/transcribe.abihash) | |
| run: uv run --no-project scripts/ci/swift_abihash_check.py | |
| swift-macos: | |
| runs-on: [self-hosted, macOS, ARM64] | |
| env: | |
| # The CMake builds inside build_xcframework.sh honor these launcher env | |
| # vars (CMake initializes CMAKE_<LANG>_COMPILER_LAUNCHER from them). | |
| CMAKE_C_COMPILER_LAUNCHER: ccache | |
| CMAKE_CXX_COMPILER_LAUNCHER: ccache | |
| # Present on this repo's runs, empty on forks — fetch-canary skips cleanly | |
| # when empty and the model tier of `swift test` then XCTSkips. | |
| HF_TOKEN: ${{ secrets.HF_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: astral-sh/setup-uv@v8.2.0 # fetch-canary fetches via uvx | |
| - name: Install build deps | |
| run: brew install ninja ccache | |
| - uses: actions/cache@v4 | |
| with: | |
| path: ~/Library/Caches/ccache | |
| key: ccache-swift-macos-${{ github.sha }} | |
| restore-keys: ccache-swift-macos- | |
| - name: Build the macOS xcframework slice | |
| run: TRANSCRIBE_XCFRAMEWORK_SLICES="macos" scripts/ci/build_xcframework.sh | |
| # Fetch the canary GGUFs (whisper-tiny + moonshine-streaming-tiny) and | |
| # export TRANSCRIBE_SMOKE_MODEL / _STREAMING_MODEL. Audio falls back to the | |
| # in-repo samples/jfk.wav. Skips cleanly without HF_TOKEN (the model tier | |
| # then XCTSkips — the two-tier scheme, requirements §4). | |
| - uses: ./.github/actions/fetch-canary | |
| with: | |
| hf-token: ${{ secrets.HF_TOKEN }} | |
| # The xcframework ships a DYNAMIC CTranscribe.framework (so app consumers | |
| # need no -ObjC and Xcode auto-embeds it). Command-line `swift test` / | |
| # `swift run`, unlike Xcode, don't reliably stage that framework into the | |
| # built binary's runtime search path across toolchains (an Xcode-beta | |
| # runner fails to; stable Xcode happens to succeed) — so point an rpath at | |
| # the built macOS slice. DYLD_FRAMEWORK_PATH won't do it: the hardened | |
| # swiftpm test helper strips DYLD_* env vars. | |
| - name: swift test (no-model + model tiers) | |
| working-directory: bindings/swift | |
| run: | | |
| FW_DIR="$(cd build-apple/TranscribeCpp.xcframework/macos-*/ && pwd)" | |
| swift test -Xlinker -rpath -Xlinker "$FW_DIR" | |
| # The 5 canonical examples (§6) run on every leg under the same skip | |
| # rules as the model tier: each transcribes with the canary or exits 0 | |
| # with a skip note (models/ is gitignored, so forks skip cleanly). | |
| - name: Run the canonical examples | |
| working-directory: bindings/swift | |
| run: | | |
| FW_DIR="$(cd build-apple/TranscribeCpp.xcframework/macos-*/ && pwd)" | |
| for example in transcribe-file streaming batch backend-select error-handling; do | |
| echo "== $example ==" | |
| swift run "$example" -Xlinker -rpath -Xlinker "$FW_DIR" | |
| done | |
| swift-ios: | |
| runs-on: [self-hosted, macOS, ARM64] | |
| env: | |
| CMAKE_C_COMPILER_LAUNCHER: ccache | |
| CMAKE_CXX_COMPILER_LAUNCHER: ccache | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install build deps | |
| run: brew install ninja ccache | |
| - uses: actions/cache@v4 | |
| with: | |
| path: ~/Library/Caches/ccache | |
| key: ccache-swift-ios-${{ github.sha }} | |
| restore-keys: ccache-swift-ios- | |
| - name: Cross-compile the iOS device + simulator slices (build-verify) | |
| run: TRANSCRIBE_XCFRAMEWORK_SLICES="ios-device ios-sim" scripts/ci/build_xcframework.sh |