Best Practice Resolving Version Conflicts within Thirdparty Libraries

Hello,

i just added grgit to my project and my build got broken

> Could not resolve all dependencies for configuration ':mach-build-tools:compileClasspath'.
   > A conflict was found between the following modules:
      - com.jcraft:jsch:0.1.54
      - com.jcraft:jsch:0.1.49

The dependency tree points out that the transitive dependencies of grgit cause the conflict

compileClasspath - Compile classpath for source set 'main'.
\--- org.ajoberstar:grgit:2.3.0
     +--- org.eclipse.jgit:org.eclipse.jgit:4.11.0.201803080745-r
     |    +--- com.jcraft:jsch:0.1.54
     |    +--- com.jcraft:jzlib:1.1.1
     |    +--- com.googlecode.javaewah:JavaEWAH:1.1.6
     |    +--- org.apache.httpcomponents:httpclient:4.5.2
     |    |    +--- org.apache.httpcomponents:httpcore:4.4.4
     |    |    +--- commons-logging:commons-logging:1.2
     |    |    \--- commons-codec:commons-codec:1.9
     |    \--- org.slf4j:slf4j-api:1.7.2
     +--- org.eclipse.jgit:org.eclipse.jgit.ui:4.11.0.201803080745-r
     |    \--- org.eclipse.jgit:org.eclipse.jgit:4.11.0.201803080745-r (*)
     +--- com.jcraft:jsch.agentproxy.core:0.0.9
     +--- com.jcraft:jsch.agentproxy.jsch:0.0.9
     |    +--- com.jcraft:jsch:0.1.49 -> 0.1.54
     |    \--- com.jcraft:jsch.agentproxy.core:0.0.9
     +--- com.jcraft:jsch.agentproxy.pageant:0.0.9
     |    +--- com.jcraft:jsch.agentproxy.core:0.0.9
     |    +--- net.java.dev.jna:jna:4.1.0
     |    \--- net.java.dev.jna:jna-platform:4.1.0
     |         \--- net.java.dev.jna:jna:4.1.0
     +--- com.jcraft:jsch.agentproxy.sshagent:0.0.9
     |    \--- com.jcraft:jsch.agentproxy.core:0.0.9
     +--- com.jcraft:jsch.agentproxy.usocket-jna:0.0.9
     |    +--- com.jcraft:jsch.agentproxy.core:0.0.9
     |    +--- net.java.dev.jna:jna:4.1.0
     |    \--- net.java.dev.jna:jna-platform:4.1.0 (*)
     +--- com.jcraft:jsch.agentproxy.usocket-nc:0.0.9
     |    \--- com.jcraft:jsch.agentproxy.core:0.0.9
     \--- com.jcraft:jsch:0.1.54

Is there any better approach than excluding group and module of the conflicting library and then explicitly adding the dependeny:

implementation ('org.ajoberstar:grgit:2.3.0'){
    exclude group: 'com.jcraft', module: 'jsch'
}
implementation 'com.jcraft:jsch:0.1.54'

I also tried the following but it didnt do the trick

implementation ('org.ajoberstar:grgit:2.3.0')
constraints {
	implementation('com.jcraft:jsch:0.1.54'){
		because 'Grgit contains transitive conflict'
	}
}

Obviously, I misunderstand the concept :-/

By default, gradle will silently pick the latest version if it encounters more than one version of a dependency. Your error suggests you have the following in your build

configurations.all {
  resolutionStrategy {
    failOnVersionConflict()
 } 
} 

So now the build fails instead of picking the latest.

I’d suggest one of the following:

  1. Remove failOnVersionConflict()
  2. Force a particular version
configurations.all {
    resolutionStrategy { 
        force 'com.jcraft:jsch:0.1.54'
    }
}

https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html

We have a large code base and use many, many libraries. Thus, we need full control of the transitive libraries and disable failOnVersionConflict is not an option. In fact, it is a very valuable feature of gradle.

Additionally, using force as resolution strategie will cause that gradle will not give us any note when we include another library which brings jsch in a newer version. I would like to get this notification such that we can analyse the differences (and potential side effects) and explicitly decide which version suits best for us.
(I hope I expressed my intention correctly :slight_smile: ).

I guess my first attempt is still the only one which covers our need.

A perfect solution for my problem would be something like this

implementation ('org.ajoberstar:grgit:2.3.0'){
    force version '0.1.54' for 'com.jcraft:jsch' in all transitive libraries of grgit 
}

Thanks for the efforts,
stdoubleu

You might be interested in this code where all the version choices are available in a collection per groupId/artifactId. The sample code uses a custom comparator to select the best version, you could tweak the logic to do whatever you like