I have a Gradle project (7.5) that I am working on. It has a bunch of dependencies and transitive dependencies and even transitive dependencies of transitive dependencies that are being blocked by my corporate Artifactory server. We have later versions of these dependencies available for use.
After doing some digging in the documentation I have figured that using a resolutionStrategy directive is what I want to use. I came up with the following:
configurations.all {
resolutionStrategy {
substitute module('org.mozilla:rhino:1.7R4') using module('org.mozilla:rhino:1.7.7')
substitute module('org.yaml:snakeyaml:1.30') using module('org.yaml:snakeyaml:1.33')
substitute module('com.google.javascript:closure-compiler-unshaded:v20210106') using module('com.google.javascript:closure-compiler-unshaded:v20200614')
//force 'org.mozilla:rhino:1.7.7'
//force 'org.yaml:snakeyaml:1.33'
//force 'com.google.javascript:closure-compiler-unshaded:v20200614'
//forcedModules = ['org.mozilla:rhino:1.7.7', 'org.yaml:snakeyaml:1.33', 'com.google.javascript:closure-compiler-unshaded:v20200614']
}
}
I tried both force (now commented out) and then substitute. Neither has any effect, the build still complains it cannot get the blocked dependencies.
Is there something I am missing that is allowing the proposed resolutionStrategy from being applied?
The answer I found was RTFM.
Still not sure why the resolutionStrategy was ignored, but I found I was successful with including the versions of the transitive dependency I wanted and then excluding them from the dependency as found here:
https://docs.gradle.org/current/userguide/dependency_constraints.html
my resolution looks a little like this:
runtimeOnly ( "com.bertramlabs.plugins:asset-pipeline-grails:3.4.6" )
constraints {
runtimeOnly('org.mozilla:rhino:1.7.7') {
because 'the designated version of this transitive dependency is blocked in Artifactory'
}
runtimeOnly('com.google.javascript:closure-compiler-unshaded:v20200614') {
because 'the designated version of this transitive dependency is blocked in Artifactory'
}
}
The single line on the top was replaced by the entire block above
Related
I am trying to use OSGI to allow me to use two different versions of a transitive dependency. The plan is that one version (the newer version) will be hidden away inside an OSGI bundle, the other will be on the runtime classpath as normal.
I have built the bundle jar using Gradle (with the Groovy DSL), but the problem is its associated runtime dependencies are wrong - it brings along the newer version, which is supposed to be hidden inside the bundle. This is still true when I do, in the build.gradle file:
compileOnly deps.diffx
runtimeOnly(deps.diffx) {
exclude group: 'com.propensive', module: 'magnolia_' + versions.scala_v
}
If I examine the dependencies with the Gradle dependencies task, it shows that magnolia is excluded from the runtimeOnly configuration, as expected - but is not excluded from the runtimeClasspath configuration.
If I then use ./gradlew dependencyInsight --dependency magnolia_2.12 --configuration runtime to try to find out where this dependency is coming from, it tells me that the newer version is coming from runtimeClasspath depending on diffx, and this is selected via conflict resolution. Well thanks - I already knew that. The question is, why is my exclusion not being applied to the derived configuration?
Basically I want to do the opposite of this question.
I also tried constraint versions, but they exhibited the same problem:
compileOnly deps.diffx
runtimeOnly(deps.diffx) {
constraints {
implementation('com.propensive:magnolia_' + versions.scala_v + ':0.10.0') {
because 'this version is required by our other dependencies'
}
}
}
From the Gradle documentation:
On the upside, Gradle’s exclude handling is, in contrast to Maven, taking the whole dependency graph into account. So if there are multiple dependencies on a library, excludes are only exercised if all dependencies agree on them. For example, if we add opencsv as another dependency to our project above, which also depends on commons-beanutils, commons-collection is no longer excluded as opencsv itself does not exclude it.
So instead, we can use a dependency resolve rule:
def magnoliaVersion = '0.10.0'
configurations.runtimeClasspath {
resolutionStrategy.eachDependency { DependencyResolveDetails details ->
if (details.requested.group == 'com.propensive' && details.requested.name.startsWith("magnolia_") && details.requested.version != magnoliaVersion) {
details.useVersion magnoliaVersion
details.because 'this version is required by our other dependencies'
}
}
}
and then change the dependency back to a simple, single implementation one:
implementation deps.diffx
Unfortunately, as the documentation notes, this resolve rule isn't published, so it has to be applied again in any dependent Gradle modules.
I am using the Spring Boot Gradle plugin and its dependency management to manage some of my own dependencies across project so I do not need to add an explicit version in the build.gradle.
dependencyManagement {
dependencies {
dependency "foo.bar:my-own-library:12.1"
}
}
The problem is that I need another version "11.9" beside the version "12.1" and that I wanted the plugin to pick the correct version based on a variable.
So I added a resolutioStrategy and some variables in ext:
dependencyManagement {
dependencies {
dependency "foo.bar:our-own-library:12.1"
}
resolutionStrategy {
eachDependency { details ->
//find available version based on src_compat
//set the new version to use via
details.useVersion(newVersion)
// details.target.version yields updated version
}
}
}
ext {
src_compat = 11
extra_versions = ["foo.bar:my-own-library" : ["11.9"]]
}
The target version is set correctly every time but than the old version (12.1) is used for every configuration.
The configurations have no other custom resolutionstrategy.
My assumption was the resolutionStrategy of the plugin is able to override every version when the dependency management of the plugin is used.
Is the resolutionStrategy able to override all versions or do I have to move it the 'normal' gradle configurations?
There's some information about this in the dependency management plugin's documentation.
The dependency management resolution strategy only applies to the plugin's internal configurations, such as those that it uses to resolve the Maven boms that you have imported. As you suspected, if you want the resolution strategy to apply to the resolution of your project's dependencies, you should move it to the normal Gradle configurations.
Is there a way to tell Gradle to exclude all dependencies of a particular dependency, that would be pulled from a given repository ?
Removing that repository from the repositories list would not work, because I need that repository for other dependencies. But for one particular group, I want to exclude all dependencies that would come from that repository.
Something like :
dependencies {
compile <my_first_package>
compile('my_second_package') {
exclude repository.name:thirdPartyRepository
}
}
Looking at the source code, there are only two possibilities how to exclude a dependency and that is to exclude by module or a group. You can also mark a dependency not to fetch its transitive dependencies:
compile('my_second_package') {
transitive = false
}
But that's all, there seems to be no way to remove dependencies based on repository. You can force versions using a ResolutionStrategy, maybe take a look if something there helps your use case.
As a workaround, maybe you can repackage the wrong dependency under a different name or version. Or you could use the transitive = false and simply add all the transitive dependencies that you actually want as declared dependencies.
I have the following entry in my gradle file
dependencies {
compile 'org.A:A:1.0'
}
which downloads 'org.B:B:1.0' because that's it's dependency.(not mentioned explicitly in gradle)
What I want to use in my project is A* and B* which are shadows(changed namespace) of A and B respectively.
Now, I have specified the dependency for A* as
dependencies{
compile file('libs/A*.jar')
}
But, this one still downloads 'org.B:B:1.0'
How do I wire the gradle to use file('libs/B*.jar')?
The first solution that comes to mind is to exclude the transitive dependency of compile 'org.A:A:1.0'
This works like this:
dependencies {
compile('org.A:A:1.0') {
exclude 'org.B:B:1.0'
}
}
Have a look at the Gradle User Guide for more details on that subject.
As mentioned in the comments, file dependencies can't have transitive dependencies. So A*.jar either has the contents of the B.jar rolled into it somehow, or you have B.jar on the build path somewhere else.
File dependencies are generally a tool of last resort, they do not participate in conflict resolution; you need a dependency repository like maven or ivy for that.
I have a library, which I call core, which is a dependency of another project, called Museum. In core's build.gradle, I am using gson-fire, which is specified as a dependency in the following manner:
repositories {
maven { url 'https://raw.github.com/julman99/mvn-repo/master'}
}
...
dependencies {
compile 'com.github.julman99:gson-fire:0.11.0'
}
This works fine - core is compiled. When I go to use it in my Museum project, though, I get the following:
A problem occurred configuring project ':Museum'.
> Could not resolve all dependencies for configuration ':Museum:_debugCompile'.
> Could not find com.github.julman99:gson-fire:0.11.0.
Searched in the following locations:
file:/Users/jwir3/.m2/repository/com/github/julman99/gson-fire/0.11.0/gson-fire-0.11.0.pom
file:/Users/jwir3/.m2/repository/com/github/julman99/gson-fire/0.11.0/gson-fire-0.11.0.jar
http://download.crashlytics.com/maven/com/github/julman99/gson-fire/0.11.0/gson-fire-0.11.0.pom
http://download.crashlytics.com/maven/com/github/julman99/gson-fire/0.11.0/gson-fire-0.11.0.jar
https://repo1.maven.org/maven2/com/github/julman99/gson-fire/0.11.0/gson-fire-0.11.0.pom
https://repo1.maven.org/maven2/com/github/julman99/gson-fire/0.11.0/gson-fire-0.11.0.jar
Required by:
museum:Museum:unspecified > com.jwir3.core:core:1.4.0-SNAPSHOT
The build.gradle of Museum looks like the following:
dependencies {
compile ('com.thisclicks.core:core:' + project.CORE_LIB_VERSION+ '+#aar') {
transitive = true
}
}
Presumably, this is because the core library is specified as transient = true in the build.gradle of Museum, but it doesn't have the correct location to search for the Maven repository of gson-fire. Is there a way to make these search locations transient as well as the dependencies themselves?
Not automatically, no. Transitive dependencies do not bring in repository information, only the artifacts themselves. If you want this to work you'll have to add the repositories { } block from the core project to the Museum project.
Additionally, adding transitive = true is unnecessary in this case. This is the default anyway, and as explained above, is unrelated to this particular issue.