Dependency Resolution changes local project dependeny to module dependency

Let us consider this setup:

{ gradletest }  » tree .                                                                                                                                                      ~/gradletest
.
├── build.gradle
├── project-a
│   └── build.gradle
├── project-b
│   └── build.gradle
└── settings.gradle

Parent Project: (in folder gradletest)

build.gradle

allprojects {
   apply plugin: java
}

settings.gradle

include ":project-a"
include ":project-b"

project-a:

build.gradle

dependencies {
    compile project (":project-b")
}

configurations {
    compile.resolutionStrategy {
        eachDependency { DependencyResolveDetails details ->
            if (details.requested.group == 'gradletest') {
                println "Changing version of " + details.requested..toString() + " to 1.4"
                details.useVersion '1.4'
            }
        }
    }
}

The build.gradle of project-b is empty.

Now if you call gradle :project-a:dependencies you can see that the project dependency on :project-b is being substituted with a module dependency.

{ gradletest }  » gradle :project-a:dependencies                                                                                                                              ~/gradletest
:project-a:dependencies

------------------------------------------------------------
Project :project-a
------------------------------------------------------------

archives - Configuration for archive artifacts.
No dependencies

compile - Dependencies for source set 'main'.
Changing version of gradletest:project-b:unspecified to 1.4
\--- project :project-b -> gradletest:project-b:1.4 FAILED

Shouldn’t the resolution strategy not be triggered for project dependencies at all? Or is this the expected behaviour?

This test was run with Gradle-2.13.

It looks like you’re trying to swap a local project dependency to a module dependency looked up from a repository… correct? See here for how to do that

eg:

configurations.all {
    resolutionStrategy.dependencySubstitution {
        substitute project(":project-b") with module("gradletest:project-b:1.4")
    }
}

No, that is exactly what I don’t want.

I’ll explain a little further:

In our current setup we are using dependency resolution to change the versions of incoming dependencies to our company requirements. But we are also using dependency substitution on transitive dependencies to change them to project dependencies if the corresponding project can be found locally.

This means that if a project defines regular project dependencies like compile project(":project-b"), we do not want our dependency resolution to change or overdefine that dependency because it is a project dependency.

That is why I am posting here. Because it really surprised me that project dependencies are even considered during dependency resolution. When doing dependency substitution you can check if the incoming dependency is of type ModuleComponentSelector and not of type ProjectComponentSelector. You cannot do that when using dependency resolution.

Our current solution is to check if an incoming dependency has a local project. If yes, then we skip the version resolution process for that dependency.

You might be interested in the composite build support feature added in 2.13

Or it could be solved with something like:

configurations.all.resolutionStrategy.dependencySubstitution {
  all { DependencySubstitution dependency ->
    ComponentSelector selector = dependency.requested
    if (selector instanceof ModuleComponentSelector && selector.group == 'gradletest') {
      substitute selector with project(":${selector.module}")
    }
  }

More info here