You must add coverage keyword to your .gitlab-ci.yml
See: https://docs.gitlab.com/ee/ci/testing/code_coverage/index.html
You can calculate coverage from the output
...
script:
- awk -F"," '{ instructions += $4 + $5; covered += $5 } END { print covered, "/", instructions, " instructions covered"; print 100*covered/instructions, "% covered" }' target/site/jacoco/jacoco.csv
coverage: '/\d+\.\d+.%.covered/'
...
Example
clean-test-jacoco:
image: maven:latest
stage: test
script:
- mvn $MAVEN_CLI_OPTS clean verify
- awk -F"," '{ instructions += $4 + $5; covered += $5 } END { print covered, "/", instructions, " instructions covered"; print 100*covered/instructions, "% covered" }' target/site/jacoco/jacoco.csv
coverage: '/\d+\.\d+.%.covered/'
artifacts:
paths:
- target/site/jacoco/jacoco.xml
reports:
coverage_report:
coverage_format: jacoco
path: target/site/jacoco/jacoco.xml
Also you can create a badge
!coverage
Answer from jschnasse on Stack OverflowYou must add coverage keyword to your .gitlab-ci.yml
See: https://docs.gitlab.com/ee/ci/testing/code_coverage/index.html
You can calculate coverage from the output
...
script:
- awk -F"," '{ instructions += $4 + $5; covered += $5 } END { print covered, "/", instructions, " instructions covered"; print 100*covered/instructions, "% covered" }' target/site/jacoco/jacoco.csv
coverage: '/\d+\.\d+.%.covered/'
...
Example
clean-test-jacoco:
image: maven:latest
stage: test
script:
- mvn $MAVEN_CLI_OPTS clean verify
- awk -F"," '{ instructions += $4 + $5; covered += $5 } END { print covered, "/", instructions, " instructions covered"; print 100*covered/instructions, "% covered" }' target/site/jacoco/jacoco.csv
coverage: '/\d+\.\d+.%.covered/'
artifacts:
paths:
- target/site/jacoco/jacoco.xml
reports:
coverage_report:
coverage_format: jacoco
path: target/site/jacoco/jacoco.xml
Also you can create a badge
!coverage
You should see them in the Tests tab on the Pipelines :
https://gitlab.com/{group}/{project}/-/pipelines/{pipeline_id}/test_report
Example :

You also have access to the report on the Merge Request if you have one open :

To see the coverage you need to configure the coverage keyword in the job :
coverage:
script:
- mvn clean install surefire-report:report
image: maven:3.9.9-sapmachine-23
stage: coverage
coverage: /Total.*?([0-9]{1,3})%/
artifacts:
[...]
This will tell to Gitlab the regex to use to get the coverage based on your coverage tool, here Jacoco. Based on the documentation :
After a pipeline runs successfully, you can view code coverage results in:
Merge request widget: See the coverage percentage and changes compared to the target branch.
Merge request widget showing code coverage percentage
Merge request diff: Review which lines are covered by tests. Available with Cobertura and JaCoCo reports. Pipeline jobs: Monitor coverage results for individual jobs.
maven - Code coverage report using gitlab-ci.yml file - Stack Overflow
java - GitLab CI&CD test coverage with jacoco - Stack Overflow
FR: Gitlab coverage report
Code coverage jacoco
It seems you forgot to add the calls to cat in your .gitlab-ci.yml file.
You should have something like that:
script:
- mvn $MAVEN_CLI_OPTS test
- cat target/site/jacoco/index.html
That being said, I don't think this is the best way of doing this, as you need to pollute your output with raw HTML in order to retreive the desired coverage value.
I would recommend using the method described in this pull request instead: https://github.com/jacoco/jacoco/pull/488
- Keep the jacoco parts in your
build.xml Use this awk instruction to print the correct code coverage total:
awk -F"," '{ instructions += $4 + $5; covered += $5 } END { print covered, "/", instructions, "instructions covered"; print 100*covered/instructions, "% covered" }' target/site/jacoco/jacoco.csvReplace the Gitlab CI regexp with what the instruction returns:
\d+.\d+ \% covered
Edit:
As of Gitlab 8.17, you can define the regexp directly inside the .gitlab-ci.yml file, as stated in the documentation.
It may seem superfluous, but if this regexp is now part of your repository history, you can change it alongside the other tools used to compute it.
GitLab employee here.
If your administrator has GitLab pages set up, you can see the URL that your artifact deployed to by going (on your project) to Settings -> Pages.
There you should see:
Congratulations! Your pages are served under: https://your-namespace.example.com/your-project
Click on that link and you should be good to go! Also we are expanding support for HTML artifacts. This issue and it’s related issues talk about existing and upcoming features that may expand on what you’ve built here.
In order to get ./gradlew test to output a summary of test coverage, I needed to add gradle-jacoco-log to my project.
plugins {
id 'org.barfuin.gradle.jacocolog' version '2.0.0'
}
test {
finalizedBy jacocoTestReport
}
jacocoTestReport {
dependsOn test
}
Which gives me the following console output:
> Task :jacocoLogTestCoverage
Test Coverage:
- Class Coverage: 100%
- Method Coverage: 83.6%
- Branch Coverage: 75%
- Line Coverage: 85.5%
- Instruction Coverage: 83.1%
- Complexity Coverage: 82.5%
I can then choose to report Instruction Coverage to GitLab by adding the following to .gitlab-ci.yml:
test:
stage: test
script: gradle check
coverage: '/ - Instruction Coverage: ([0-9.]+)%/'
GitLab Community Edition 15.7.6
parse_jacoco.sh
#!/bin/bash
# Check if the JaCoCo XML file path is provided
if [ $# -eq 0 ]; then
echo "Please provide the JaCoCo XML report file path"
exit 1
fi
JACOCO_XML=$1
# Check if the file exists
if [ ! -f "$JACOCO_XML" ]; then
echo "File not found: $JACOCO_XML"
exit 1
fi
# Ensure xmllint is installed
if ! command -v xmllint &> /dev/null; then
echo "xmllint is not installed. Please install libxml2-utils"
exit 1
fi
# Define a function to calculate coverage percentage
calculate_coverage() {
local covered=$1
local missed=$2
local total=$((covered + missed))
if [ $total -eq 0 ]; then
echo "0.0"
else
echo "scale=1; $covered * 100 / $total" | bc
fi
}
echo "Coverage Data:"
# Initialize total instruction coverage counters
total_instruction_covered=0
total_instruction_missed=0
# Get coverage for various types
for type in INSTRUCTION BRANCH LINE COMPLEXITY METHOD CLASS; do
covered=$(xmllint --xpath "sum(/report/counter[@type='$type']/@covered)" $JACOCO_XML)
missed=$(xmllint --xpath "sum(/report/counter[@type='$type']/@missed)" $JACOCO_XML)
total=$((covered + missed))
coverage=$(calculate_coverage $covered $missed)
echo "${type} Coverage: ${covered} covered, ${missed} missed, ${total} total (${coverage}%)"
# Accumulate INSTRUCTION coverage as the total coverage
if [ "$type" = "INSTRUCTION" ]; then
total_instruction_covered=$covered
total_instruction_missed=$missed
fi
done
# Calculate and output total coverage (echo here for GitLab usage)
total_coverage=$(calculate_coverage $total_instruction_covered $total_instruction_missed)
echo "Total Coverage: ${total_coverage}%"
gitlab config
stages:
- test
- visualize
test-job:
stage: test
image: maven:3.3-jdk-8
script:
- mvn verify
artifacts:
when: always
reports:
junit:
- target/surefire-reports/TEST-*.xml
- target/failsafe-reports/TEST-*.xml
paths:
- target/site/jacoco/jacoco.xml
tags:
- docker-runner
coverage-job:
stage: visualize
image: alpine:latest
before_script:
- apk add --no-cache libxml2-utils
script:
- ./parse_jacoco.sh target/site/jacoco/jacoco.xml
coverage: '/Total Coverage: (\d+\.\d+)%/'
needs: ["test-job"]
tags:
- docker-runner