spring-gradle-plugins / dependency-management-plugin

A Gradle plugin that provides Maven-like dependency management functionality
684 stars 85 forks source link

Unexpected dynamic dependency version resolution #268

Open GFriedrich opened 4 years ago

GFriedrich commented 4 years ago

I'm struggeling with the solution that was implemented for #155 This issue resulted in a compatibility fix for the Versions plugin, to resolve the dynamic version instead of the one from dependency management, so that the plugin still works properly. Even though the plugin works fine now, it breaks the dependency resolution quite badly for me. Let me give an example:

Imagine to have a project which has a dependency to A and B. A in turn also has a dependency to B (but you as project owner do not know about this - this is why you've added B directly to your project). A includes B via a dynamic version. Finally you've used the dependency managment for B in your project to use a specific version.

Normally you would expect now to get the very specific version of B that you've described via the dependency management. Unfortunately the workaround for the Versions plugin kicks in and expects that the dynamic version and the direct dependency being used at the same spot (even though they are NOT) resulting in a deactivation of the dependency management. Even more intransparent to the user: Removing the dependency to B from the project results in the expected dependency tree (as B is no longer a direct dependency).

Sadly I don't have a clue how to fix this, so that both "Versions plugin" and "dependency management" work properly. But from my point of view the dependency managment of the builds is more important than the compatibility to a plugin. Maybe it's somehow possible to add an "option" to enable the behaviour that is currently enabled by default and which then can be set via "doFirst" before executing the task of the Versions plugin.

What do you think?

wilkinsona commented 4 years ago

Can you please create and share a small sample build that reproduces the behaviour that you have described?

GFriedrich commented 4 years ago

@wilkinsona: Please see the attached project and switch between directly using and not using the "selenium-java" dependency. resolution-issue.zip

GFriedrich commented 4 years ago

@wilkinsona: Any update on this? Would it be ok to introduce some sort of option to opt-in/opt-out? If we decide on a solution I would try to tackle it.

wilkinsona commented 4 years ago

Thanks for the sample project. I've reproduced the problem.

Without the direct dependency:

> Task :dependencyInsight
org.seleniumhq.selenium:selenium-java:3.14.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
   ]

org.seleniumhq.selenium:selenium-java:3.12.0 -> 3.14.0
\--- io.appium:java-client:6.1.0
     \--- com.applitools:eyes-selenium-java3:3.160.0 (requested io.appium:java-client:[5.0.1, 7.0])
          \--- compileClasspath (requested com.applitools:eyes-selenium-java3)

org.seleniumhq.selenium:selenium-java:[3.141.0, 3.141.59] -> 3.14.0
\--- com.applitools:eyes-selenium-java3:3.160.0
     \--- compileClasspath (requested com.applitools:eyes-selenium-java3)

With the direct dependency:

> Task :dependencyInsight
org.seleniumhq.selenium:selenium-java:3.141.59
   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:
      - Selected by rule
      - Was requested : didn't match versions 4.0.0-alpha-4, 4.0.0-alpha-3, 4.0.0-alpha-2, 4.0.0-alpha-1
      - By conflict resolution : between versions 3.14.0 and 3.141.59

org.seleniumhq.selenium:selenium-java -> 3.141.59
\--- compileClasspath

org.seleniumhq.selenium:selenium-java:3.12.0 -> 3.141.59
\--- io.appium:java-client:6.1.0
     \--- com.applitools:eyes-selenium-java3:3.160.0 (requested io.appium:java-client:[5.0.1, 7.0])
          \--- compileClasspath (requested com.applitools:eyes-selenium-java3)

org.seleniumhq.selenium:selenium-java:[3.141.0, 3.141.59] -> 3.141.59
\--- com.applitools:eyes-selenium-java3:3.160.0
     \--- compileClasspath (requested com.applitools:eyes-selenium-java3)

I'm not yet sure how to fix it. It may be possible to distinguish between dynamic versions that are transitive and that are declared directly.

GFriedrich commented 4 years ago

@wilkinsona: I've thought about that too, but unfortunately came to the conclusion that you miss the information whether it is a transitive dependency or not at the code where the decision takes place. So I don't have a clue how to achieve that ... :disappointed:

wilkinsona commented 4 years ago

Digging a bit more, the fix for https://github.com/spring-gradle-plugins/dependency-management-plugin/issues/151 didn't introduce the problem.

In #77 (0.6.0) any dependency with a dynamic version was ignored completely. In #151 (1.0.1) that was refined so that only direct dependencies with dynamic versions were ignored. The sample fails in the same way with 1.0.1 of the plugin as it does with 1.0.9.

The problem that we have now is that the dependency is declared both directly and transitively and distinguishing between the two is problematic.

wilkinsona commented 4 years ago

I think I can further refine the fixes for #77 and #151 so that the problem described here doesn't occur. With that change in place, all the existing tests pass other than the test that verifies compatibility with the versions plugin. I believe a further refinement that would also work with the Versions plugin is possible, but it requires Gradle 5.1 or later.

That leaves three options:

  1. Accept the problem described in this issue as a known limitation
  2. Fix the problem now and break compatibility with the Versions plugin
  3. Raise the supported version of Gradle to 5.1 and fix the problem then

I know from issues that have been raised in the past that option 2 will cause a problem for existing users. Option 1 is a bit of a cop-out so that leaves option 3.

A change in the minimum supported version of Gradle is long over due with the plugin currently supporting Gradle 2.9 and later and the current latest version of Gradle being 6.2. Spring Boot 2.3 milestones have raised the minimum supported version of Gradle to 5.6.x. A new version of this plugin with a similar requirement increasingly makes sense at this point.

GFriedrich commented 4 years ago

Requiring Gradle 5.1 or later would be fine for me (I'm currently on Gradle 5.6). So if you think you can go with a fix when updating the version, I'm looking forward to a new release. 😃

GFriedrich commented 4 years ago

@wilkinsona: About one month later is there any update on this? Do you require a helping hand? Shall I do the update to Gradle 5.6 / Java 8? Just drop me a line in case you want me to do something...

wilkinsona commented 4 years ago

Thanks for the offer, but updating to Gradle 5.6 will require a significant review and probably rewrite of large chunks of the plugin. As such, it would require as much if not more effort to review a pull request as it would to make the changes. I don't have an estimate for when I might be able to do that work at the moment as there are other, higher priority, things to be getting on with.