Closed SayakMukhopadhyay closed 1 year ago
Thanks for the sample and detailed description of the problem. The cause appears to be related to ordering. If the dependency substitution is configured after the dependency management plugin has been applied, the problem does not occur. This is why it worked when you configured the substitution in the child project. It will also work if you configure it in the root project and react to the dependency management plugin being applied:
allprojects {
plugins.withId('io.spring.dependency-management') {
configurations.all {
resolutionStrategy {
dependencySubstitution {
substitute module('joda-time:joda-time') with project(':library')
}
}
}
}
}
I'm not sure what, if anything, the dependency management plugin can do about the problem. It'll require some further investigation.
It would appear that Gradle loses the dependency substitution when another resolution strategy configures a version. For example, the following modified consumer project shows the same problem:
plugins {
id 'java'
}
group = 'com.example'
version = '1.0.0'
sourceCompatibility = 11
repositories {
mavenCentral()
}
dependencies {
implementation 'joda-time:joda-time:2.12.0'
}
configurations.all {
resolutionStrategy {
eachDependency {
it.useVersion('2.12.0')
}
}
}
The dependency management plugin does the equivalent of this itself so that a version that's specified in a dependency declaration overrides the version from any dependency management that has been configured. You can disable this behavior:
dependencyManagement {
overriddenByDependencies = false
}
The problem does not occur with this in place. I don't think there's anything more that can be done in the dependency management plugin. Ideally, Gradle would not lose the dependency substitution when another resolution strategy configures a version but that is out of the dependency management plugin's control. If none of the approaches above are suitable, you may want to raise a Gradle issue to see what can be done.
Thank you for the detailed explanation. This would be helpful while discussing with the Gradle folks.
EDIT: I have raised an issue at https://github.com/gradle/gradle/issues/23509
I have a multi-project layout which uses git submodules such that developers can checkout the sub projects as standalone git repos and work on them. For eg. I have
Parent
gradle project which hasChild1
andChild2
as sub projects.Let me discuss the reasoning for that so that the context is laid out.
If
Child1
depends onChild2
as a library, I have theChild2
dependency added inChild1
as a maven repo (implementation com.example:child2:1.0.0
) so that a developer checking out onlyChild1
doesn't have broken dependencies. At the same time, I want people checking outParent
to be able to use theChild2
dependency as a project (implementation project(:child2)
). To implement this, I use dependency substitution inParent
only like belowThe above substitution is not working when
Child1
has the dependency management plugin activeThe substitution happens as soon as the dependency management plugin is removed. The substitution also works if I use the substitution code in
Child1
itself likebut that's not something that I am looking to do here.
I am able to reproduce this consistently and have created a repo with a simple reproduction (here I am replacing
joda-time
with thelibrary
project in theconsumer
, both of which are present in thedep-sub-test
project, as I need an existing maven package to demonstrate`)To reproduce:
Pull the project as is and run
.\gradlew.bat :consumer:dependencies --configuration compileClasspath
to see the dependency tree. The output will haveComment out the lines
id 'io.spring.dependency-management' version '1.0.15.RELEASE'
andimplementation 'org.springframework.boot:spring-boot-starter-web'
and run the above command once again. The output will haveNOTE: the
org.springframework.boot:spring-boot-starter-web
dependency is only there to ensure that there is no corner case that is missed when the plugin is added but no spring dependencies are given.