CtrlK
BlogDocsLog inGet started
Tessl Logo

testland/jacoco-analysis

Configures JaCoCo for JVM projects (Java / Kotlin / Scala / Groovy) - wires the runtime agent via `jacoco-maven-plugin` `prepare-agent`, generates per-build reports (HTML / XML / CSV) via the `report` goal, gates the build via the `check` goal with element / limit / minimum rules, parses the six native counters (instructions, branches, lines, methods, classes, cyclomatic complexity), and converts JaCoCo XML to LCOV / Cobertura when downstream tools need a different format. Use when the JVM build is Maven / Gradle and the team wants the canonical JVM coverage tool - or to convert JaCoCo output for cross-language coverage aggregation.

75

Quality

94%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide

SecuritybySnyk

Passed

No findings from the security scan

Overview
Quality
Evals
Security
Files

gradle-parsing-and-ci.mdreferences/

JaCoCo Gradle config, XML parsing, counter-aware gating, and CI

Deep reference for the jacoco-analysis SKILL.md. Consult for the Gradle plugin equivalent, the jacoco.xml parser, the per-counter gating table, the JaCoCo-to-Cobertura / LCOV conversions, and the Maven verify CI job.

Gradle equivalent

plugins {
  id 'java'
  id 'jacoco'
}

jacoco {
  toolVersion = '0.8.13'
}

test {
  finalizedBy jacocoTestReport
}

jacocoTestReport {
  dependsOn test
  reports {
    xml.required = true
    html.required = true
    csv.required = false
  }
}

jacocoTestCoverageVerification {
  violationRules {
    rule {
      limit {
        counter = 'INSTRUCTION'
        value = 'COVEREDRATIO'
        minimum = 0.80
      }
      limit {
        counter = 'BRANCH'
        value = 'COVEREDRATIO'
        minimum = 0.70
      }
    }
  }
}

check.dependsOn jacocoTestCoverageVerification

Parse jacoco.xml

The JaCoCo XML format mirrors the report tree (report -> package -> class -> method -> counter):

<report name="my-app">
  <package name="com/example/checkout">
    <class name="com/example/checkout/Cart" sourcefilename="Cart.java">
      <method name="addItem" desc="(LItem;)V" line="12">
        <counter type="INSTRUCTION" missed="0" covered="15"/>
        <counter type="BRANCH" missed="1" covered="3"/>
        <counter type="LINE" missed="0" covered="3"/>
        <counter type="METHOD" missed="0" covered="1"/>
        <counter type="COMPLEXITY" missed="0" covered="2"/>
      </method>
      <counter type="INSTRUCTION" missed="0" covered="42"/>
      ...
    </class>
    <counter type="INSTRUCTION" missed="0" covered="100"/>
    ...
  </package>
  <counter type="INSTRUCTION" missed="20" covered="500"/>
  ...
</report>
# scripts/parse_jacoco.py
import xml.etree.ElementTree as ET

def parse_jacoco(path):
    root = ET.parse(path).getroot()
    files = []
    for pkg in root.findall('package'):
        for cls in pkg.findall('class'):
            counters = {c.get('type'): {
                            'missed': int(c.get('missed')),
                            'covered': int(c.get('covered')),
                        } for c in cls.findall('counter')}
            files.append({
                'package': pkg.get('name'),
                'name': cls.get('name'),
                'sourcefile': cls.get('sourcefilename'),
                'counters': counters,
            })
    return files

Counter-aware metrics

Per jacoco-counters, the six counters have different semantics. Don't aggregate naively:

CounterWhen to gate on it
INSTRUCTIONThe most granular; least sensitive to source formatting. Best whole-repo gate.
LINEMost intuitive for reviewers; aggregates per source line.
BRANCHCritical for control flow correctness; gate separately from line.
METHODCoarse-grained; "any test touched this method" - useful as a "no dead code" floor.
CLASSEven coarser; "any test touched this class" - proves the test suite at least loads it.
COMPLEXITYPair with branch coverage; high-complexity uncovered methods are the highest-risk.

Cross-language: convert JaCoCo XML

For projects that mix JVM with other languages and want one coverage UI, convert JaCoCo XML to a sibling format.

To Cobertura

# Use the cover2cover.py script (community-maintained):
python cover2cover.py target/site/jacoco/jacoco.xml src/main/java > target/cobertura.xml

Then feed cobertura-analysis.

To LCOV

# Use the xml2lcov converter (per LCOV's language-agnostic converter family):
xml2lcov target/site/jacoco/jacoco.xml > target/jacoco.info

Then feed lcov-analysis. LCOV is the language-agnostic interchange format; LCOV's own documentation lists JaCoCo conversion as a supported path.

CI shape

- name: Run Maven verify
  run: ./mvnw -B verify

- name: Upload JaCoCo report
  if: always()
  uses: actions/upload-artifact@v4
  with:
    name: jacoco
    path: target/site/jacoco/

- name: Convert to LCOV for SaaS
  run: xml2lcov target/site/jacoco/jacoco.xml > target/jacoco.info

- name: Upload to coverage SaaS
  uses: codecov/codecov-action@v5
  with:
    files: target/jacoco.info

SKILL.md

tile.json