autonomousapps / dependency-analysis-gradle-plugin

Gradle plugin for JVM projects written in Java, Kotlin, Groovy, or Scala; and Android projects written in Java or Kotlin. Provides advice for managing dependencies and other applied plugins
Apache License 2.0
1.67k stars 115 forks source link

Transitive Dependencies Version Mismatches on Compile Classpath #1095

Closed NoPhaseNoKill closed 5 months ago

NoPhaseNoKill commented 6 months ago

Just wanted to give a quick thanks for the plugin - absolutely love the work.

Please note: Excuse my ignorance (as I've only just started delving into the space), so feel free to correct any wrong/bad assumptions I've made here. Leaving these transitive deps may cause problems in the future, unless you plan/do test every single piece of code is which ties to functionality related to mismatching transitive deps (so you know when it will/won't break). Fixing these instead, particularly when you're using a bom (which I assumed was the reason you chose it), will reduce heartache and strange issues in the future (or ones that may exist that you're not aware of).

Build scan link https://scans.gradle.com/s/5hafl5qsusuoq/dependencies?toggled=W1swXSxbMCw0XSxbMCwzXSxbMCwxXSxbMCwxLFs5XV0sWzAsMSxbOSw1Nl1dLFswLDEsWzksNTYsNjJdXSxbMCwxLFs5LDU2LDYyLDQ4XV0sWzAsMSxbOSw1Niw2Miw0N11dLFswLDEsWzksNTYsNjIsNDcsNDldXSxbMV1d

Plugin version 1.28.0

Gradle version 8.4

JDK version 17

(Optional) Kotlin and Kotlin Gradle Plugin (KGP) version 1.9.10

Describe the bug

  1. Project contains multiple conflicting transitive dependencies
  2. This may cause unexpected/hard to debug bugs where functionality that expects or relies on a particular version may break suddenly and you have no idea why
  3. This is being caused mainly my moshi (but there may be others), as you'd probably need to programmatically compare the expected classpath versus the actual ones to see the full difference

To Reproduce Steps to reproduce the behavior:

  1. Go to: https://github.com/NoPhaseNoKill/IntegraBoost/tree/9d3e726f22281e9b4e2920abea852bda935290f3/new/toolset/jvm
  2. Run ./gradlew :build-logic:plugins:dependencies

Expected behavior

  1. Considering you have a bom defined here of 1.9.10: https://github.com/autonomousapps/dependency-analysis-gradle-plugin/blob/412e26b235a0f479789741df56c3fe178b698f2a/gradle/libs.versions.toml#L29
  2. I would have expected that there would be no transitive dependency mismatches that need to be resolved for anything related to said bom - as you wanted a reliable set of dependencies working together
  3. However, because mochi uses a completely different version (super old one) - you most likely are going to have issues that already exist or will crop up in extremely subtle and hard to debug ways

Sample:

+--- com.autonomousapps:dependency-analysis-gradle-plugin -> 1.28.0
|    +--- com.google.guava:guava:31.1-jre
|    |    +--- com.google.guava:failureaccess:1.0.1
|    |    +--- com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
|    |    +--- com.google.code.findbugs:jsr305:3.0.2
|    |    +--- org.checkerframework:checker-qual:3.12.0
|    |    +--- com.google.errorprone:error_prone_annotations:2.11.0
|    |    \--- com.google.j2objc:j2objc-annotations:1.3
|    +--- javax.inject:javax.inject:1
|    +--- com.squareup.moshi:moshi:1.14.0
|    |    +--- com.squareup.okio:okio:2.10.0
|    |    |    +--- org.jetbrains.kotlin:kotlin-stdlib:1.4.20 -> 1.9.10 (*) <---------- huge mismatch version
|    |    |    \--- org.jetbrains.kotlin:kotlin-stdlib-common:1.4.20 -> 1.9.10 <---------- huge mismatch version
|    |    \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0 -> 1.9.10
|    |         +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.10 (*)
|    |         \--- org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.10
|    |              \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.10 (*)
|    \--- dev.zacsweers.moshix:moshi-sealed-runtime:0.19.0
|         +--- com.squareup.moshi:moshi-adapters:1.14.0
|         |    +--- com.squareup.moshi:moshi:1.14.0 (*)
|         |    \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0 -> 1.9.10 (*)
|         +--- com.squareup.moshi:moshi:1.14.0 (*)
|         \--- org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.20 -> 1.9.10 (*)

See attached transitive-deps.txt

edit: Add sample

autonomousapps commented 5 months ago

Thanks for filing the issue, but I'm not sure what you're asking me to do here.

NoPhaseNoKill commented 5 months ago

Sorry if this wasn't clear.

  1. To prevent long-term transitive dependency conflicts, explicitly select versions that are pulled in by transitive dependencies, by adding something like this to the root build.gradle.kts of the project:
    configurations.all {
    resolutionStrategy {
    failOnVersionConflict()
    }
    }
  2. This produces errors:
......

* What went wrong:
Could not determine the dependencies of task ':compileGroovy'.
> Could not resolve all dependencies for configuration ':compileClasspath'.
   > Conflicts found for the following modules:
       - org.jetbrains.kotlin:kotlin-stdlib between versions 1.9.20, 1.9.10 and 1.4.20
       - org.jetbrains.kotlin:kotlin-reflect between versions 1.9.20, 1.9.10 and 1.7.0
       - org.jetbrains.kotlin:kotlin-stdlib-jdk8 between versions 1.9.10, 1.7.0, 1.7.20 and 1.8.0
       - org.jetbrains.kotlin:kotlin-stdlib-jdk7 between versions 1.9.10 and 1.8.0
       - org.checkerframework:checker-qual between versions 3.21.4 and 3.12.0
       - com.google.errorprone:error_prone_annotations between versions 2.13.1 and 2.11.0
       - org.jetbrains.kotlin:kotlin-stdlib-common between versions 1.9.20, 1.9.10 and 1.4.20
  1. Fix said errors

Please note: This is merely one option you have. Other details can be found here:

https://docs.gradle.org/current/userguide/dependency_capability_conflict.html https://docs.gradle.org/current/javadoc/org/gradle/api/artifacts/ResolutionStrategy.html#capabilitiesResolution

NoPhaseNoKill commented 5 months ago

After further investigation, it turned out that the original issue was what I'll call a 'skill gap' haha.

Your library doesn't introduce transitive dependencies on the classpath, this was due to the way I was implementing it. For future reference, see working example here: https://github.com/NoPhaseNoKill/monorepo/tree/08e26fda3751aa7f101fdb0af208f80475dc6fd5

Resulting output is:

> Task :modules:applications:app:dependencies

------------------------------------------------------------
Project ':modules:applications:app'
------------------------------------------------------------

annotationProcessor - Annotation processors and their dependencies for source set 'main'.
No dependencies

api - API dependencies for null/main (n)
No dependencies

apiDependenciesMetadata
No dependencies

apiElements - API elements for the 'main' feature. (n)
No dependencies

apiElements-published (n)
No dependencies

compileClasspath - Compile classpath for null/main.
+--- project :modules:libraries:utilities
|    +--- project :modules:libraries:list
|    |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
|    |         \--- org.jetbrains:annotations:13.0
|    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
+--- project :modules:libraries:list (*)
+--- org.apache.commons:commons-text:1.10.0
|    \--- org.apache.commons:commons-lang3:3.12.0
\--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)

compileOnly - Compile only dependencies for null/main. (n)
No dependencies

compileOnlyDependenciesMetadata
No dependencies

default - Configuration for default artifacts. (n)
No dependencies

implementation - Implementation only dependencies for null/main. (n)
+--- project utilities (n)
+--- project list (n)
+--- org.apache.commons:commons-text:1.10.0 (n)
\--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (n)

implementationDependenciesMetadata
+--- project :modules:libraries:utilities
|    +--- project :modules:libraries:list
|    |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
|    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
+--- project :modules:libraries:list (*)
+--- org.apache.commons:commons-text:1.10.0
|    \--- org.apache.commons:commons-lang3:3.12.0
\--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20

intransitiveDependenciesMetadata
No dependencies

kotlinBuildToolsApiClasspath
\--- org.jetbrains.kotlin:kotlin-build-tools-impl:1.9.20
     +--- org.jetbrains.kotlin:kotlin-build-tools-api:1.9.20
     +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
     |    \--- org.jetbrains:annotations:13.0
     +--- org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.20
     |    +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
     |    +--- org.jetbrains.kotlin:kotlin-script-runtime:1.9.20
     |    +--- org.jetbrains.kotlin:kotlin-reflect:1.6.10
     |    +--- org.jetbrains.kotlin:kotlin-daemon-embeddable:1.9.20
     |    \--- org.jetbrains.intellij.deps:trove4j:1.0.20200330
     \--- org.jetbrains.kotlin:kotlin-compiler-runner:1.9.20
          +--- org.jetbrains.kotlin:kotlin-build-common:1.9.20
          +--- org.jetbrains.kotlin:kotlin-daemon-client:1.9.20
          +--- org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.5.0
          \--- org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.20 (*)

kotlinCompilerClasspath
\--- org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.20
     +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
     |    \--- org.jetbrains:annotations:13.0
     +--- org.jetbrains.kotlin:kotlin-script-runtime:1.9.20
     +--- org.jetbrains.kotlin:kotlin-reflect:1.6.10
     +--- org.jetbrains.kotlin:kotlin-daemon-embeddable:1.9.20
     \--- org.jetbrains.intellij.deps:trove4j:1.0.20200330

kotlinCompilerPluginClasspath
No dependencies

kotlinCompilerPluginClasspathMain - Kotlin compiler plugins for compilation
\--- org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.9.20
     +--- org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.9.20
     |    +--- org.jetbrains.kotlin:kotlin-scripting-common:1.9.20
     |    |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
     |    |         \--- org.jetbrains:annotations:13.0
     |    +--- org.jetbrains.kotlin:kotlin-scripting-jvm:1.9.20
     |    |    +--- org.jetbrains.kotlin:kotlin-script-runtime:1.9.20
     |    |    +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
     |    |    \--- org.jetbrains.kotlin:kotlin-scripting-common:1.9.20 (*)
     |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
     \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)

kotlinCompilerPluginClasspathTest - Kotlin compiler plugins for compilation
\--- org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.9.20
     +--- org.jetbrains.kotlin:kotlin-scripting-compiler-impl-embeddable:1.9.20
     |    +--- org.jetbrains.kotlin:kotlin-scripting-common:1.9.20
     |    |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
     |    |         \--- org.jetbrains:annotations:13.0
     |    +--- org.jetbrains.kotlin:kotlin-scripting-jvm:1.9.20
     |    |    +--- org.jetbrains.kotlin:kotlin-script-runtime:1.9.20
     |    |    +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
     |    |    \--- org.jetbrains.kotlin:kotlin-scripting-common:1.9.20 (*)
     |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
     \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)

kotlinKlibCommonizerClasspath
\--- org.jetbrains.kotlin:kotlin-klib-commonizer-embeddable:1.9.20
     +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
     |    \--- org.jetbrains:annotations:13.0
     \--- org.jetbrains.kotlin:kotlin-compiler-embeddable:1.9.20
          +--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
          +--- org.jetbrains.kotlin:kotlin-script-runtime:1.9.20
          +--- org.jetbrains.kotlin:kotlin-reflect:1.6.10
          +--- org.jetbrains.kotlin:kotlin-daemon-embeddable:1.9.20
          \--- org.jetbrains.intellij.deps:trove4j:1.0.20200330

kotlinNativeCompilerPluginClasspath
No dependencies

kotlinScriptDef - Script filename extensions discovery classpath configuration
No dependencies

kotlinScriptDefExtensions
No dependencies

mainSourceElements - List of source directories contained in the Main SourceSet. (n)
No dependencies

runtimeClasspath - Runtime classpath of null/main.
+--- project :modules:libraries:utilities
|    +--- project :modules:libraries:list
|    |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
|    |         \--- org.jetbrains:annotations:13.0
|    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
+--- project :modules:libraries:list (*)
+--- org.apache.commons:commons-text:1.10.0
|    \--- org.apache.commons:commons-lang3:3.12.0
\--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)

runtimeElements - Runtime elements for the 'main' feature. (n)
No dependencies

runtimeElements-published (n)
No dependencies

runtimeOnly - Runtime only dependencies for null/main. (n)
No dependencies

testAnnotationProcessor - Annotation processors and their dependencies for source set 'test'.
No dependencies

testApi - API dependencies for null/test (n)
No dependencies

testApiDependenciesMetadata
No dependencies

testCompileClasspath - Compile classpath for null/test.
+--- project :modules:libraries:utilities
|    +--- project :modules:libraries:list
|    |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
|    |         \--- org.jetbrains:annotations:13.0
|    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
+--- project :modules:libraries:list (*)
+--- org.apache.commons:commons-text:1.10.0
|    \--- org.apache.commons:commons-lang3:3.12.0
+--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
\--- org.junit.jupiter:junit-jupiter-api:5.10.1
     +--- org.junit:junit-bom:5.10.1
     |    +--- org.junit.jupiter:junit-jupiter-api:5.10.1 (c)
     |    \--- org.junit.platform:junit-platform-commons:1.10.1 (c)
     +--- org.opentest4j:opentest4j:1.3.0
     +--- org.junit.platform:junit-platform-commons:1.10.1
     |    +--- org.junit:junit-bom:5.10.1 (*)
     |    \--- org.apiguardian:apiguardian-api:1.1.2
     \--- org.apiguardian:apiguardian-api:1.1.2

testCompileOnly - Compile only dependencies for null/test. (n)
No dependencies

testCompileOnlyDependenciesMetadata
No dependencies

testImplementation - Implementation only dependencies for null/test. (n)
\--- org.junit.jupiter:junit-jupiter-api:5.10.1 (n)

testImplementationDependenciesMetadata
+--- project :modules:libraries:utilities
|    +--- project :modules:libraries:list
|    |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
|    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
+--- project :modules:libraries:list (*)
+--- org.apache.commons:commons-text:1.10.0
|    \--- org.apache.commons:commons-lang3:3.12.0
+--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
\--- org.junit.jupiter:junit-jupiter-api:5.10.1
     +--- org.junit:junit-bom:5.10.1
     |    +--- org.junit.jupiter:junit-jupiter-api:5.10.1 (c)
     |    \--- org.junit.platform:junit-platform-commons:1.10.1 (c)
     +--- org.opentest4j:opentest4j:1.3.0
     +--- org.junit.platform:junit-platform-commons:1.10.1
     |    +--- org.junit:junit-bom:5.10.1 (*)
     |    \--- org.apiguardian:apiguardian-api:1.1.2
     \--- org.apiguardian:apiguardian-api:1.1.2

testIntransitiveDependenciesMetadata
No dependencies

testKotlinScriptDef - Script filename extensions discovery classpath configuration
No dependencies

testKotlinScriptDefExtensions
No dependencies

testRuntimeClasspath - Runtime classpath of null/test.
+--- project :modules:libraries:utilities
|    +--- project :modules:libraries:list
|    |    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20
|    |         \--- org.jetbrains:annotations:13.0
|    \--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
+--- project :modules:libraries:list (*)
+--- org.apache.commons:commons-text:1.10.0
|    \--- org.apache.commons:commons-lang3:3.12.0
+--- org.jetbrains.kotlin:kotlin-stdlib:1.9.20 (*)
+--- org.junit.jupiter:junit-jupiter-api:5.10.1
|    +--- org.junit:junit-bom:5.10.1
|    |    +--- org.junit.jupiter:junit-jupiter-api:5.10.1 (c)
|    |    +--- org.junit.jupiter:junit-jupiter-engine:5.10.1 (c)
|    |    +--- org.junit.platform:junit-platform-commons:1.10.1 (c)
|    |    \--- org.junit.platform:junit-platform-engine:1.10.1 (c)
|    +--- org.opentest4j:opentest4j:1.3.0
|    \--- org.junit.platform:junit-platform-commons:1.10.1
|         \--- org.junit:junit-bom:5.10.1 (*)
\--- org.junit.jupiter:junit-jupiter-engine -> 5.10.1
     +--- org.junit:junit-bom:5.10.1 (*)
     +--- org.junit.platform:junit-platform-engine:1.10.1
     |    +--- org.junit:junit-bom:5.10.1 (*)
     |    +--- org.opentest4j:opentest4j:1.3.0
     |    \--- org.junit.platform:junit-platform-commons:1.10.1 (*)
     \--- org.junit.jupiter:junit-jupiter-api:5.10.1 (*)

However, the secondary issue around transitive dependency conflicts for your library still exist. I'll leave this up to you decide whether you want to leave this open and put it in the backlog - or whether you don't care and are happy to run the risk of having multiple transitive dependency versions which may or may not conflict with each other.

Thanks once again for your time and effort surrounding the plugin. Apologies for the original issue being misleading.