DEV Community

Cover image for JaCoCo Coverage Badges for Multi-Module Projects in GitHub Actions
Vincent A. Cicirello
Vincent A. Cicirello

Posted on

JaCoCo Coverage Badges for Multi-Module Projects in GitHub Actions

The jacoco-badge-generator is a GitHub Action, which can also be used locally as a command-line utility. Its functionality includes parsing JaCoCo test coverage csv files, generating coverage badges that can be displayed within the READMEs of GitHub repositories, generating a JSON summary file with the coverage percentages, and can optionally be used for pull-request coverage checks (e.g., validating if coverage is above a target minimum and/or ensuring that coverage did not decrease). It is customizable in a variety of ways (see its GitHub repository and/or the other posts in this series for details).

I just release version v2.9.0, which enhanced the existing functionality associated with using the jacoco-badge-generator GitHub Action with multi-module projects. Specifically, prior to this release, for a multi-module project, the paths to all of the JaCoCo csv reports had to be listed in the inputs to the action. Now, as of v2.9.0, you can use a glob pattern to specify the paths to the JaCoCo csv reports. This can actually now also work for the more common single module project, but the glob functionality is likely most useful in the multi-module case. Note that the CLI mode already implicitly supported globs since your shell will expand any globs you specify on the command line. But as a GitHub Action this previously was not the case as GitHub Actions doesn't expand globs in the inputs to an Action. The jacoco-badge-generator v2.9.0 now handles glob expansion internally.

This post focuses on workflows for the multi-module case, including introducing the new approach to using a glob to specify the JaCoCo reports. The README in the GitHub repository, as well as other posts in this series here on DEV, cover other functionality along with additional sample workflows.

Table of Contents: The remainder of this post is organized as follows:

Preliminaries

Before you can use the jacoco-badge-generator, your workflow must generate a JaCoCo csv coverage report. Here are a couple examples of how to do this for different build tools.

Running JaCoCo with Maven

The example workflows in this post assume that you are using Maven to build and test a Java project, and that you have the jacoco-maven-plugin configured in your pom.xml in the test phase with something along the lines of the following:

<build>
  <plugins>
    <plugin>
      <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
      <version>0.8.10</version>
      <executions>
        <execution>
          <goals>
            <goal>prepare-agent</goal>
          </goals>
        </execution>
        <execution>
          <id>generate-code-coverage-report</id>
          <phase>test</phase>
          <goals>
            <goal>report</goal>
          </goals>
        </execution>
      </executions>
      </plugin>
  </plugins>
</build>
Enter fullscreen mode Exit fullscreen mode

Running JaCoCo with Gradle

If you use gradle as your build tool, then you can configure JaCoCo to generate the csv report in build.gradle.kts with:

plugins {
    jacoco
}

tasks.jacocoTestReport {
    reports {
        csv.isEnabled = true
    }
}
Enter fullscreen mode Exit fullscreen mode

Or the equivalent in build.gradle:

plugins {
    id 'jacoco'
}

jacocoTestReport {
    reports {
        csv.enabled true
    }
}
Enter fullscreen mode Exit fullscreen mode

Note that the workflows in the remainder of this post assume that Maven is in use, including Maven's default location and filename for the coverage report. You will need to alter the jacoco-csv-file input if you are using Gradle to the appropriate location and filename.

Workflow Specifying Paths to JaCoCo Reports Without Globs

This example workflow generates both badges (instructions coverage percentage and branches coverage percentage) for a multi-module project. The badges that are generated are computed over all modules. To do so, simply pass the paths to all of the JaCoCo reports that you want to include via the jacoco-csv-file input. The > is just Yaml's way of writing a string across multiple lines. You can also just list all on a single space-separated line, but your workflow file will be easier to read if you put them one per line. In this example, there are three subprojects: module1, module2, and module3. This workflow assumes that you are using Maven as your build tool, and that you have configured JaCoCo to run during the test phase.

name: build

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Set up the Java JDK
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'adopt'

    - name: Build with Maven
      run: mvn -B test

    - name: Generate JaCoCo Badge
      id: jacoco
      uses: cicirello/jacoco-badge-generator@v2
      with:
        generate-branches-badge: true
        jacoco-csv-file: >
          module1/target/site/jacoco/jacoco.csv
          module2/target/site/jacoco/jacoco.csv
          module3/target/site/jacoco/jacoco.csv

    - name: Log coverage percentage
      run: |
        echo "coverage = ${{ steps.jacoco.outputs.coverage }}"
        echo "branch coverage = ${{ steps.jacoco.outputs.branches }}"

    - name: Commit the badge (if it changed)
      run: |
        if [[ `git status --porcelain` ]]; then
          git config --global user.name 'YOUR NAME HERE'
          git config --global user.email 'YOUR-GITHUB-USERID@users.noreply.github.com'
          git add -A
          git commit -m "Autogenerated JaCoCo coverage badge"
          git push
        fi
Enter fullscreen mode Exit fullscreen mode

Workflow Specifying Paths to JaCoCo Reports With Globs

This next example workflow is just like the previous, except that now a glob is used to to find all JaCoCo reports named jacoco.csv regardless of where they appear within your project. This will actually also work if you have a single module project, with a single jacoco.csv but without the need to specify its path. We'll pass the glob pattern to the jacoco-csv-file input with the following: jacoco-csv-file: "**/jacoco.csv". Note that the quotes around the pattern are necessary. Without the quotes, the wildcard characters will lead to an "invalid workflow" error from GitHub Actions. We're essentially passing the glob as a string to the action, and the action then processes the glob internally.

name: build

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Set up the Java JDK
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'adopt'

    - name: Build with Maven
      run: mvn -B test

    - name: Generate JaCoCo Badge
      id: jacoco
      uses: cicirello/jacoco-badge-generator@v2
      with:
        generate-branches-badge: true
        jacoco-csv-file: "**/jacoco.csv"

    - name: Log coverage percentage
      run: |
        echo "coverage = ${{ steps.jacoco.outputs.coverage }}"
        echo "branch coverage = ${{ steps.jacoco.outputs.branches }}"

    - name: Commit the badge (if it changed)
      run: |
        if [[ `git status --porcelain` ]]; then
          git config --global user.name 'YOUR NAME HERE'
          git config --global user.email 'YOUR-GITHUB-USERID@users.noreply.github.com'
          git add -A
          git commit -m "Autogenerated JaCoCo coverage badge"
          git push
        fi
Enter fullscreen mode Exit fullscreen mode

Workflow Generating Separate Badges for Each Module

If you prefer to generate separate coverage badges for each of the modules of a multi-module project, then just include multiple steps of the jacoco-badge-generator in your workflow, such as in this example. Be sure to use the inputs to specify names for the badge files, otherwise with the defaults the subsequent steps will overwrite the previous. This example assumes that there are two modules. You also will likely want to use the coverage-label and branches-label inputs to change the text on the left side of the badges if you are displaying badges for multiple modules in the README of the same repository. This example demonstrates that as well.

name: build

on:
  push:
    branches: [ main ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3

    - name: Set up the Java JDK
      uses: actions/setup-java@v3
      with:
        java-version: '17'
        distribution: 'adopt'

    - name: Build with Maven
      run: mvn -B test

    - name: Generate JaCoCo Badges for Module 1
      id: jacocoMod1
      uses: cicirello/jacoco-badge-generator@v2
      with:
        generate-branches-badge: true
        jacoco-csv-file: module1/target/site/jacoco/jacoco.csv
        coverage-badge-filename: jacoco1.svg
        branches-badge-filename: branches1.svg
        coverage-label: coverage (module 1)
        branches-label: branches (module 1)

    - name: Generate JaCoCo Badges for Module 2
      id: jacocoMod2
      uses: cicirello/jacoco-badge-generator@v2
      with:
        generate-branches-badge: true
        jacoco-csv-file: module2/target/site/jacoco/jacoco.csv
        coverage-badge-filename: jacoco2.svg
        branches-badge-filename: branches2.svg
        coverage-label: coverage (module 2)
        branches-label: branches (module 2)

    - name: Commit the badges (if they changed)
      run: |
        if [[ `git status --porcelain` ]]; then
          git config --global user.name 'YOUR NAME HERE'
          git config --global user.email 'YOUR-GITHUB-USERID@users.noreply.github.com'
          git add -A
          git commit -m "Autogenerated JaCoCo coverage badge"
          git push
        fi
Enter fullscreen mode Exit fullscreen mode

Multi-Module Examples with the CLI Utility

For those using the jacoco-badge-generator as a CLI tool, the following commands will accomplish the equivalent of the above three workflows. First, to install the CLI tool with pip from PyPI.

On Linux and MacOS:

python3 -m pip install jacoco-badge-generator
Enter fullscreen mode Exit fullscreen mode

On Windows:

py -m pip install jacoco-badge-generator
Enter fullscreen mode Exit fullscreen mode

Note that all examples below assume Linux (e.g., Python command is python3). If on Windows, just change python3 to py in all of the examples below.

Three Modules Without Globs:

Generate both instructions coverage and branches coverage badges for combination of three modules:

python3 -m jacoco_badge_generator --generate-branches-badge true --jacoco-csv-file module1/target/site/jacoco/jacoco.csv module2/target/site/jacoco/jacoco.csv module3/target/site/jacoco/jacoco.csv
Enter fullscreen mode Exit fullscreen mode

Three Modules With Globs:

Generate both instructions coverage and branches coverage badges for combination of three modules:

python3 -m jacoco_badge_generator --generate-branches-badge true --jacoco-csv-file **/jacoco.csv
Enter fullscreen mode Exit fullscreen mode

Two Modules with Separate Badges for Each:

python3 -m jacoco_badge_generator --generate-branches-badge true --jacoco-csv-file module1/target/site/jacoco/jacoco.csv --coverage-badge-filename jacoco1.svg --branches-badge-filename branches1.svg --coverage-label "coverage (module 1)" --branches-label "branches (module 1)"
python3 -m jacoco_badge_generator --generate-branches-badge true --jacoco-csv-file module2/target/site/jacoco/jacoco.csv --coverage-badge-filename jacoco2.svg --branches-badge-filename branches2.svg --coverage-label "coverage (module 2)" --branches-label "branches (module 2)"
Enter fullscreen mode Exit fullscreen mode

More Information

For more information, see the GitHub Repository:

GitHub logo cicirello / jacoco-badge-generator

Coverage badges, and pull request coverage checks, from JaCoCo reports in GitHub Actions

jacoco-badge-generator

cicirello/jacoco-badge-generator - Coverage badges, and pull request coverage checks, from JaCoCo reports in GitHub Actions

Check out all of our GitHub Actions: https://actions.cicirello.org/

About

GitHub Actions GitHub release (latest by date) Count of Action Users
Command-Line Utility PyPI PyPI Downloads/month PyPI Downloads/week
Build Status build CodeQL
Security Snyk security score
Source Info License GitHub top language
Support GitHub Sponsors Liberapay Ko-Fi

The jacoco-badge-generator can be used in one of two ways: as a GitHub Action or as a command-line utility (e.g., such as part of a local build script). The jacoco-badge-generator parses a jacoco.csv from a JaCoCo coverage report, computes coverage percentages from JaCoCo's Instructions and Branches counters, and generates badges for one or both of these (user configurable) to provide an easy to read visual summary of the code coverage of your test cases. The default behavior directly generates the badges internally with no external calls, but the action also provides an option to instead generate Shields JSON endpoints. It supports both the basic case of a single jacoco.csv, as well as multi-module projects in which case the action can produce coverage badges from the combination of…

You can also check out a website about this action as well as other GitHub Actions that I maintain:

Vincent Cicirello - Open source GitHub Actions for workflow automation

Features information on several open source GitHub Actions for workflow automation that we have developed to automate parts of the CI/CD pipeline, and other repetitive tasks. The GitHub Actions featured include jacoco-badge-generator, generate-sitemap, user-statistician, and javadoc-cleanup.

favicon actions.cicirello.org

Where You Can Find Me

Follow me here on DEV and on GitHub:

Or visit my website:

Vincent A. Cicirello - Professor of Computer Science

Vincent A. Cicirello - Professor of Computer Science at Stockton University - is a researcher in artificial intelligence, evolutionary computation, swarm intelligence, and computational intelligence, with a Ph.D. in Robotics from Carnegie Mellon University. He is an ACM Senior Member, IEEE Senior Member, AAAI Life Member, EAI Distinguished Member, and SIAM Member.

favicon cicirello.org

Top comments (0)