diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 67c0c0e6..2db6cefc 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -1,12 +1,13 @@ name: Coverage -# Skip paths that can't move the Rust coverage number or break `npm run build` -# / `cargo llvm-cov`: docs, the local docker-compose fixtures used for manual +# Two independent jobs, one Codecov upload each under its own flag (see +# codecov.yml): `frontend` (vitest, Node-only) and `rust` (cargo-llvm-cov, +# the expensive one — Tauri system deps + a full Rust build). Both share the +# same paths-ignore below since neither can move on a docs-only/script-only +# change: docs, the local docker-compose fixtures used for manual # Kafka/RabbitMQ testing, and the one-off maintenance scripts (icon gen, # release verification, MCP-sidecar prep for the desktop build — not the -# `npm run build` this job actually runs). This is the most expensive -# workflow here (Tauri system deps + a full Rust build), so it's worth being -# picky about what triggers it. +# `npm run build` the rust job runs to embed the frontend). on: push: branches: [main] @@ -31,7 +32,39 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: - coverage: + # Node-only, no Tauri system deps/Rust toolchain — reports in well under a + # minute, independent of the Rust job below. Uploaded under its own + # `frontend` flag (see codecov.yml) so it shows as a separate component + # from the Rust coverage, instead of one number that mixes two languages' + # very different testability. + frontend: + runs-on: ubuntu-22.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Setup Node.js + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: lts/* + cache: npm + + - name: Install frontend dependencies + run: npm ci --prefer-offline --no-audit --no-fund --ignore-scripts + + - name: Generate coverage (lcov, vitest.config.ts's existing coverage block) + run: npm run test:coverage + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 + with: + files: coverage/lcov.info + flags: frontend + fail_ci_if_error: false + env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + + rust: runs-on: ubuntu-22.04 # Observed median 3 min, worst 7.5 min. The default is 360, so a job wedged # on a network stall would otherwise hold a concurrency slot for six hours. @@ -93,6 +126,7 @@ jobs: uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 with: files: lcov.info + flags: rust fail_ci_if_error: false env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/codecov.yml b/codecov.yml index 9a5fc17a..88aa1e94 100644 --- a/codecov.yml +++ b/codecov.yml @@ -1,7 +1,9 @@ # Codecov configuration. -# Coverage here measures the Rust backend (src-tauri). Much of that crate is -# Tauri command glue and network/file I/O that can't run in unit tests, so -# coverage is reported as informational — it never fails CI or blocks a PR. +# Two flags, one per language, uploaded by .github/workflows/coverage.yml's +# two jobs: `frontend` (vitest, src/) and `rust` (cargo-llvm-cov, src-tauri/). +# Both a Tauri command's glue/network/file I/O and a fair amount of frontend +# UI wiring can't run in unit tests, so every status stays informational — it +# never fails CI or blocks a PR, for either flag. coverage: status: project: @@ -11,12 +13,28 @@ coverage: default: informational: true +flags: + frontend: + paths: + - "src/" + # A doc-only/script-only PR skips BOTH jobs (coverage.yml's paths-ignore), + # so neither flag uploads anything for that commit — without carryforward + # Codecov would report this flag as having "dropped to 0%" instead of + # just reusing its last known number. + carryforward: true + rust: + paths: + - "src-tauri/src/" + carryforward: true + comment: layout: "reach, diff, flags, files" require_changes: true -# The lcov report only contains the Rust backend (src-tauri/src), so no -# frontend ignores are needed. Exclude the Tauri entrypoint, which is plumbing -# that can't be exercised by unit tests. +# `src-tauri/src/main.rs` is the Tauri entrypoint — plumbing that can't be +# exercised by unit tests. Frontend exclusions live in vitest.config.ts's own +# coverage.exclude instead (test files, src/main.tsx, the design-system +# re-export barrel) — vitest never puts those in its lcov.info, so nothing +# here needs to repeat them. ignore: - "src-tauri/src/main.rs"