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

Allow direct dependencies to have no effect on transitive dependencies if they are not overriding dependency management #264

Closed
dorongold opened this issue Jan 4, 2020 · 2 comments

Comments

@dorongold
Copy link

dorongold commented Jan 4, 2020

Expected Behavior

In a project using the dependency-management-plugin, having ordinary non-managed dependencies, i.e. dependencies not imported from a BOM and not declared under dependencyManagement.dependencies, if there are conflicts between direct and transitive dependencies (same dependencies with different versions), Gradle's conflict resolution strategy should apply, meaning the highest version should win over.

Current Behavior

If my project has a direct dependency on another library while also having a transitive dependency on that same library but with another version, the version declared by the direct dependency always wins over.
Setting dependencyManagement.overriddenByDependencies = false works around this behavior, however it also disables overriding managed dependencies.

Steps to Reproduce

Create 3 separate projects: project-a, project-b and project-c

build.gradle for project-c:

plugins {
    id 'java'
    id 'maven'
}

repositories {
    mavenLocal()
}

group = 'com.dependency.example'

version = '1.0'
//version = '2.0'

Run gradle install once, then comment out version = '1.0', uncomment version = '2.0' and un gradle install again. This will result in 2 versions of project-c published to the local maven repository.

build.gradle for project-b:

plugins {
    id 'java'
    id 'maven'
}

repositories {
    mavenLocal()
}

group = 'com.dependency.example'
version = '1.0'

dependencies {
    compile 'com.dependency.example:project-c:2.0'
}

Run gradle install once to publish project-b (which depends on version 2.0 of project-c) to the local maven repository.

build.gradle of project-a:

plugins {
    id 'java'
    id "io.spring.dependency-management" version "1.0.8.RELEASE"
}

repositories {
    mavenLocal()
}

dependencies {
    compile 'com.dependency.example:project-b:1.0'
    compile 'com.dependency.example:project-c:1.0'
}

Run gradle dependencyInsight --dependency project-c.
The (unexpected) output:

> Task :dependencyInsight
com.dependency.example:project-c:1.0 (selected by rule)
   variant "compile" [
      org.gradle.status              = release (not requested)
      org.gradle.usage               = java-api
      org.gradle.libraryelements     = jar (compatible with: classes)
      org.gradle.category            = library (not requested)

      Requested attributes not found in the selected variant:
         org.gradle.dependency.bundling = external
         org.gradle.jvm.version         = 8
   ]

com.dependency.example:project-c:1.0
\--- compileClasspath

com.dependency.example:project-c:2.0 -> 1.0
\--- com.dependency.example:project-b:1.0
     \--- compileClasspath

The expected output (achieved by dependencyManagement.overriddenByDependencies = false or by completely disabling the plugin):

> Task :dependencyInsight
com.dependency.example:project-c:2.0
   variant "compile" [
      org.gradle.status              = release (not requested)
      org.gradle.usage               = java-api
      org.gradle.libraryelements     = jar (compatible with: classes)
      org.gradle.category            = library (not requested)

      Requested attributes not found in the selected variant:
         org.gradle.dependency.bundling = external
         org.gradle.jvm.version         = 8
   ]
   Selection reasons:
      - By conflict resolution : between versions 2.0 and 1.0

com.dependency.example:project-c:2.0
\--- com.dependency.example:project-b:1.0
     \--- compileClasspath

com.dependency.example:project-c:1.0 -> 2.0
\--- compileClasspath

To easily reproduce this issue, clone this repository which contains 3 projects as described above: https://github.com/dorongold/spring-dependency-management-plugin-issue-264

My Environment

Gradle 5.6.2

Build time:   2019-09-05 16:13:54 UTC
Revision:     55a5e53d855db8fc7b0e494412fc624051a8e781

Kotlin:       1.3.41
Groovy:       2.5.4
Ant:          Apache Ant(TM) version 1.9.14 compiled on March 12 2019
JVM:          1.8.0_201 (Oracle Corporation 25.201-b09)
OS:           Mac OS X 10.14.6 x86_64
@dorongold dorongold changed the title esolution rules are applied to non-managed dependencies Resolution rules are applied to non-managed dependencies Jan 4, 2020
@wilkinsona
Copy link
Contributor

The current behaviour matches what's documented behaviour:

You can also override the dependency management by declaring a dependency and configuring it with the desired version, as shown in the following example:

dependencies {
    compile("com.google.guava:guava:18.0")
}

This will cause any dependency (direct or transitive) on com.google.guava:guava:18.0 in the compile configuration to use version 18.0, overriding any dependency management that may exist. If you do not want a project’s dependencies to override its dependency management, this behavior can be disabled using overriddenByDependencies.

The key part is "overriding any dependency management that may exist". That is to say, there's no requirement for the dependency management to exist for the version on a dependency to affect the version of any transitive dependency on the same module. This aligns with Maven's behaviour and, therefore, with the plugin's goal of mimicking Maven's behaviour.

The behaviour that you'd like to see could possibly be offered as a configuration option by using an enum for overriddenByDependencies rather than a boolean (and perhaps with a different name for the property as well).

@wilkinsona wilkinsona changed the title Resolution rules are applied to non-managed dependencies Allow direct dependencies to have no effect on transitive dependencies if they are not overriding dependency management Jan 6, 2020
@wilkinsona
Copy link
Contributor

This will be addressed by #330. As part of the move to using constraints, the dependency management plugin will ignore versions on direct dependencies and allow Gradle's version conflict resolution to determine the desired version.

@wilkinsona wilkinsona closed this as not planned Won't fix, can't repro, duplicate, stale Jun 30, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants