gradle-print-coverage-plugin
gradle-print-coverage-plugin copied to clipboard
PrintCoverage with multi-module gradle project
Hi @jansauer,
Nice and lightweight plugin for Jacoco coverage console output. Appreciate your work.
I've tried your plugin in my pet multi-module Gradle project, but it looks like I've missed something. Does plugin support it? I didn't have a chance to look at your code, but when I run printCoverage on a root level, I have error, though running command per individual subproject works well.
gradlew check printCoverage
* What went wrong:
Execution failed for task ':printCoverage'.
> empty String
settings.gradle:
rootProject.name = "root"
include("sub1", "sub2", "sub3")
build gradle root:
buildscript {
repositories {
jcenter()
gradlePluginPortal()
}
dependencies {
classpath "gradle.plugin.de.jansauer.printcoverage:printcoverage:2.0.0"
}
}
allprojects {
apply plugin: "de.jansauer.printcoverage"
...
}
...
I would appreciate feedback from you!
Thanks, Yurii
Ou, It looks like that your print functionality depends on XML report, hmmm. Might worth to extend implementation for printcoverage() and catch subprojects reports with some math/aggregation involved for coverage result.
Hi @yurii-polishchuk Thx for your feedback. I have not yet worked with multi-module but should be interesting to get this working :-D Yes 'jacoco' generates the xml report and my plugin processes it. I'm at work right now but hopefully I will have time this evening to reproduce is and extend the plugin for multi-module support.
Cool Thnx,
For now, I did a trick and just merged all the results to root project level. overall looks good.
build.gradle (root one)
ext {
junitJupiterVersion = "5.2.0"
jacksonVersion = "2.9.5"
jacocoTestReportXml = "${buildDir}/reports/jacoco/test/jacocoTestReport.xml"
jacocoTestPattern = "**/build/jacoco/*.exec"
}
buildscript {
repositories {
jcenter()
gradlePluginPortal()
}
dependencies {
classpath "gradle.plugin.de.jansauer.printcoverage:printcoverage:2.0.0"
}
}
allprojects {
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'jacoco'
apply plugin: "de.jansauer.printcoverage"
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
repositories {
jcenter()
}
dependencies {
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}"
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"
testImplementation "org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}"
testImplementation "org.mockito:mockito-junit-jupiter:2.18.3"
}
test {
useJUnitPlatform()
}
jacoco {
toolVersion = '0.8.1'
}
check.dependsOn jacocoTestCoverageVerification
}
task codeCoverageReportRoot(type: JacocoReport) {
// Gather execution data from all sub-projects
// (change this if you e.g. want to calculate unit test/integration test coverage separately)
executionData fileTree(project.rootDir.absolutePath).include(jacocoTestPattern)
// Add all relevant source-sets from the sub-projects
subprojects.each {
sourceSets it.sourceSets.main
}
// Generate global merged report
reports {
xml.setEnabled(true)
xml.setDestination(file(jacocoTestReportXml))
html.setEnabled(false)
csv.setEnabled(false)
}
}
// Always run the tests before generating the report
codeCoverageReportRoot.dependsOn subprojects.collect { it.tasks.check }
codeCoverageReportRoot.dependsOn jacocoTestReport
printCoverage.dependsOn codeCoverageReportRoot
project(":sub1")
project(":sub3") {
dependencies {
implementation project(":sub1")
}
}
project(":sub2") {
dependencies {
implementation project(":sub1")
}
}
As a result:

As a result in console:
> Task :printCoverage
Coverage: 74.93%
> Task :sub1:jacocoTestReport UP-TO-DATE
> Task :sub1:printCoverage
Coverage: 75.58%
> Task :sub2:jacocoTestReport UP-TO-DATE
> Task :sub2:printCoverage
Coverage: 1.64%
> Task :sub3:jacocoTestReport UP-TO-DATE
> Task :sub3:printCoverage
Coverage: 95.02%
@jansauer though, it would be very helpfull, if in: https://github.com/jansauer/gradle-print-coverage-plugin/blob/master/src/main/groovy/de/jansauer/printcoverage/PrintCoverageTask.groovy
File jacocoTestReport = new File("${project.buildDir}/reports/jacoco/test/jacocoTestReport.xml") Would not be hardcoded
it would be much easier to make it configurable and tell your task to parse any XML
I agree with @yurii-polishchuk . It would be very helpful if we could configure where/which xml report to parse.
I maintain a lot of projects and almost all of them are Multi module Gradle projects. I needed an overall coverage report. So, I also ended up doing the same thing. In my root project's build.gradle file, I added a task that creates an aggregated report of all the subprojects.
task combinedCoverageReport(type: JacocoReport) {
additionalSourceDirs = files(subprojects.sourceSets.main.allSource.srcDirs)
sourceDirectories = files(subprojects.sourceSets.main.allSource.srcDirs)
classDirectories = files(subprojects.sourceSets.main.output)
executionData = files(subprojects.jacocoTestReport.executionData)
reports {
html.enabled = true
xml.enabled = true
csv.enabled = false
}
doFirst {
classDirectories = files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
'**/some/package/to/be/excluded/if/needed/*'
])
})
executionData = files(executionData.findAll { it.exists() })
}
}
The above task will generate the combined xml report under $rootProject.buildDir/jacoco/combinedCoverageReport/combinedCoverageReport.xml
I then added another Copy task that will copy the above xml report generated by above task to $rootProject.buildDir/jacoco/test/jacocoTestReport.xml, which is what this plugin expects.
task copyRootCoverageReport(type: Copy) {
from (combinedCoverageReport) {
include "combinedCoverageReport.xml"
}
rename ("combinedCoverageReport.xml", "jacocoTestReport.xml")
into "$buildDir/reports/jacoco/test"
}
@amimas Your message is from a long time ago but ... You can add
report {
...
xml.destination = file("$buildDir/reports/jacoco/test/jacocoTestReport.xml")
...
}
in your combinedCoverageReport instead of having a separate copy task.