ci(integration): skip scheduled rebuild when main hasn't moved (#202) #415
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: CI | |
| # Integration gate for the `main` (integration) and `release` branches. | |
| # Fast, Linux-only validation that formatting is clean, the renderer workspace | |
| # builds + all its tests pass (including doctests), and the Studio frontend | |
| # builds. Deliberately does NOT bundle Tauri or build the Windows/ASIO target — | |
| # those are covered by the heavier tag-triggered release.yml. | |
| # | |
| # NOTE on scope: `clippy` is NOT gated yet — the workspace currently has ~70 | |
| # clippy warnings plus a couple of deny-level lints, several inside hot audio | |
| # loops where the lint suggestions are not obviously safe. Cleaning that up is a | |
| # separate, careful pass; until then a clippy gate would block merges for | |
| # reasons unrelated to correctness. | |
| on: | |
| push: | |
| branches: [main, release] | |
| pull_request: | |
| branches: [main, release] | |
| workflow_dispatch: | |
| # Cancel superseded runs on the same ref to save Actions minutes. | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| build-and-test: | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v5 | |
| with: | |
| node-version: 20 | |
| - name: Install Rust stable | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt | |
| - name: Cache Cargo registry | |
| uses: actions/cache@v5 | |
| # Caching is an optimization, not a correctness step: a crash of the | |
| # cache action must never fail the build. | |
| continue-on-error: true | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| omniphony-renderer/target | |
| # omniphony-renderer/Cargo.lock is gitignored, so key off the tracked | |
| # manifests instead (cache invalidates when a dependency changes). | |
| key: ${{ runner.os }}-ci-cargo-${{ hashFiles('omniphony-renderer/**/Cargo.toml') }} | |
| restore-keys: ${{ runner.os }}-ci-cargo- | |
| # Fast fail before the heavy build if formatting drifts. | |
| - name: Check formatting | |
| working-directory: omniphony-renderer | |
| run: cargo fmt --all -- --check | |
| # ── Platform dependencies ───────────────────────────────────────────── | |
| # Same PipeWire PPA as release.yml: ubuntu-22.04 ships PipeWire 0.3.48 but | |
| # pipewire-rs 0.9.x needs >= 0.3.65. The GUI/Tauri libs are kept too so the | |
| # whole workspace links exactly as in the release build (cheap, robust). | |
| - name: Install Linux system dependencies | |
| run: | | |
| for attempt in 1 2 3; do | |
| if sudo add-apt-repository ppa:pipewire-debian/pipewire-upstream -y; then | |
| break | |
| fi | |
| if [ "$attempt" -eq 3 ]; then | |
| echo "Failed to add PipeWire PPA after $attempt attempts" >&2 | |
| exit 1 | |
| fi | |
| sleep 10 | |
| done | |
| for attempt in 1 2 3; do | |
| if sudo apt-get update; then | |
| break | |
| fi | |
| if [ "$attempt" -eq 3 ]; then | |
| echo "apt-get update failed after $attempt attempts" >&2 | |
| exit 1 | |
| fi | |
| sleep 10 | |
| done | |
| sudo apt-get install -y \ | |
| libwebkit2gtk-4.1-dev \ | |
| libssl-dev \ | |
| libgtk-3-dev \ | |
| libayatana-appindicator3-dev \ | |
| librsvg2-dev \ | |
| libpipewire-0.3-dev \ | |
| pkg-config | |
| # ── Rust: build + test (strict gate) ────────────────────────────────── | |
| # No --locked: omniphony-renderer/Cargo.lock is gitignored (matches | |
| # release.yml, which also resolves dependencies fresh). | |
| - name: Build renderer workspace | |
| working-directory: omniphony-renderer | |
| run: cargo build --workspace | |
| - name: Test renderer workspace | |
| working-directory: omniphony-renderer | |
| run: cargo test --workspace | |
| # ── C ABI smoke test (liborender) ────────────────────────────────────── | |
| # Compile and run the header/link smoke test against the debug cdylib | |
| # (debug builds skip the soname so the bare .so links directly). Guards | |
| # the generated header, the exported symbols, and the version handshake — | |
| # this is what mpv consumes, so it must never drift silently. | |
| - name: C ABI smoke test (liborender) | |
| working-directory: omniphony-renderer | |
| run: | | |
| cc -Wall -Werror -I orender_ffi/include orender_ffi/examples/smoke.c \ | |
| -L target/debug -lorender -o target/debug/orender_smoke | |
| LD_LIBRARY_PATH=target/debug target/debug/orender_smoke | |
| # ── Studio frontend build (no Tauri bundling / no sidecar) ───────────── | |
| - name: Install Studio npm dependencies | |
| working-directory: omniphony-studio | |
| run: npm ci | |
| - name: Build Studio frontend | |
| working-directory: omniphony-studio | |
| run: npm run build | |
| # Translation parity is reported but never blocks a merge: incomplete | |
| # locales fall back to English at runtime, so this is a heads-up, not a | |
| # gate. Emits ::warning:: annotations on the PR. | |
| - name: Check i18n parity (warn-only) | |
| working-directory: omniphony-studio | |
| continue-on-error: true | |
| run: npm run i18n:check | |
| # Dead-code gate (knip): a module with no importer fails the build. | |
| # An orphaned ingestion module is how live-option state silently stopped | |
| # reaching the UI for months (see docs/live-options-registry.md, "The | |
| # incident"); unused *exports* are only warnings for now. | |
| - name: Dead-code lint (knip) | |
| working-directory: omniphony-studio | |
| run: npm run lint:dead | |
| # Options-schema contract: the renderer dumps its declared live options | |
| # (registry rows); every option must resolve its Studio i18n keys. Hard | |
| # gate — an option declared engine-side but invisible to the UI is the | |
| # silent-omission class the registry exists to kill. | |
| - name: Check options-schema ↔ Studio contract | |
| run: | | |
| cargo run -q -p renderer --example dump_options_schema \ | |
| --manifest-path omniphony-renderer/Cargo.toml > /tmp/options-schema.json | |
| node omniphony-studio/scripts/check-options-schema.mjs /tmp/options-schema.json | |
| build-macos: | |
| # macOS arm64 compile gate. The renderer workspace pulls the CoreAudio | |
| # output backend (cpal) and the `sys` signal/IO layer, both of which carry | |
| # macOS-specific code paths. Build-only (no PipeWire/Tauri) — this catches | |
| # macOS portability regressions on PRs, before the tag-triggered release | |
| # builds (liborender / Studio / mpv) ever run on macOS. | |
| runs-on: macos-14 | |
| steps: | |
| - uses: actions/checkout@v5 | |
| - name: Install Rust stable | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt | |
| - name: Cache Cargo registry | |
| uses: actions/cache@v5 | |
| continue-on-error: true | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| omniphony-renderer/target | |
| key: macos-ci-cargo-${{ hashFiles('omniphony-renderer/**/Cargo.toml') }} | |
| restore-keys: macos-ci-cargo- | |
| - name: Build renderer workspace (macOS arm64) | |
| working-directory: omniphony-renderer | |
| run: cargo build --workspace |