diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 468d38fb..478178b3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -146,11 +146,15 @@ jobs: # A separate `go build ./...` would only be a third full compile of the tree. - run: go vet ./... - name: Test (race on every platform; coverage only where it is uploaded) - # Only ubuntu uploads coverage, so only ubuntu pays the atomic-coverage - # instrumentation cost. The other platforms run the identical suite under - # -race with COVER unset, which is a correctness gate, not a coverage one. + # Ubuntu and Windows upload coverage, so only they pay the atomic-coverage + # instrumentation cost. Windows is uploaded because about 2,300 lines of + # *_windows.go code, and every runtime.GOOS == "windows" branch in shared + # code, run only there; Codecov counts a line covered when any upload covers + # it, so without this upload that code reads as untested on every pull + # request. macOS runs the identical suite under -race with COVER unset: its + # platform-only code is about 140 lines, too little to pay for a slower leg. env: - COVER: ${{ matrix.os == 'ubuntu-latest' && '-covermode=atomic -coverpkg=./... -coverprofile=coverage.out' || '' }} + COVER: ${{ matrix.os != 'macos-latest' && '-covermode=atomic -coverpkg=./... -coverprofile=coverage.out' || '' }} run: ./dev/test # Coverage is only a number until something fails when it drops. The floor @@ -161,11 +165,13 @@ jobs: if: matrix.os == 'ubuntu-latest' && matrix.go == '1.27' run: ./dev/coverfloor + # The flag names the platform, so Codecov can show either report on its own. - name: Upload coverage - if: matrix.os == 'ubuntu-latest' && matrix.go == '1.27' + if: matrix.os != 'macos-latest' && matrix.go == '1.27' uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7 with: files: coverage.out + flags: ${{ runner.os }} continue-on-error: true # The same profile, kept inside the repository's own trust boundary so the diff --git a/codecov.yml b/codecov.yml index 0e7d9a09..c395e42e 100644 --- a/codecov.yml +++ b/codecov.yml @@ -25,14 +25,33 @@ # The packages they test are not ignored. Coverage of the real implementations, # which is what the harnesses exist to produce, is unaffected. # -# The two `*_linux.go` files at the end are ignored for a related reason: their -# number reports the runner's configuration rather than the state of the tests. -# Both attach network plumbing to a child process inside a user namespace, and -# both are covered by tests that call t.Skip when the host has unprivileged user -# namespaces disabled. The GitHub ubuntu runner has them disabled, so the tests -# that exist for this code never execute in CI and it reports 10% and 50% while -# being tested. A pull request that touches either file is then scored against -# coverage it has no way to earn. +# Linux and Windows both upload (ci.yml, the test job), and a line counts as +# covered when either report covers it, so Windows-only code is scored on the +# Windows run. Codecov holds its status until the rest of CI has finished, so the +# status is posted once, after both uploads. +# +# The patch target is fixed rather than following the project figure. Codecov's +# default holds a pull request's changed lines to the project's own coverage (94% +# when this was written), so three or four untested error paths in a small diff +# fail it. 90% sits just under the floor dev/coverfloor enforces on the whole +# tree. A changed line still uncovered needs a test or a reason in the pull +# request body (AGENTS.md, Coverage), whatever this check says. +# +# The project status is off because dev/coverfloor is the project gate: it fails +# CI when Linux coverage drops below dev/coverage-floor, and lowering the floor is +# a reviewed diff. A second, advisory project number would only differ from it by +# whatever the Windows upload adds. +codecov: + notify: + wait_for_ci: true + +coverage: + status: + patch: + default: + target: 90% + project: off + ignore: - "bus/bustest" - "jobs/jobstest" @@ -44,5 +63,3 @@ ignore: - "spine/spinetest" - "state/statetest" - "internal/conformtest" - - "sandbox/egress_linux.go" - - "sandbox/forward_linux.go" diff --git a/dev/test b/dev/test index ade25c29..28070772 100755 --- a/dev/test +++ b/dev/test @@ -6,9 +6,8 @@ # The race detector always runs: it is the point of this gate. Coverage # instrumentation is separable via COVER, which defaults to atomic coverage # written to coverage.out (the local and primary-CI invocation). Set COVER= to -# run without it: CI uploads coverage from one platform only, so the other -# platforms skip the instrumentation cost while still running every test under -# -race. Unsetting it is also the fast path for a scoped local run, since the +# run without it: CI uploads coverage from Linux and Windows only, so macOS +# skips the instrumentation cost while still running every test under -race. Unsetting it is also the fast path for a scoped local run, since the # coverage default instruments the whole tree no matter how few packages you name. # # -coverpkg=./... is what makes the number honest. By default `go test` credits a