From ca2597a71d8f87614f6a080106d3cb1cc3549800 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 30 Sep 2026 14:08:04 +0000 Subject: [PATCH] ci: upload the coverage report to Codecov The Coverage report job aggregates the JDK 17 unit and integration lanes into jacoco.xml and archives it as a workflow artifact, which records the number without reporting it: no per-pull-request delta, no line-level annotation on the diff, and no history to compare a branch against. Upload that jacoco.xml to Codecov, with the CODECOV_TOKEN repository secret, from a job of its own after the report job. The report job runs even when a lane failed and keeps what the lanes left as its artifact, which is right for diagnosis but wrong as a Codecov baseline: a partial report on scylla-4.x becomes what target: auto compares the next pull request against. So the upload job runs only when every unit, Cassandra and Scylla lane passed and the report job built and archived the report; the report job's continue-on-error makes it look successful to the jobs that need it either way, so it exposes that as an output. needs cannot tell a matrix's legs apart, so a failed JDK 11 leg, which records no coverage, holds the upload back as well. The upload is not in the report job itself because that job's continue-on-error would swallow a refused upload. Pull requests from forks, which is most of them here, get no repository secrets, so their upload goes without a token, which Codecov accepts for public repositories unless the organization's Codecov settings require one; Dependabot-triggered runs get no CODECOV_TOKEN either. An upload error fails the job everywhere except those two cases. Codecov files a pull request's report under its head commit. codecov.yml carries what the action cannot express: - No path fixes: each package/sourcefile pair in jacoco.xml names exactly one file of the repository. - require_ci_to_pass: false and notify.wait_for_ci: false, so the report is neither withheld because an unrelated check failed nor held back while one is still running. - max_report_age: false. By default Codecov discards a JaCoCo report whose oldest session is from before noon the previous day. "Re-run failed jobs" reuses the lanes that passed, so a re-run after a weekend would be discarded, while the report is only ever built from the run's own lanes. - Informational project and patch statuses. The integration suites run against live Scylla and Cassandra clusters, and which lines they reach depends on cluster timing as well as on the diff. Also add a Codecov badge to README.md and mention the upload in the coverage section of README-dev.md. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LRxoFGZ2HGZczLhjHdVfp6 --- .github/workflows/tests@v1.yml | 48 ++++++++++++++++++++++++++++++++++ README-dev.md | 4 +++ README.md | 1 + codecov.yml | 36 +++++++++++++++++++++++++ 4 files changed, 89 insertions(+) create mode 100644 codecov.yml diff --git a/.github/workflows/tests@v1.yml b/.github/workflows/tests@v1.yml index 7fefb725707..d39c950c304 100644 --- a/.github/workflows/tests@v1.yml +++ b/.github/workflows/tests@v1.yml @@ -493,6 +493,10 @@ jobs: if: ${{ !cancelled() }} continue-on-error: true timeout-minutes: 20 + # continue-on-error reports this job to the jobs that need it as a success + # even when it failed, so the Codecov upload reads this instead. + outputs: + built: ${{ steps.aggregate.outcome == 'success' && steps.upload-report.outcome == 'success' }} # Only needs to read the checkout; same-run artifacts are handled by the # Actions runtime token rather than GITHUB_TOKEN. Scoped on this job alone @@ -577,12 +581,56 @@ jobs: find . -name 'jacoco-*.exec' -printf '%p\t%s bytes\n' - name: Aggregate coverage + id: aggregate run: make coverage-report - name: Upload coverage report + id: upload-report uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 if: ${{ !cancelled() }} with: name: coverage-report path: coverage-report/target/site/jacoco-aggregate if-no-files-found: error + + # A job of its own, without the report job's continue-on-error, so that a + # refused upload fails the run. Only a run in which every lane passed + # uploads: a partial report on scylla-4.x would become the baseline later + # pull requests are compared against. needs cannot tell a matrix's legs + # apart, so a failed JDK 11 leg, which records no coverage, holds the upload + # back as well. Pull requests from forks get no secrets and upload without a + # token; neither that nor a Dependabot run, which gets no CODECOV_TOKEN, + # fails on a refused upload. + codecov: + name: Upload coverage to Codecov + runs-on: ubuntu-latest + needs: [unit-tests, cassandra-integration-tests, scylla-integration-tests, coverage-report] + if: >- + needs.unit-tests.result == 'success' && + needs.cassandra-integration-tests.result == 'success' && + needs.scylla-integration-tests.result == 'success' && + needs.coverage-report.outputs.built == 'true' + timeout-minutes: 10 + permissions: + contents: read + + steps: + # Codecov matches jacoco.xml's paths against the checkout's file list. + - name: Checkout source + uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5.0.1 + with: + persist-credentials: false + + - name: Download coverage report + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: coverage-report + path: coverage-report + + - name: Upload coverage to Codecov + uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: coverage-report/jacoco.xml + disable_search: true + fail_ci_if_error: ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]') }} diff --git a/README-dev.md b/README-dev.md index 44ac3a56ddf..8cd60c06afb 100644 --- a/README-dev.md +++ b/README-dev.md @@ -79,6 +79,10 @@ as an artifact. That job is `continue-on-error`, so a flaky integration test cos data rather than adding a second failure to the pull request. Collecting from the existing lanes rather than a dedicated workflow keeps the Scylla suite from being run twice. +When every test lane passed, the next job uploads that `jacoco.xml` to +[Codecov](https://codecov.io/gh/scylladb/java-driver), which comments the coverage delta on the +pull request. Its statuses are informational, so a drop never blocks a merge. + Only the lanes on `COVERAGE_JAVA_VERSION` (a workflow-level variable, JDK 17) are instrumented. javac 11 and javac 17 do not emit the same bytes for the same source even under `--release 11` -- they order the constant pool differently -- so the class ids differ, and a report rendered against diff --git a/README.md b/README.md index 18201370e79..059257ec8d1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Java Driver for Scylla and Apache Cassandra® [![Maven Central](https://img.shields.io/maven-central/v/com.scylladb/java-driver-core)](https://central.sonatype.com/artifact/com.scylladb/java-driver-core) +[![Codecov](https://codecov.io/gh/scylladb/java-driver/branch/scylla-4.x/graph/badge.svg)](https://codecov.io/gh/scylladb/java-driver) *If you're reading this on github.com, please note that this is the readme for the development version and that some features described here might not yet have been released. You can find the diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000000..202d7aa54ef --- /dev/null +++ b/codecov.yml @@ -0,0 +1,36 @@ +# Codecov configuration for the upload in the "Coverage report" job of +# .github/workflows/tests@v1.yml. +# Reference: https://docs.codecov.com/docs/codecov-yaml +# +# There are no path fixes: each package/sourcefile pair in jacoco.xml names +# exactly one file, e.g. com/datastax/oss/driver/api/core/CqlSession.java can +# only be core/src/main/java/com/datastax/oss/driver/api/core/CqlSession.java. + +codecov: + # That job is the only uploader, so its report should neither be withheld + # because an unrelated check (Full verify, say) failed nor wait for it. + require_ci_to_pass: false + notify: + wait_for_ci: false + # Codecov discards a JaCoCo report whose oldest session is from before noon + # the previous day. "Re-run failed jobs" keeps the lanes that passed, so a + # re-run's report still carries their first-attempt sessions, and a re-run + # after a weekend would be discarded although it is built from this run's + # own lanes. + max_report_age: false + +coverage: + status: + # Informational: report the delta, never fail a pull request on it. The + # integration suites run against live Scylla and Cassandra clusters, so + # which lines they reach depends on cluster timing as well as on the diff. + project: + default: + target: auto + threshold: 1% + informational: true + patch: + default: + target: auto + threshold: 1% + informational: true