# Share a JaCoCo Coverage Report — Link, Not a Build Artifact

Canonical: https://commareports.com/share-jacoco-report
Published: 2026-08-24

> JaCoCo writes target/site/jacoco/ and Maven archives it where nobody looks. Publish the report to Comma for one browsable URL, comments on the uncovered class, and a revision per build.

# Share a JaCoCo coverage report

Java's coverage story ends one step early. JaCoCo produces a genuinely good
artifact — a browsable site with per-class source views and the exact lines
your tests never reached — and then Maven files it under `target/site/`, CI
archives it as a build artifact, and the only thing that escapes into a human
conversation is a single percentage in a Jenkins column.

That percentage is the least useful number in the whole report. "68%" starts
an argument. "The retry path in `PaymentGateway` has never been executed"
ends one.

## Drop the folder in

```bash
mvn test jacoco:report          # → target/site/jacoco/
./gradlew test jacocoTestReport # → build/reports/jacoco/test/html/
```

Drag that folder — or a zip of it — into [the app](https://commareports.com/):

- `index.html` becomes the **report body**, the page carrying the comment
  layer.
- Package pages, per-class source views, the CSS and JaCoCo's icons upload as
  assets.
- Relative `href` and `src` references are rewritten, so clicking from the
  summary into `com.acme.billing` into `PaymentGateway.java` works at the URL.

Scripts run inside a sandboxed iframe (`allow-scripts`, no
`allow-same-origin`), so the sortable summary columns behave normally.

## From CI, one stable URL per module

```bash
curl -fsS -X PATCH "https://commareports.com/api/v1/reports/$REPORT_ID" \
  -H "Authorization: Bearer $COMMA_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile html target/site/jacoco/index.html \
        --arg title "Coverage — $GIT_BRANCH" '{title: $title, html: $html}')"
```

Use a [scoped token](/docs/api-tokens) with only `reports:write`. Each build
appends a revision at the same URL, so the coverage question becomes a
[diff between two revisions](/docs/ci) instead of a trend line with no
detail behind it.

Provider wiring: [GitHub Actions](/ci/github-actions-html-report),
[GitLab CI](/ci/gitlab-ci-html-report), [Jenkins](/ci/jenkins-html-report),
[Azure DevOps](/ci/azure-devops-html-report).

## Multi-module builds

Two honest options:

- **`jacoco:report-aggregate`** — one rolled-up site for the reactor. Simple
  link, but a big monorepo's aggregate can push past the 500-file asset count.
- **One report per module** — a report id per module, PATCHed by that module's
  job. More ids to track, but each link is the one a specific team owns, and
  the review threads land with the people who can act on them.

The second is usually right for anything over a handful of modules.

## Limits

- **Entry HTML: 5 MB.** Assets: 25 MB per file, 250 MB and 500 files total.
- **Scripts run, sandboxed:** no same-origin fetches.
- **60 requests/minute per token.**

## Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision
history.

**[Publish a coverage report →](https://commareports.com/)**

### Related

- [Share a coverage report](/share-coverage-report) — the Python/JS flavour
- [Share a JUnit report](/share-junit-report) · [Share an Allure report](/share-allure-report)
- [Publish from CI](/docs/ci) · [Comment on HTML](/comment-on-html)
