Jacoco reprt agregation issue since 8.3

Hi

After an upgrade to 8.3 from 8.1, I have the following issue

> What went wrong:
> Could not determine the dependencies of task ':spring-boot-application:test'.
> Could not create task ':spring-boot-application:bootJar'.
> Cannot change artifacts of dependency configuration ':spring-boot-application:runtimeElements' after it has been included in dependency resolution.

My setup is :

If I remove

tasks.named('check') {
    dependsOn tasks.named('testCodeCoverageReport', JacocoReport)
}

the build is working

Update 1
There is something else, the issue is also fixed when I downgrade nebula maven publish to version < 20.3.0. (Comparing v20.2.0...v20.3.0 · nebula-plugins/nebula-publishing-plugin · GitHub)
I can’t explain for the moment

Update 2
I did my best to divide and remove all company work
From my shell :

gfc-Services$ ./gradlew clean check

[Incubating] Problems report is available at: file:///home/lagoueyte/dev/repos/gfc/gfc-Services/build/reports/problems/problems-report.html

FAILURE: Build failed with an exception.

  • What went wrong:
    Could not determine the dependencies of task ‘:spring-boot-application:test’.
    Could not create task ‘:spring-boot-application:bootJar’.
    Cannot change artifacts of dependency configuration ‘:spring-boot-application:runtimeElements’ after it has been included in dependency resolution.

I tried different approches to identify the culprit but didn’t find the real root cause.
Any ideas ?
thanks
gfc-Services.zip (1.8 MB)

Can you knit an MCVE that shows the problem?

We are entering two times in the SpringBootJarPlugin. 1) apiElement, 2) runtimeElements
The first time we add the artefact produced by bootJar
The second time we want to remove the artefact before re-adding it (a jar is already there)
Then I got the mutationGuard whose seems to throw an InvalidDataUserException.

do you confirm this scenario ?
I will try with another nvce

The SpringBootJarPlugin of the Nebula Publishing plugin tries to remove the artifact coming from the jar task and instead add the bootJar task artifact as artifact if the project also applies the Spring Boot plugin and the java plugin.

But something in the project causes the :spring-boot-application:runtimeElements configuration to already be resolved before this artifact manipulation is done.

If you remove the check → testCodeCoverageReport dependency, this resolving does not happen and so the error does not happen. But even then if you execute ./gradlew testCodeCoverageReport build the same error still happens even without the dependency, if you execute ./gradlew build testCodeCoverageReport, the error does not happen.

One point is, that you use the Spring Dependency Management plugin. This plugin is a relict from times when Gradle did not have built-in BOM support, by now does more harm than good, and even its maintainer recommends not to use it anymore, but instead the built-in BOM support using platform(...).

An additional problem is, that the SpringBootJarPlugin does this artifact manipulation task-configuration-avoidance-“safe” only when the bootJar task is configured and this is exactly the problem. With the Spring Dependency Management plugin replaced by built-in BOM support you still get the same error while Gradle is building the Task graph as then the task gets configured to get its dependencies, but when the bootJar task gets configured it changes the configuration of the apiElements and runtimeElements configurations which in your case were already involved in dependency resolution and thus are no longer mutable.

If you make sure the bootJar task gets configured early and thus break task-configuration avoidance for that task, by simply adding the line

bootJar

in your org.cocktail.gfc.application-spring-boot.gradle file, it gets configured in time and thus can do this bad configuration manipulation in-time before resolution started.

Actually to leverage task-configuration avoidance as far as possible it would make sense to only force the bootJar task configuration when really necessary, that is right before apiElements or runtimeElements take part in resolution configuration the first time using this:

configurations.apiElements {
    withDependencies {
        bootJar
    }
}
configurations.runtimeElements {
    withDependencies {
        bootJar
    }
}

Then it at least only gets configured if necessary.

thanks for the analysis and your insights

I will try to switch to Managing Dependencies :: Spring Boot soon
Can I keep my “custom plugin into build-logic” and replace

ext['oracle-database.version'] = '19.9.0.0'
dependencyManagement {
    imports {
        mavenBom(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
    }
}

by

dependencies {
	implementation platform(org.springframework.boot.gradle.plugin.SpringBootPlugin.BOM_COORDINATES)
}

?

I also tested your fix in my full build and works perfectly. I didn’t know about configurations.xxx.withDependencies

Thanks for your time

1 Like

Can I keep my “custom plugin into build-logic” and replace

Sure

I didn’t know about configurations.xxx.withDependencies

It usually is the last-call place to add something based on something else before dependency resolution starts for a configuration.
So for example checking whether the user added X and in that case also add Y.

1 Like