How to lazy configure jacoco build directory

Hello,

I am currently trying to setup jacoco in a multi build project, however, run into some problems concerning the build path and are therefore looking for help.
I set up a small plugin in the build-logic to provide a common configuration for all projects that use jacoco. Here, I also want to modify the report directory of the xml, html, and csv reports. I figured out I need to configure this lazy, as I change the build directory for some builds in their respective build file. The resulting plugin looks like this:


plugins {
  `java`
  `jacoco`
}

tasks.jacocoTestReport.get().reports.csv.required.set(true)
tasks.jacocoTestReport.get().reports.html.required.set(false)
tasks.jacocoTestReport.get().reports.xml.required.set(true)
tasks.jacocoTestReport.get().reports.csv.outputLocation.set(layout.buildDirectory.file("/reports/test-coverage/jacoco.csv"))
tasks.jacocoTestReport.get().reports.html.outputLocation.set(layout.buildDirectory.dir("/reports/test-coverage/jacoco/html"))
tasks.jacocoTestReport.get().reports.xml.outputLocation.set(layout.buildDirectory.file("/reports/test-coverage/jacoco.xml"))

tasks.test.get().finalizedBy(tasks.jacocoTestReport)
tasks.jacocoTestReport.get().dependsOn(tasks.test)

This works fine locally. All projects that use this plugin produce files as expected in the “build/reports/test-coverage/” or similar for those that update their build path.
However, this does not work in a gitlab ci environment. Here, it seems that the default build path is only set after execution of the jacoco test report task. Files are generated into “/reports/test-coverage/”.

Printing the build path to command line after task execution via

tasks.getByName<JacocoReport>("jacocoTestReport").doLast {
  this as JacocoReport
  println("CSV report dir: " + this.reports.csv.outputLocation.get())
  println("XML report dir: " + this.reports.xml.outputLocation.get())
  println("Build dir: $buildDir")
}

produces these results:

CSV report dir: /reports/test-coverage/jacoco.csv
XML report dir: /reports/test-coverage/jacoco.xml
Build dir: PROJECT_DIR/build (with RPOJECT_DIR being a placeholder for the respective dir of the subproject)

Any ideas/input is highly appreciated.

Are you aware that you torpedo task configuration avoidance by using things like get() or getByName()?
Besides that readability suffers.
And a project can also set a custom report directory on the reporting extension.

So what you should have right now would better be

plugins {
    java
    jacoco
}

tasks.jacocoTestReport {
    reports {
        csv.required.set(true)
        html.required.set(false)
        xml.required.set(true)
        csv.outputLocation.set(reporting.baseDirectory.file("test-coverage/jacoco.csv"))
        html.outputLocation.set(reporting.baseDirectory.dir("test-coverage/jacoco/html"))
        xml.outputLocation.set(reporting.baseDirectory.file("test-coverage/jacoco.xml"))
    }
}

tasks.test { finalizedBy(tasks.jacocoTestReport) }
tasks.jacocoTestReport { dependsOn(tasks.test) }

and

tasks.withType<JacocoReport>().matching { it.name == "jacocoTestReport" }.configureEach {
    doLast {
        println("CSV report dir: " + reports.csv.outputLocation.get())
        println("XML report dir: " + reports.xml.outputLocation.get())
        println("Build dir: $buildDir")
    }
}

or actually

tasks.jacocoTestReport {
    doLast {
        println("CSV report dir: " + reports.csv.outputLocation.get())
        println("XML report dir: " + reports.xml.outputLocation.get())
        println("Build dir: $buildDir")
    }
}

I don’t actually expect this to change the output as you used lazy properties just didn’t honor task configuration avoidance, but maybe you give it a try.

Thank you very much for your input. I knew about configuration avoidance but never read into it in detail. So far, I was more concerned with getting the build up and running than the advertised benefits of configuration avoidance. The time it takes to configure our build pales in comparison to how long the actual build takes.

Still, with the input, I was happy to give it a try, and surprisingly, it did actually fix my problem, though I do not understand why. Thanks again for the input; for now, it seems like I have a solution to my problem.