Skip to content
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

PrintCoverage with multi-module gradle project #1

Open
yurii-polishchuk opened this issue May 8, 2018 · 6 comments
Open

PrintCoverage with multi-module gradle project #1

yurii-polishchuk opened this issue May 8, 2018 · 6 comments
Labels
enhancement New feature or request

Comments

@yurii-polishchuk
Copy link

yurii-polishchuk commented May 8, 2018

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

@yurii-polishchuk
Copy link
Author

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.

@jansauer
Copy link
Owner

jansauer commented May 9, 2018

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.

@yurii-polishchuk
Copy link
Author

yurii-polishchuk commented May 10, 2018

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:

image

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%

@yurii-polishchuk
Copy link
Author

@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

@amimas
Copy link

amimas commented Jul 5, 2018

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"
}

@pdegand
Copy link

pdegand commented Jan 27, 2020

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants