doc/ci/testing/code_coverage/coverage_visualization.md
{{< details >}}
{{< /details >}}
Use the artifacts:reports:coverage_report
keyword to display line-by-line coverage annotations in merge request diffs.
This keyword displays diff annotations only. It does not display a coverage percentage in the
MR widget or populate coverage history graphs. To display a coverage percentage, configure
the coverage keyword separately.
After the pipeline completes, GitLab processes the report in the background and annotates lines in the MR diff:
Annotations appear only on files changed in the MR diff. Files not changed in the MR are not annotated, even if the report includes coverage data for them.
To configure coverage visualization, add artifacts:reports:coverage_report to your job:
test:
script:
- run tests with coverage
artifacts:
reports:
coverage_report:
coverage_format: cobertura # or jacoco
path: coverage/coverage.xml
For language-specific examples, see:
To collect multiple reports, use a wildcard in the artifact path. GitLab merges the results into a single report.
Coverage reports from child pipelines appear in MR diff annotations.
| Limit | Value |
|---|---|
| Maximum Cobertura XML file size | 10 MiB |
Maximum <source> nodes in a Cobertura XML file | 100 |
If your Cobertura report exceeds 100 <source> nodes, annotations may be missing or
mismatched in the diff view. For large projects, split the report into smaller files.
See issue 328772 for details.
The visualization appears only after the pipeline completes. If the pipeline has a blocking manual job, the visualization is not available until that job runs.
To download the coverage report from the job details page, add it to the
artifact paths as well as reports:
artifacts:
paths:
- coverage/cobertura-coverage.xml
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
Coverage reports use relative file paths. GitLab resolves these to absolute repository paths by matching them against the files changed in the MR.
For JaCoCo, the matching process is:
For Cobertura, GitLab also uses the <sources> element to reconstruct paths:
<source> entry.filename attribute of each <class> element.This automatic correction only works when <source> paths follow the format
<CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/....
For a C# project with a full path of test-org/test-cs-project and these files
relative to the project root:
Auth/User.cs
Lib/Utils/User.cs
With these sources in the Cobertura XML:
<sources>
<source>/builds/test-org/test-cs-project/Auth</source>
<source>/builds/test-org/test-cs-project/Lib/Utils</source>
</sources>
The parser extracts Auth and Lib/Utils from the sources, then combines each with the
filename attribute of each <class> element. For a class with filename="User.cs", the
first candidate that matches a file in the repository is Auth/User.cs.
For each <class> element, the parser attempts up to 100 iterations. If no match is found,
the class is not included in the final coverage report.
When working with coverage visualization, you might encounter the following issues.
Annotations might not appear for the following reasons:
The pipeline has not completed. Annotations are generated after the pipeline finishes. Wait for the pipeline to complete, then reload the MR diff.
The file is not in the MR diff. Annotations appear only on files changed in the MR, even if the report includes coverage data for other files.
The file path in the report does not match the repository path. If path resolution
fails, the annotation is silently skipped. To diagnose, download the coverage XML
artifact and compare the filename attribute on a <class> element to the file's
path in the repository relative to the project root.
The project has multiple modules with duplicate relative paths. When paths are not unique across modules, GitLab cannot resolve which file the annotation belongs to. Ensure relative paths are unique across modules:
src/main/java/org/acme/DemoExample.java
- src/main/other-module/org/acme/DemoExample.java
+ src/main/other-module/org/acme/OtherDemoExample.java
The coverage keyword is not configured. artifacts:reports:coverage_report does
not produce a percentage in the MR widget. To display a coverage percentage, configure
the coverage keyword separately.
This issue occurs when you create a new merge request from the same source branch but with a different target branch. The pipeline uses diffs from the previous merge request and does not display annotations for files not in that diff.
To fix this issue, wait until the new merge request is created, then rerun the pipeline.