Java coverage

Generate JaCoCo XML with Maven or Gradle, then upload the report directly from GitHub Actions.

Install dependencies

Add the JaCoCo Maven plugin or Gradle jacoco plugin to your build so CI writes a JaCoCo XML report.

Generate coverage

mvn test jacoco:report
./gradlew test jacocoTestReport

Maven GitHub Actions workflow

For Maven, upload target/site/jacoco/jacoco.xml. The action uses the default upload endpoint unless you provide an optional endpoint override.

name: coverage

on:
  pull_request:
  push:

jobs:
  coverage:
    if: github.event_name == 'pull_request' || github.ref_name == github.event.repository.default_branch
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: "21"
          cache: maven
      - run: mvn -B test jacoco:report
      - name: Upload coverage
        uses: 9to5/9to5-coverage-action@v1
        with:
          token: ${{ secrets.COVERAGE_UPLOAD_TOKEN }}
          path: target/site/jacoco/jacoco.xml

Maven: attach the JaCoCo test agent

Add this plugin under build/plugins in your pom.xml. The agent records execution during tests; the report goal writes XML for upload.

<plugin>
  <groupId>org.jacoco</groupId>
  <artifactId>jacoco-maven-plugin</artifactId>
  <version>0.8.14</version>
  <executions>
    <execution>
      <goals><goal>prepare-agent</goal></goals>
    </execution>
  </executions>
</plugin>

Gradle: enable XML and upload the report

For a single-module JVM project, add this to build.gradle.kts and commit the Gradle wrapper. Multi-module and Android builds require their own report tasks and paths.

plugins {
    java
    jacoco
}

jacoco {
    toolVersion = "0.8.14"
}

tasks.jacocoTestReport {
    dependsOn(tasks.test)
    reports {
        xml.required.set(true)
    }
}
name: coverage
on:
  pull_request:
  push:
jobs:
  coverage:
    if: github.event_name == 'pull_request' || github.ref_name == github.event.repository.default_branch
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: "21"
      - run: ./gradlew test jacocoTestReport
      - name: Upload coverage
        uses: 9to5/9to5-coverage-action@v1
        with:
          token: ${{ secrets.COVERAGE_UPLOAD_TOKEN }}
          path: build/reports/jacoco/test/jacocoTestReport.xml

See the Gradle JaCoCo documentation for custom report locations.

Pull request behavior

JaCoCo reports behave like other uploads: project and patch checks are attached to the pull request commit.

Troubleshooting

If upload fails, confirm the JaCoCo XML path. Gradle projects usually write build/reports/jacoco/test/jacocoTestReport.xml.