New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Jacoco Gradle Sonarqube multi-module #8881
Comments
After a 2 days of trying different things I found the following to be working. Not sure if this is the best approach, but this at least works for me now. I think the key is to have the jacocomerge being called using the
Is this the best approach to do this? If yes it might make sense to add this to the jacoco plugin documentation as an example to use it for multimodule gradle projects. |
I am facing similar difficulties (mockito/mockito#1689). I will try out your approach and report if it is working. |
It works for me also |
After upgrading to SonarQube 8.1 (which includes some show unstopping bug fixes, so downgrading isn't an option), the binary jacoco exec data is no longer supported, which means the JacocoMerge solution from the jacoco plugin no longer works. And we're losing our coverage tracking for our large multi module project since the upgrade. |
Can I please find somewhere basic process description on how to implement jacoco and sonar for multi module gradle project ? I have found so many misleading and contradictory information... |
@Veranicus at least my comment above did work for us at the time of writing. Not sure with newer versions etc. Can't check either as I left the company and thereby also that codebase. |
@marcofranssen your solution is appropriate only for older versions of the SonarJava scanner. The latest does not support the old jacoco binary .exec format. It requires XML. The solution provided at https://community.sonarsource.com/t/coverage-test-data-importing-jacoco-coverage-report-in-xml-format/12151 describes how to support multi-module xml merge with Maven, but it is not explicit with Gradle. Removing the JacocoMerge step and ensuring the xml data is being produced, we are getting coverage numbers again. But nearly 1/2 of what they used to be. |
@hajush do you see any reason why the coverage values have changed? |
I’ve not worked it out yet but has everything only done limited experiments. I suspect it is just a path issue. I plan to spend more time investigating next week and will update what I find. |
I've got it working finally after a lot of struggle and referring to documents and solutions. My
Command to run test with coverage:
Two things to be noted that made it work:
|
We now added a sample showing how to properly configure a multi-module build using jacoco (HTML or XML for Sonar). As mentioned above already, |
My Project configuration : Gradle 2.8 ,SonarQube 7.9 |
@cdpatelgit could this Gradle plugin be useful to you? https://remal.gitlab.io/gradle-plugins/plugins/name.remal.merged-jacoco-report/ |
@ashwini-desai Thank you! I tried many ways to fix it only your fixes worked for me! Using gradle 6.5.1 and sonarqube 8.3.1.34397 |
I am also trying to integrate jacoco with SonarQube for my multi-module project. I have an XML code coverage report generated. I have defined the following properties:
But I am unable to see the coverage report. Is there anything I am missing? |
Here's the solution I use with Gradle 7.4 (non-Android project), based on my earlier finding #8794 (comment) : plugins {
id 'jacoco'
}
repositories {
// Need to resolve `org.jacoco.ant` jar on root level too. You can also use `allprojects {}` for common repo declarations.
mavenCentral()
}
subprojects {
pluginManager.withPlugin('java') {
apply plugin: 'jacoco'
tasks.withType(JacocoReport).configureEach { enabled = false }
tasks.withType(Test).configureEach { finalizedBy ':jacocoMergedReport' }
}
}
tasks.register('jacocoMergedReport', JacocoReport) {
subprojects {
pluginManager.withPlugin('jacoco') {
sourceSets sourceSets.main
// `executionData tasks.withType(Test)` should work but it doesn't...
executionData files(tasks.withType(Test)).filter { it.name.endsWith('.exec') && it.exists() }
}
}
reports {
xml.required = true
html.required = true
}
}
sonarqube {
properties {
property 'sonar.coverage.jacoco.xmlReportPaths', "${tasks.named('jacocoMergedReport', JacocoReport).get().reports.xml.outputLocation.get()}"
}
}
subprojects {
pluginManager.withPlugin('java') {
sonarqube {
properties {
property 'sonar.coverage.jacoco.xmlReportPaths', null
}
}
}
} Currently I can't recommend the jacoco-report-aggregation plugin due its limitation that it cannot aggregate all test types: #23223 Update: See also more solution ideas at #26668 TL;DR (Why other approaches are problematic)More explanation: The default approach is to enable JaCoCo in every project, but then JaCoCo itself will no longer track coverage across subprojects. So this is also a JaCoCo problem. One naive way to address this problem I saw was something like this: subprojects {
gradle.projectsEvaluated {
tasks.withType(JacocoReport).configureEach {
configurations.implementation.allDependencies.withType(ProjectDependency)*.dependencyProject.each {
additionalSourceDirs files(it.sourceSets.main.java.srcDirs)
additionalClassDirs files(it.sourceSets.main.output)
}
}
}
} But it has two problems: one is that now you can look for coverage for the same class in multiple HTML reports. And if you tell Sonar to track sources similarly, it will complain like:
You can fiddle around with the exclude patterns, but they will fail the same way if multiple subprojects depend on the same subproject. So the following configuration won't help every project, plus I think it's more complicated than having a single report: subprojects {
configurations.implementation.allDependencies.withType(ProjectDependency)*.dependencyProject.each { proj ->
sonarqube {
properties {
property 'sonar.projectBaseDir', rootDir
property 'sonar.sources', properties['sonar.sources'] + proj.sourceSets.main.java.srcDirs
property 'sonar.tests', properties['sonar.tests'].split(/,/).collect { (projectDir as String) + '/' + it }
}
}
proj.sonarqube {
properties {
property 'sonar.exclusions', ((properties['sonar.exclusions'] ?: []) +
proj.sourceSets.main.java.srcDirs.collect { "${it}/**" - "${proj.projectDir}/" }).unique()
}
}
}
} |
hello @hajush , i am in a similar situation as once you were. For me we are using gradle 4.6 and our sonarqube server is 8.9. |
Hi @himanshu2416 - unfortunately, I stopped working on that code base days after my post in 2020, so I had no time to do further investigations. I'm pretty sure that if you run the tasks.register('jacocoMergedReport', JacocoReport) as @rkrisztian described on April 4, 2023, you should get a merged report. It was working for me in 2020, I was just not sure why our coverage number declined so much, but it was probably a path or other configuration issue for the overall project. |
@hajush to be honest i did not try the approach by @rkrisztian as we are using gradle 4.6 and the task.register() method is available from gradle 5. But i will try something on similar lines. Thank you for the feedback. |
@himanshu2416 I'm pretty sure we were using Gradle 6 at the time the beginning of 2020 and we definitely were using the task.register() method. Gradle is up to 8.1 today. Not sure anything will go well without upgrading, but if you do it should work. |
#23223 (comment) solves the issue with the aggregation plugin, which can be good if you need not just the full aggregation but also per test type. |
I'm unable to get a working code coverage report for sonarqube plugin so all the covered code is reflected. There are always some of my subprojects missing from the coverage report which is invalid as they are touched by my tests for sure.
Is there anyone able to provide a good example on the official documentation page over here?
https://docs.gradle.org/current/userguide/jacoco_plugin.html
It seems there are many people suffering from this, all providing different approaches, all giving different, but inaccurate results. With one approach Project B isn't in the coverage report with another approach it appears Project C isn't included etc.
Would be great if there is a complete example on how to use jacocoMerge tasks with gradle 5.3 using a gradle project with subprojects.
Below an extract of my build gradle with the last approach I tried for getting the gradle stuff merged.
The text was updated successfully, but these errors were encountered: