how can I make jacoco play nice with JvmTestSuite....
# community-support
c
how can I make jacoco play nice with JvmTestSuite. I had to split my existing
test
suite in 2 and now my coverage has dropped
v
how can I make jacoco play nice with JvmTestSuite
It does in one way of the definition. It provides you with coverage report per test type. And with the
jacoco-report-aggregation
plugin you can merge the reports of multiple projects per test type. If you want an overall JaCoCo report over all test types, you have to manually configure it.
c
after applying the aggregation plugin which appears? to be no-config needed by default, I get this error
Copy code
Could not create domain object 'whitebox' (JvmTestSuite)
> Cannot query the value of this provider because it has no value available.
  The value of this provider is derived from:
    - property 'testType'
I'm applying the jacoco* plugins via a convention plugin
I think it's cute that gradle thinks I distinguish my tests in suites this way. Using the Test Trophy with proper layering I'm not certain it ever makes sense.
for performance tests maybe... only because they usually involve repeats that can add a lot of time
e2e doesn't make sense to even be in the same project
but anyways, yeah, to me it looks like I'm setting test type, but the aggregation plugin says I"m not
v
Iirc you cannot have two suites for the same type anyway
c
oh, that's probably it, and naive
nope, that's not it, I changed and it still doesn't work
v
Well, maybe the full error would help? 🤷‍♂️
c
that is the full error that I see, or did you mean if I print the stacktrace
Untitled
this is line
72
Copy code
val whitebox by registering(JvmTestSuite::class) {
v
From the stacktrace I'd say you (or some plugin) have some action like
testing.suites.all { ... }
or
testing.suites.configureEach { ... }
that tries to use the suite type before it got set, and something causes the suite to be realized immediately
c
that would be true, I was told to do the previous block in a previous question
v
From a cursory look I'd say that is not the culprit
c
well this is the test convention plugin
which does nothing explicitly to whitebox...
sounds like you're saying that has to somehow be applied after? but that looks the same to me
gonna be a real pain if I have to create the named suite first
tried to put this in my convention plugin and the final project, the normal default should be unit
Copy code
if (!testType.isPresent) testType.set(TestSuiteType.INTEGRATION_TEST)
and whitebox is explicitly set to functional
SSDD
v
Ah, wait, it does not complain that you do not have a test type on the suite.
It complains you have configured an aggregate report without type
c
is that in the stacktrace?
v
yes
c
because that's not what the top level error says
lol
v
Just not displayed in Slack as it cuts the snippet and accessing full Slack snippets via browser hurts each time
c
snippets is arguably better than the backtick support, but yes
v
The top level error says something went wrong when creating the test suite whitebox. The caused by shows what happened when trying to create the test suite
c
although, I don't use the browser
v
And that is coming from the aggregation plugin when it tries to iterate over the test reports
snippets is arguably better than the backtick support
It's arguably much worse, yes 🙂
I mean the snippet support
I did not see any benefit yet and only have PITA every time I have to access it through the browser which does not remember me so I always have to login, then wait for e-mail and copy over code, then enter 2fa code, and then just get an error and need to open the link again
c
how 'bout discord is better ...
v
the threads support in discord is 💩
c
backticks are better because they support syntax highlighting
I haven't had a problem with threads in dicord
lol
other than no one ever uses them!
v
Ah, you meant backticks is better, ok. I got that you said snippet is better than backticks
c
I did, in slack
because syntax highlighting
slack backtick support is like using notepad
so what's the right answer for the aggregate plugin
it appears confused
v
Ah, yeah with backticks in Slack you have no syntax hl, but in my eyes still much better than the snippets.
so what's the right answer for the aggregate plugin
set the test type on the report you defined, as I said
c
I don't create that.. but I suppose I could do it in the withType
Copy code
// © Copyright 2023-2024 Caleb Cushing
// SPDX-License-Identifier: MIT

plugins {
  `java-base`
  jacoco
}

val coverage = project.extensions.create<CoveragePluginExtension>("coverage")

tasks.withType<JacocoReport> {
  dependsOn(project.tasks.withType<Test>())
}

project.tasks.check.configure {
  dependsOn(tasks.withType<JacocoCoverageVerification>())
}

tasks.withType<JacocoCoverageVerification>().configureEach {
  dependsOn(project.tasks.withType<JacocoReport>())
  violationRules {
    rule {
      limit {
        coverage.minimum.convention(0.9).let { minimum = it.get().toBigDecimal() }
      }
    }
  }
}

interface CoveragePluginExtension {
  val minimum: Property<Double>
}
(wondering why I didn't use configureEach
v
While that is a good question and misses a comment if intentional, that is the report task. What is missing the type is the report configured for the aggregate plugin
Like having example 1 on https://docs.gradle.org/current/userguide/jacoco_report_aggregation_plugin.html but there not setting the test type
I think that is what the stacktrace says
Actually yes, the missing
confiugreEach
could be the problem, as then the report is eagerly evaluated and then is missing the testtype as it is not set on the test suite yet
The should print in the error which
testType
property is missing a value 😕
c
yeah, it's definitely the missing configureEach
👌 1
doesn't fix my aggregation problem, but kills that error
I do not understand how it's supposed to aggregate my test and whitebox suites
if I can't give 2 suites the same type
v
I told you it is not. It is supposed to aggregate the results for the same test type over multiple projects.
c
right, so it doesn't solve my problem
so how do I solve my problem
v
And to aggregate multiple within the same project or over projects, you need to do some configuration
Only within the same project? Just register a jacoco report task and configure it to
reportsOn
all the test tasks.
To get this over multiple projects cleanly, you need significantly more configuration, but it is doable, I did it in the past
c
yeah, I don't (currently) need/want to do multi-project tasks
v
Yeah, then it should be relatively easy
c
I personally feel that enforcing coverage over the whole repo is a bad idea, but a single project is good
I see each project as an independent library
v
All has its pros and cons.
For example if you want to report coverage to TeamCity, you need one aggregated result
And you can also configure it in a way so you can create the individual reports but also an aggregated one
All a matter of preference, really
c
well... yeah, I mean, there's always the option of both
v
Exactly
You actually don't even need to register a new report task
c
if you do a project as a whole you end up with the problem of completely uncovered code in certain places simply because it's being offset somewhere else. That's my experience
v
You already have one task that you want to use, don't you?
Just configure it to report on all test tasks and I think you should be fine
c
I mean, I didn't create it, but I think only one is created by default for test
v
Probably even removes the need for explicit dependency from report task to test task
I mean, I didn't create it, but I think only one is created by default for test
Exactly
If I have it in mind correctly, you just need
executionData(tasks.withType<Test>())
and can then even remove the explicit dependency from report task to test tasks
c
you mean like this?
Copy code
tasks.withType<JacocoReport>().configureEach {
  dependsOn(project.tasks.withType<Test>()) // tried removing
  executionData(project.tasks.withType<Test>())
}
Copy code
Could not determine the dependencies of task ':controller-authn:jacocoTestCoverageVerification'.
> Could not create task ':controller-authn:jacocoTestReport'.
   > DefaultTaskCollection#all(Action) on task set cannot be executed in the current context.
interesting how late that would be though...
probably because it's disabled
Copy code
// © Copyright 2024 Caleb Cushing
// SPDX-License-Identifier: MIT

import com.github.spotbugs.snom.SpotBugsTask

buildscript { dependencyLocking { lockAllConfigurations() } }

plugins {
  our.javalibrary
}

val demoServer by sourceSets.creating

java {
  registerFeature("demoServer") {
    usingSourceSet(demoServer)
  }
}

val demoServerImplementation by configurations.existing
val demoServerRuntimeOnly by configurations.existing
val demoServerApi by configurations.existing

dependencies {
  implementation(libs.spring.security.config)
  implementation(libs.spring.security.web)
  implementation(libs.spring.context)

  runtimeOnly(libs.starter.security)
  runtimeOnly(libs.starter.web)
  runtimeOnly(libs.starter.oauth2.resource.server)

  testFixturesImplementation(platform(libs.spring.bom))
  testFixturesImplementation(libs.log4j.api)
  testFixturesImplementation(libs.spring.security.core)
  testFixturesImplementation(libs.spring.web)

  testImplementation(libs.bundles.spring.test)

  testRuntimeOnly(libs.starter.web)
  testRuntimeOnly(libs.starter.webflux)
  testRuntimeOnly(projects.testApp)

  demoServerApi(platform(libs.spring.bom))
  demoServerApi(libs.spring.context)
  demoServerApi(libs.spring.boot.autoconfigure)

  demoServerImplementation(platform(libs.spring.bom))
  demoServerImplementation(libs.spring.security.config)
  demoServerImplementation(libs.spring.webmvc)
  demoServerImplementation(libs.spring.boot.actuator)
  demoServerImplementation(libs.spring.boot.core)

  demoServerRuntimeOnly(platform(libs.spring.bom))
  demoServerRuntimeOnly(testFixtures(project))
  demoServerRuntimeOnly(libs.spring.boot.devtools)
  demoServerRuntimeOnly(libs.starter.actuator)
  demoServerRuntimeOnly(libs.starter.log4j2)
  demoServerRuntimeOnly(libs.starter.web)
  demoServerRuntimeOnly(libs.starter.security)
  demoServerRuntimeOnly(libs.starter.oauth2.resource.server)

  modules {
    module("org.springframework.boot:spring-boot-starter-logging") {
      replacedBy(
        "org.springframework.boot:spring-boot-starter-log4j2",
        "Use Log4j2 instead of Logback",
      )
    }
  }
}

tasks.withType<Test>().configureEach {
  enabled = false
}

tasks.withType<JacocoCoverageVerification>().configureEach {
  enabled = false
}

tasks.withType<SpotBugsTask>().configureEach {
  enabled = false
}

tasks.withType<Javadoc>().configureEach {
  enabled = false
}
but why would that cause that errror
v
Or that is the reason why the configure each was missing
c
hah, but adding configureEach didn't break this
not until I added your executionData
v
🤷‍♂️
c
although I've added code that I could remove that disable, now that I can set the limit externally
why does executionData break this though? verification is run later, no?
this doesn't really say don't run coverage, it says don't fail on not meeting the limit
oh, but I"m also disabling test
hrm..
my tests are passing, I always wonder why
well I re-enabled those suites, but looks like I"m not facing another error regarding whitebox. p.s. sorry about the snippet, but it was too big
intellij says
Copy code
Could not create task ':jpa:whiteboxCodeCoverageReport'.
DefaultTaskCollection#all(Action) on task set cannot be executed in the current context.
if scans are preferred to snippet, I can add those instead, this is all open source code after all
I wish gradle would create more machine parseable outputs so I could be like
.gradlew foo:bar --json | jq ".scan" | clip
v
if scans are preferred to snippet
yes, always for me 🙂
> I wish gradle would create more machine parseable outputs
Copy code
develocity {
    buildScan {
        buildScanPublished {
            // log ${this.buildScanUri} in parseable form or set clipboard to it
        }
    }
}
c
well, there's the 2 scans 😉
I've isolated in main that it's caused by executionData
v
Yeah, sure, that's also what the stacktrace is saying. This is executed at a time where
all
is no longer legal
Probably pre-dates task-configuration avoidance. Move it around, then it works:
Copy code
tasks.withType<Test>().configureEach {
    tasks.jacocoTestReport {
        executionData(this@configureEach)
    }
}
c
I don't seem to have that accessor generated in my convention plugin... but this should be the same... or enough?
Copy code
tasks.withType<Test>().configureEach {
  tasks.withType<JacocoReport>().named("jacocoTestReport") {
    executionData(this@configureEach)
  }
}
https://gradle.com/s/rjqsnzklgxfuq
v
Almost
Copy code
tasks.withType<Test>().configureEach {
    tasks.named<JacocoReport>("jacocoTestReport") {
        executionData(this@configureEach)
    }
}
c
v
... what the ...
Argh, executed the wrong task to test as IJ prefers to restart the debug configuration even if the last was run * grml *
c
roflol, I can't even upgrade intellij these days
I've formerly declared if they don't fix there shit by january I'm going to stop giving them money
I moved my renewal date because of it
v
Hm, might be not possible to do it lazy in lazy. Maybe that changes with the propertyrisation in Gradle 9. But I guess for now you have to do something like
Copy code
tasks.jacocoTestReport {
    tasks.withType<Test>().forEach(::executionData)
}
And you do seem to still need the explicit task dependency 😞
Or maybe you don't want to do it with
withType
but simply in the test suite configuration if that works
Hm, this seems to work, and also without the explicit task dependency:
Copy code
testing {
    suites {
        val fooTests by registering(JvmTestSuite::class) {
            targets.all {
                tasks.jacocoTestReport {
                    executionData(testTask)
                }
            }
        }
    }
}
If you then execute
jacocoTestReport
it gives no error and automatically depends on
fooTests
That probably was what I had in mind
c
so I would use
whitebox
not
fooTests
and
test
will automoagically work?
v
Yes and no. It would still report on it, but probably miss the dependency. You can probably do that too with
suites.configureEach
I hope
c
INTELLIJ!!!! I would love to know why intellij (and only intellij from what I can tell) downloads things like they don't have locks
Copy code
> Task :prepareKotlinBuildScriptModel UP-TO-DATE
Download <https://plugins.gradle.org/m2/com/diffplug/spotless/spotless-plugin-gradle/maven-metadata.xml>, took 116 ms
Download <https://plugins.gradle.org/m2/com/github/spotbugs/snom/spotbugs-gradle-plugin/maven-metadata.xml>, took 44 ms
Download <https://plugins.gradle.org/m2/net/ltgt/gradle/gradle-errorprone-plugin/maven-metadata.xml>, took 39 ms
https://gradle.com/s/revjgwvmbt6nu Unable to read execution data file
Copy code
// © Copyright 2023-2024 Caleb Cushing
// SPDX-License-Identifier: MIT

buildscript { dependencyLocking { lockAllConfigurations() } }

plugins { our.javalibrary }

coverage {
  // right now whitebox testing has broken this
  minimum.set(0.2)
}

dependencies {
  annotationProcessor(platform(libs.jakarta.bom))
  annotationProcessor(platform(libs.spring.bom))
  annotationProcessor(libs.hibernate.jpa.modelgen)

  compileOnly(libs.java.tools)

  api(projects.model)
  api(libs.jakarta.persistence)
  api(libs.jakarta.validation)
  api(libs.spring.context)
  api(libs.spring.data.commons)
  api(libs.hibernate.envers)

  implementation(libs.commons.lang)
  implementation(libs.spring.beans)
  implementation(libs.spring.transaction)

  runtimeOnly(libs.starter.data.jpa)
  runtimeOnly(libs.starter.validation)
  // transients required by jakarta transaction which is required by hibernate
  runtimeOnly(libs.jakarta.cdi)
  runtimeOnly(libs.jakarta.lang.model)
  runtimeOnly(libs.jakarta.interceptor)

  testFixturesAnnotationProcessor(platform(libs.jakarta.bom))
  testFixturesAnnotationProcessor(platform(libs.spring.bom))
  testFixturesAnnotationProcessor(libs.hibernate.jpa.modelgen)

  testFixturesApi(projects.model)
  testFixturesApi(libs.spring.data.jpa)
  testFixturesImplementation(libs.uuid.creator)
  testFixturesImplementation(libs.java.tools)

  testFixturesCompileOnlyApi(libs.jspecify)
}

testing {
  suites {
    withType<JvmTestSuite>().configureEach {
      dependencies {
        implementation(testFixtures(project()))

        implementation(platform(libs.jakarta.bom))
        implementation(platform(libs.spring.bom))
        implementation(libs.spring.test)
        implementation(libs.spring.boot.test.autoconfigure)
        implementation(libs.spring.boot.test.core)

        runtimeOnly(libs.h2)
        runtimeOnly(libs.starter.validation)
        runtimeOnly(libs.starter.data.jpa)
        runtimeOnly(libs.starter.aop)
        runtimeOnly(projects.testApp)
        runtimeOnly(libs.spring.data.envers)
      }
    }

    val test by getting(JvmTestSuite::class) {
      dependencies {
        implementation(libs.spring.orm)
        compileOnly(libs.jspecify)
      }
    }
    val whitebox by registering(JvmTestSuite::class) {
      targets.all {
        tasks.jacocoTestReport {
          executionData(testTask)
        }
      }
      dependencies {
        implementation(projects.jpa)
        implementation(projects.model)
        implementation(libs.equalsverifier)
        implementation(libs.commons.lang)
        implementation(libs.spring.beans)
        implementation(libs.spring.transaction)
        implementation(libs.hibernate.orm.core)
      }
    }
  }
}

tasks.compileJava {
  options.release = 17
  options.compilerArgs.addAll(
    listOf(
      "-AaddSuppressWarningsAnnotation=true",
      "-AaddGeneratedAnnotation=true",
    ),
  )
}
thought maybe this would work, but seems like I still only get 0.2 coverage https://gradle.com/s/vqp64jkgsp6u6 it does list both exec files
Copy code
tasks.withType<JacocoReport>().configureEach {
  dependsOn(project.tasks.withType<Test>())
  val files = project.layout.buildDirectory.dir("jacoco").get().asFileTree.toList()
  logger.quiet("Jacoco: {}", files)
  executionData(files)
}
would have thought that would work based on my understanding of the google
hmm.. that evaluation would be too early
wait, this is weird. the generated report shows me 93.% which sounds right
Copy code
// © Copyright 2023-2024 Caleb Cushing
// SPDX-License-Identifier: MIT

plugins {
  `java-base`
  jacoco
  // `jacoco-report-aggregation`
}

val coverage = project.extensions.create<CoveragePluginExtension>("coverage")

tasks.withType<JacocoReport>().configureEach {
  dependsOn(project.tasks.withType<Test>())
  val files = project.layout.buildDirectory.dir("jacoco").map { it.asFileTree.toList() }
  executionData(files)
}

project.tasks.check.configure {
  dependsOn(tasks.withType<JacocoCoverageVerification>())
}

tasks.withType<JacocoCoverageVerification>().configureEach {
  dependsOn(project.tasks.withType<JacocoReport>())
  violationRules {
    rule {
      limit {
        coverage.minimum.convention(0.9).let { minimum = it.get().toBigDecimal() }
      }
    }
  }
}

interface CoveragePluginExtension {
  val minimum: Property<Double>
}
and it looks right
this works... ugh... is there a better way to get the list of files?
Copy code
// © Copyright 2023-2024 Caleb Cushing
// SPDX-License-Identifier: MIT

plugins {
  `java-base`
  jacoco
  // `jacoco-report-aggregation`
}

val coverage = project.extensions.create<CoveragePluginExtension>("coverage")

tasks.withType<JacocoReport>().configureEach {
  dependsOn(project.tasks.withType<Test>())
  val files = project.layout.buildDirectory.dir("jacoco").map { it.asFileTree.toList() }
  executionData(files)
}

project.tasks.check.configure {
  dependsOn(tasks.withType<JacocoCoverageVerification>())
}

tasks.withType<JacocoCoverageVerification>().configureEach {
  executionData(project.tasks.withType<JacocoReport>().map { it.executionData })
  violationRules {
    rule {
      limit {
        coverage.minimum.convention(0.9).let { minimum = it.get().toBigDecimal() }
      }
    }
  }
}

interface CoveragePluginExtension {
  val minimum: Property<Double>
}
Copy code
tasks.withType<JacocoReport>().configureEach {
  dependsOn(project.tasks.withType<Test>())
  // execution data needs to be aggregated from all exec files in the project for multi jvm test suite testing
  executionData(project.layout.buildDirectory.dir("jacoco"))
}
seems to work, but I'm wondering if there's a way to get that
jacoco
string from a configured setting instead which feels like surprising behavior because it can be overriden in the jacoco task but I can't find a way to get the result
well.. I thought it worked, but now I think there's a race condition on creating things
v
It will probably only work on a dirty work tree
You list the existing files at configuration time
So if you are on a clean worktree there will be no files found?
With the
...filetree...
I mean
c
probs
rather looks like
so this looks relatively like what needs to happen, but I guess not sure how to accomplish it yet
v
if there's a way to get that
jacoco
string from a configured setting
I guess
output
on the
JacocoTaskExtension
on the
Test
task?
c
probably? but I don't know how to get that from within the report block
and I guess still not sure it would work, because that assumes things exist
v
I don't think it does
The version with
filtree
does
But
executionData
called with not task collection or task is basically like
configurableFileColleciton.from
I think
c
I tried just doing the .dir and it seemed to work but then I saw a failure that the
jacoco
dir was missing...
v
At execution time then when you have the test task disabled or not running any tests?
c
what? no, this is a project where it's enabled
I was running
build
https://gradle.com/s/t5fibtd2dsv2u like this, but I've seen a build where it was
model
too
so, yeah, I guess still looking for a solution to aggregating jvm test suites
v
Well, maybe you do need to go the extra mile to do it like I did it with the cross-project just not cross-project. I think I even described it here somewhere already
c
and how will I be able to validate that each library meets its standard? so that I don't end up with entire libraries untested because they're small
v
Basically you replicate what the jacoco plugin and report aggregation plugin are doing, just a bit customized. You add a consumable configuration for the binary like the jacoco plugin does for each test suite with the
TEST_SUITE_TYPE_ATTRIBUTE
set to
all
. Then like the jacoco plugin you
configureEach
all test suites, doing adding
testTask.map { it.jacoco.destinationFile!! }
as artifact to that configuration with type
BINARY_DATA_TYPE
. And then you can register a report for the jacoco report aggregation plugin with test type
all
.
and how will I be able to validate that each library meets its standard? so that I don't end up with entire libraries untested because they're small
Not sure what you mean
c
btfh
v
What libraries are you talking about?
c
I said it earlier. I treat each subproject like it's own library
because that's what it is
thus each of them must meet a coverage standard
v
You can do that per project, no problem
c
right now apparently not
not without "replicating an existing plugin"
v
Iirc you just set the configuration the aggregation plugin adds to
isTransitive = false
By default it aggregates the current project and all projects it depends on directly or transitively
c
I'm done for the night, I think the obvious next step for me is actually to investigate the alternatives to gradle
I spend more time on build logic than writing real code
v
Good luck
c
Thanks!
trying the aggregation plugin. the task that the documentation says is there, is not there https://scans.gradle.com/s/b34f3eglo7aay/plugins?toggled=WyJqYWNvY28tcmVwb3J0LWFnZ3JlZ2F0aW9uLTI1Il0
tried
jacocoTestReport - Generates code coverage report for the test task.
but that didn't actually generate a report
v
You misinterpret the docs
testSuite
is italic, that means it is a placeholder
c
probably, they should be better written
v
Above it it says "for each test suite"
So for example
integTestCodeCoverageReport
if the test suite is called
integTest
The
jacocoTestReport
is the standard JaCoCo report task, not related to the aggregation plugin
probably, they should be better written
Always
Any docs
c
yes, I know, but it was the one listed in gradlew tasks
v
Feel free to open an improvement issue, or PR 😉
yes, I know, but it was the one listed in gradlew tasks
Both should be listed
c
maybe I will if I can ever get it working
is not
Copy code
Reusing configuration cache.

> Task :tasks

------------------------------------------------------------
Tasks runnable from root project 'spring-app-commons'
------------------------------------------------------------

Build tasks
-----------
assemble - Assembles the outputs of this project.
build - Assembles and tests this project.
buildDependents - Assembles and tests this project and all projects that depend on it.
buildNeeded - Assembles and tests this project and all projects it depends on.
classes - Assembles main classes.
clean - Deletes the build directory.
demoServerClasses - Assembles demo server classes.
demoServerJar - Assembles a jar archive containing the classes of the 'demoServer' feature.
jar - Assembles a jar archive containing the classes of the 'main' feature.
javadocJar - Assembles a jar archive containing the main javadoc.
sourcesJar - Assembles a jar archive containing the main sources.
testClasses - Assembles test classes.
testFixturesClasses - Assembles test fixtures classes.
testFixturesJar - Assembles a jar archive containing the classes of the 'testFixtures' feature.
whiteboxClasses - Assembles whitebox classes.

Build Setup tasks
-----------------
init - Initializes a new Gradle build.
updateDaemonJvm - Generates or updates the Gradle Daemon JVM criteria.
wrapper - Generates Gradle wrapper files.

Dependency-analysis tasks
-------------------------
abiAnalysisDemoServer - Produces a report of the ABI of this project
abiAnalysisMain - Produces a report of the ABI of this project
abiAnalysisTestFixtures - Produces a report of the ABI of this project
buildHealth - Generates holistic advice for whole project, and can fail the build if desired
computeDominatorTreeCompileDemoServer - Computes a dominator view of the dependency graph
computeDominatorTreeCompileMain - Computes a dominator view of the dependency graph
computeDominatorTreeCompileTest - Computes a dominator view of the dependency graph
computeDominatorTreeCompileTestFixtures - Computes a dominator view of the dependency graph
computeDominatorTreeCompileWhitebox - Computes a dominator view of the dependency graph
computeDominatorTreeRuntimeDemoServer - Computes a dominator view of the dependency graph
computeDominatorTreeRuntimeMain - Computes a dominator view of the dependency graph
computeDominatorTreeRuntimeTest - Computes a dominator view of the dependency graph
computeDominatorTreeRuntimeTestFixtures - Computes a dominator view of the dependency graph
computeDominatorTreeRuntimeWhitebox - Computes a dominator view of the dependency graph
computeDuplicateDependencies - Computes 'duplicate' external dependencies across entire build.
computeResolvedDependencies - Computes resolved external dependencies for all variants.
fixDependencies - Rewrite build script for this project to match dependency advice
generateProjectGraphDemoServer - Generates a graph view of this project's local dependency graph
generateProjectGraphMain - Generates a graph view of this project's local dependency graph
generateProjectGraphTest - Generates a graph view of this project's local dependency graph
generateProjectGraphTestFixtures - Generates a graph view of this project's local dependency graph
generateProjectGraphWhitebox - Generates a graph view of this project's local dependency graph
printDominatorTreeCompileDemoServer - Prints a dominator view of the dependency graph
printDominatorTreeCompileMain - Prints a dominator view of the dependency graph
printDominatorTreeCompileTest - Prints a dominator view of the dependency graph
printDominatorTreeCompileTestFixtures - Prints a dominator view of the dependency graph
printDominatorTreeCompileWhitebox - Prints a dominator view of the dependency graph
printDominatorTreeRuntimeDemoServer - Prints a dominator view of the dependency graph
printDominatorTreeRuntimeMain - Prints a dominator view of the dependency graph
printDominatorTreeRuntimeTest - Prints a dominator view of the dependency graph
printDominatorTreeRuntimeTestFixtures - Prints a dominator view of the dependency graph
printDominatorTreeRuntimeWhitebox - Prints a dominator view of the dependency graph
printDuplicateDependencies - Prints report of dependencies that have multiple versions across the build.
projectHealth - Prints advice for this project
reason - Explain how a dependency is used

Documentation tasks
-------------------
demoServerJavadoc - Generates Javadoc API documentation for the 'demoServer' feature.
javadoc - Generates Javadoc API documentation for the 'main' feature.
testFixturesJavadoc - Generates Javadoc API documentation for the 'testFixtures' feature.

Gradle Enterprise tasks
-----------------------
buildScanPublishPrevious - Publishes the data captured by the last build.
provisionGradleEnterpriseAccessKey - Provisions a new access key for this build environment.

Help tasks
----------
buildEnvironment - Displays all buildscript dependencies declared in root project 'spring-app-commons'.
dependencies - Displays all dependencies declared in root project 'spring-app-commons'.
dependencyInsight - Displays the insight into a specific dependency in root project 'spring-app-commons'.
help - Displays a help message.
javaToolchains - Displays the detected java toolchains.
kotlinDslAccessorsReport - Prints the Kotlin code for accessing the currently available project extensions and conventions.
outgoingVariants - Displays the outgoing variants of root project 'spring-app-commons'.
projects - Displays the sub-projects of root project 'spring-app-commons'.
properties - Displays the properties of root project 'spring-app-commons'.
resolvableConfigurations - Displays the configurations that can be resolved in root project 'spring-app-commons'.
tasks - Displays the tasks runnable from root project 'spring-app-commons' (some of the displayed tasks may belong to subprojects).

Publishing tasks
----------------
generateMetadataFileForMavenPublication - Generates the Gradle metadata file for publication 'maven'.
generatePomFileForMavenPublication - Generates the Maven POM file for publication 'maven'.
publish - Publishes all publications produced by this project.
publishAllPublicationsToGhRepository - Publishes all Maven publications produced by this project to the gh repository.
publishMavenPublicationToGhRepository - Publishes Maven publication 'maven' to Maven repository 'gh'.
publishMavenPublicationToMavenLocal - Publishes Maven publication 'maven' to the local Maven repository.
publishToMavenLocal - Publishes all Maven publications produced by this project to the local Maven cache.

Verification tasks
------------------
check - Runs all checks.
jacocoTestCoverageVerification - Verifies code coverage metrics based on specified rules for the test task.
jacocoTestReport - Generates code coverage report for the test task.
spotbugsDemoServer - Run SpotBugs analysis for the source set 'demoServer'
spotbugsMain - Run SpotBugs analysis for the source set 'main'
spotbugsTest - Run SpotBugs analysis for the source set 'test'
spotbugsTestFixtures - Run SpotBugs analysis for the source set 'testFixtures'
spotbugsWhitebox - Run SpotBugs analysis for the source set 'whitebox'
spotlessApply - Applies code formatting steps to sourcecode in-place.
spotlessCheck - Checks that sourcecode satisfies formatting steps.
spotlessDiagnose
spotlessJava
spotlessJavaApply
spotlessJavaCheck
spotlessJavaDiagnose
spotlessKotlinGradle
spotlessKotlinGradleApply
spotlessKotlinGradleCheck
spotlessKotlinGradleDiagnose
test - Runs the test suite.
whitebox - Runs the whitebox suite.

Rules
-----
Pattern: clean<TaskName>: Cleans the output files of a task.
Pattern: build<ConfigurationName>: Assembles the artifacts of a configuration.

To see all tasks and more detail, run gradlew tasks --all

To see more detail about a task, run gradlew help --task <task>

BUILD SUCCESSFUL in 681ms
1 actionable task: 1 executed
Configuration cache entry reused.
v
Are you sure you applied the plugin to the root project and have test suites on the root project?
c
I do not have test suites on the root project
why would I have any there? it's a root project
v
Because not everyone shares your opinion on what should or should not be in a root project
My root projects usually have content
c
they should, my rule is law 😉
v
Then you do not get any reports configured automatically as they are only configured for test suites present on the project where you apply the plugin as documented
But you can configure the reports manually as documented without adding test suites
c
right, the docs say
Copy code
reporting {
    reports {
        val testCodeCoverageReport by creating(JacocoCoverageReport::class) { 
            testType = TestSuiteType.UNIT_TEST
        }
    }
}
which won't work because not all test types are UNIT_TEST
and I need to aggregate all the jvm test suites inside the project
so I can get one verification for the suites in that project
v
I think I already explained lengthy, that this is not supported by the plugin out of the box. Out of the box it only supports aggregation over multiple projects for one test type. And if you want to do it across types, you need to put in some effort with extra configuration which I think I also already described in detail previously.
c
I remember fighting through a bunch of stuff and you said I should go back to doing this
these docs are pretty sparse
v
The docs are not telling how to aggregate over mutliple types at all, because again, this is not a use-case supported by the plugin out-of-the-box. You just can make it behave like that with some configuration which I did myself in the past successfully.
c
so, you're saying you don't know how to do it
v
I said I did it before. How would I have done it before if I don't know how. And I also described previously how to do it.
You just like always ignore half the things I'm saying
c
more like I don't understand half the things you're saying
v
That's not a valid reason to ignore them 😜
c
I think it's also possible that you respond sometimes multiple times and I move on to the last part because you seem to be superseding yourself, like this https://gradle-community.slack.com/archives/CAHSN3LDN/p1723575290625169?thread_ts=1723493005.019139&amp;cid=CAHSN3LDN I then paste some stuff trying to do that, and don't seem to be able to get it to work
looking back though, before you said this https://gradle-community.slack.com/archives/CAHSN3LDN/p1723575067334259?thread_ts=1723493005.019139&amp;cid=CAHSN3LDN best guess I never tried it because I tried the 2nd way that you said was better
also, so far there's no explanation for the aggregate thing that I saw other than "I did it before" (paraphrase)
it seems that the answer that you superseded actually works
I don't see where you responded to why this (which I think is exactly what you told me to do) didn't work https://gradle-community.slack.com/archives/CAHSN3LDN/p1723577463910209?thread_ts=1723493005.019139&amp;cid=CAHSN3LDN
v
I then paste some stuff trying to do that,
That was exclusively for aggregating within one project and without the aggregation plugin
because I tried the 2nd way that you said was better
Same here, you said you only want to aggregate within one project, not across multiple projects
I don't see where you responded to why this didn't work
Well, you also seemed to have superseded yourself with the next messages iirc. And also, I'm not your interactive debugging service or personal AI. I can only guide you but you have to put effort in it yourself or debug problems you might hit, especially as I don't have your project at hand to look myself, besides that I have not time for that.
also, so far there's no explanation for the aggregate thing that I saw other than "I did it before" (paraphrase)
Not in this thread, that's correct, because you clearly stated:
yeah, I don't (currently) need/want to do multi-project tasks
And for that use-case it is not necessary to do it. I did not say I explained it in this thread, I just said I explained it before. To someone else, so you could search for that conversation. But as a quick recap you need to: • define a consumable configuration on all projects like the aggregation plugin does it for each test suite, with ◦ category attribute set to verification, ◦ verification type attribute set to jacoco results and ◦ test suite type attribute set to
"all"
• react to the
jvm-test-suite
plugin being applied `configureEach`ing all
JvmTestSuite
suites, adding test test tasks jacoco destination file with type attribute set to binary data type as outgoing artifact to the configuration added above like the aggregation plugin does it for the specific test suite types • define a
JacocoCoverageReport
report with test type
"all"
to the project where you want to have the aggregate task • add the projects that should be aggregated (or just all if that is what you want) as dependencies to the
jacocoAggregation
configuration on the project where you want to have the aggregation task
c
> Same here, you said you only want to aggregate within one project, not across multiple projects because I did, and do > I can only guide you but you have to put effort in it yourself or debug problems you might hit, especially as I don't have your project at hand to look myself, besides that I have not time for that. I was, and you could have, it's publicly available. I'm sure I've linked it before but probably didn't think to again. > And also, I'm not your interactive debugging service or personal AI. I want you to know I absolutely try not to ask questions on here, and I always hope for pointers to good docs. Having a solution for my problem I could try to update some docs, but I'm not 100% certain I understand the solution which is usually the problem. In this case one part of the solution I don't understand, which I might go google, is the kotlin ::something, although I assume that's a method reference. Still I feel like the best I can do for other people is to simply put this answer in something more indexed on google than slack, and open yet another ignored ticket on gradle. You on the otherhand understand the answer and have created successful PRs so could probably easily update the documentation for both plugins so next time someone asks. I always prefer answers as documentation, even if I don't always get it.