Right, so I have a Kotlin Gradle project with the framework SpringBoot. The project is on GitHub and our CI system is Circle CI.
At the build.gradle.kts
file we have the following configs:
sonarqube {
properties {
property("sonar.projectKey", "Creditas_recupera-gateway")
property("sonar.organization", "creditas-fintech")
property("sonar.host.url", "https://sonarcloud.io")
property(
"sonar.coverage.jacoco.xmlReportPaths",
"$buildDir/reports/jacoco/jacocoTestReport/jacocoTestReport.xml"
)
}
}
fun ignorePackagesInJacocoReport(classDirectories: ConfigurableFileCollection) {
classDirectories.setFrom(
files(
classDirectories.files.map {
fileTree(it).apply {
exclude(
"**/company/**/*.java",
"**/company/**/*.kts",
"**/company/commons/**",
"**/company/**/config/**",
"**/company**/configuration/**",
"**/company/**/requests/**",
"**/company/**/responses/**",
"**/company/**/dto/**",
"**/company/**/infrastructure/scripts/**"
)
}
}
)
)
}
tasks.jacocoTestReport {
sourceSets(sourceSets.main.get())
executionData(fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec"))
reports {
xml.required.set(true)
html.required.set(true)
xml.outputLocation.set(File("$buildDir/reports/jacoco/jacocoTestReport/jacocoTestReport.xml"))
html.outputLocation.set(layout.buildDirectory.dir("$buildDir/reports/jacoco"))
}
ignorePackagesInJacocoReport(classDirectories)
}
Our config.yml
used by Circle CI is like the following:
version: 2.1
orbs:
docker: circleci/[email protected]
jobs:
unit_test:
steps:
- run:
name: Run tests
command: gradle test -i
- run:
name: Save test results
command: |
mkdir -p ~/junit/
find . -type f -regex ".*/build/test-results/.*xml"
find . -type f -regex ".*/build/test-results/.*xml" -exec cp {} ~/junit/ \;
when: always
- persist_to_workspace:
root: ~/
paths:
- project-folder/build/jacoco
coverage:
steps:
- run: ./gradlew dependencies build -x test -x detekt
- run:
name: Run coverage report
command: ./gradlew jacocoTestReport
- persist_to_workspace:
root: ~/
paths:
- recupera-gateway/build/reports/jacoco
sonarqube:
steps:
- restore_cache:
keys:
- app-dependencies-{{ checksum "build.gradle.kts" }}
- run: ./gradlew dependencies build -x test -x detekt
- save_cache:
paths:
- ~/.gradle
key: app-dependencies-{{ checksum "build.gradle.kts" }}
- attach_workspace:
at: ~/
- run:
name: Run sonar analysis
command: ./gradlew sonarqube
workflows:
version: 2.1
- unit_test
- coverage:
requires:
- unit_test
- sonarqube:
requires:
- coverage
Locally, running:
./gradlew jacocoTestReport
returns:
However, on SonarCloud, is the following:
Note that excluded files in Jacoco are present, and the total coverage is completely different. In SonarCloud General Settings, I am passing JacocoTestReport.xml path to the file:
So, first, I have a question: Does SonarCloud have the capacity to calculate the coverage by itself? Because it looks like it is taking the coverage results from somewhere else.
And second: How do I make Jacoco's Coverage Report match with SonarCloud's?
Note that I have omitted many information for security and privacy reasons. If any crucial information is missing, please ask and I will see if it can be provided. Also, it might sound like a duplicate, however other topics found does not have a solution for the problem.
CodePudding user response:
What happened is that, first of all, SonarCloud is unable to check if a file is being ignored or not from Jacoco's report, so it assumes it is 0% coverage. To solve this issue, it would be necessary to add the excluded files to Jacoco as well.
Another thing about the difference between Jacoco's coverage and SonarCloud's is that Jacoco also takes under consideration the instruction coverage, which is not represented on SonarCloud.
For a more complete answer I suggest to see this post on Sonar's forum here, all credits to that page.