Circular dependency when upgrading to Gradle 5 - gradle

Our project worked until I tried to upgrade to Gradle 5. There the first thing it complained was that / isn't a good character for multi-projects, e.g. bla/blub isn't valid, so we changed this to bla:blub (even though the error message said : also isn't valid). But now we apparently have a circular dependency which didn't exist before with Gradle 4:
Circular dependency between the following tasks:
:lap:server:classes
\--- :lap:server:compileJava
+--- :lap:server:compileKotlin
| \--- :lap:server:jar
| +--- :lap:server:classes (*)
| +--- :lap:server:compileKotlin (*)
| \--- :lap:server:inspectClassesForKotlinIC
| \--- :lap:server:classes (*)
\--- :lap:server:jar (*)
Why could this be?

The problem was indeed with the : notation in our settings.gradle. Now that I've changed all the nested projects to - the problem is resolved.
More concretely, before we had something like:
include 'common/server',
'someproject/server',
'someproject/common',
'someproject/search',
...
which worked with gradle 4.
Then in Gradle 5 I've changed it to
include 'common:server',
'someproject:server',
'someproject:common',
'someproject:search',
...
which caused the issue, presumably because someproject:common depended on common:server or something of the likes.
Now that I've changed it to
include 'common-server'
project(':common-server').projectDir = file('common/server')
include 'someproject-server'
project(':someproject-server').projectDir = file('someproject/server')
include 'someproject-common'
project(':someproject-common').projectDir = file('someproject/common')
everything works like a charm. By the way, the error with the circular dependency is also reproducible in Gradle 4, it's just that there we still had the / notation.

For those of you who stumble on this question.
see : https://github.com/gradle/gradle/issues/847
in a multi project setup, a duplicate "shortname" will throw in a monkey wrench:
from the url above:
myApp
- client
- common
- server
- common
Even though it should be 2 distinct entries, the duplicate (shortname) of "common" is the issue/bug.
I ended up doing this: (my code is different names of course) (but the idea is)
myApp
- client
- clientcommon
- server
- servercommon
to disambiguate.
The url has some other ideas.
What I saw in my code was, the built jars looked something like this:
common-1.0-SNAPSHOT.jar
So that was what clued me in to "ahhh, maybe I have ambiguous issue with the shortname". And finally found that github-gradle link.

Related

Downgrading transitive gradle dependancy

Lets say I have 3 dependencies A, B and C. A depends on C V1.0 while B depends on C V2.0. If A uses C V2.0 then it throws an error and if B uses C V1.0 it will also thrown an error. These are both obviously unwanted behaviors. So I want a dependency tree that looks like this.
A
+--- C:1.0
B
+--- C:2.0
However, when I try to implement this with gradle I get this
A
+--- C:1.0 -> 2.0
B
+--- C:2.0
which means C:1.0 is not being used anywhere despite A requesting that version. How can I get gradle to not override the 1.0 version of C that A needs to work?

Grade Force Version Not Work at Higher Level

I use below config to force using old version of library_common in project my_library
my_library
dependencies{
compile("library_A")
compile("library_B")
compile("library_common:old_version"){
force = true
}
}
Library_common is resolved to old_version, which match our expectation
dependency tree
+---library_A
| +---library_common: new_version -> old_version
+---library_B
| +---library_common: old_version
+---library_common: old_version
Another Project my_application then have dependencies on my_library and a non_related_lib
my_application
dependencies{
compile("my_library")
compile("non_related_lib"){transitive = false}
}
Library_common is somehow resolved to new_version which causes the conflicts in my_library.
dependency tree
+---my_library
| +---library_A
| | +---library_common: new_version
| \---library_B
| | +---library_common: old_version -> new_version
| \---library_common: old_version -> new_version
+---non_related_lib
I know I can force library_common version again in my_application, but it seems not right, as my_library should handle this conflict by itself.
It seems to me Gradle ignores force=true constraint declared in a direct dependency. Could somebody help explain if this is the way Gradle works?
Also, another thought is to exclude library_common in library_A and library_B. Will need to test it. But this way may become complicated when library_common is included as a transitive dependency of library_A/B, and nested level is deep.
Could someone provide any suggestions on the best practice to downgrade a dependency in a library project?
Thank you!!
If you want to force an older version of a transitive dependency, you should use dependency constraints. If your libraries are all published using Gradle, the constraints are also packaged within the Gradle module metadata, which means they will be preserved whenever you add your libraries as dependencies to some other project.
This all means, your buildscript has to change to something like this:
// my_library
dependencies{
compile("library_A") // do not specify a version of library_A here
constraints {
compile("library_A:version") // specify a version of library_A here
compile("library_common") { // do not specify a version of library_common here
version {
strictly(old_version) // specify a version of library_common here
}
}
}
compile("library_B")
}

gradle dependency what does (c) and (n) mean?

extremely close to this SO post, and asked in comments, but left unclear there.
$ git clone https://github.com/k9mail/k-9.git
$ cd k-9/mail/protocols/smtp
$ ../../../gradlew dependencies | grep "4.7.1 (\*)\|4.7.1 (c)\|4.7.1 (n)" | sort -u
+--- com.jakewharton.timber:timber:4.7.1 (*)
+--- com.jakewharton.timber:timber:4.7.1 (n)
+--- com.jakewharton.timber:timber:{strictly 4.7.1} -> 4.7.1 (c)
What do (c) and (n) suffixes mean?
Sadly, the Gradle docs do not cover this topic so it is a bit confusing.
Issuing gradlew dependencies | tail shows a legend explaining the meaning of the printed suffixes.
(c) - dependency constraint
(*) - dependencies omitted (listed previously)
(n) - Not resolved (configuration is not meant to be resolved)
Constraints are not pulled in unless some other dependency pulls them in.
Transitive dependencies are listed only once and then omitted.
Declared just for holding/listing the dependency not resolving it to a graph. This is the case for configurations like implementation or api.

Gradle Multi-Project Setup Layout - Multiple Dependencies

I'm converting an existing java multimodule project to gradle. The dependencies are a bit complicated - in short, I have something along these lines:
Root project MainProject
+--- Project ':P1'
| \--- Project ':P1:P2'
\--- Project ':utilProject'
So, my mainProject depends on P1, which in turn depends on P2, and a utilProject.
The thing is, both P1 and P2 also depend on the utilProject.
In the build.gradle for each of these projects was just compiling the ':utilProject' (the project is always in the root, and the projects for the main one look as I wrote above):
dependencies {
compile project(':utilProject')
// compile some other dependencies
}
P1 and P2 are fine (compiling without errors), however the main project won't compile. I've tried changing the code in utilProject around, and found that while the utilProject itself does compile the latest changes, the the main project is blind to them.
Any ideas would be greatly appreciated.
/// Update - July 20th 2014
Forgot to mention the MainProject is an eclipse plugin, and so we use the wuff plugin to compile (though I'm not sure it's relevant).
Seems like there is no need for P2 - P1 won't compile either (previously it just didn't use that bit of updated code. My bad).
Also, while I wasn't able to reproduce, I was able to find a workaround - adding the latest utilProject.jar to the dependency list seems to do the trick. I'm not sure why it's necessary... any ideas? Note that I did have to add the P1.jar to the MainProject and so on to make things work, which seems to indicate something's wrong with the dependency list, but all the projects on that list compile just fine.

Gradle multiprojects with same name, different paths

I have a monolith Gradle project that contains multiple subprojects, each with its own subprojects, like so:
project
|
|-- subprojectA
| |-- models
|
|-- subprojectB
| |-- models
This compiles fine but the issue is when I try to add a dependency on :subprojectB:models to :subprojectA:models, Gradle thinks :subprojectA:models is trying to add a dependency on itself and complains of a circular dependency, even though I specify the fully qualified path like so (in subprojectA's build.gradle):
compile project(':subprojectB:models')
How can I avoid this? Can subprojects not have the same name even if their paths are unique?
Project identity for dependency resolution is based on the group:name:version or GAV coordinates, as explained in the linked Gradle issue.
So you need to make sure your different models project have different GAVs.
One way to make this happen is to make the subprojectA (or B) part of the group.
Another way is to assign names that are not based on the containing folder.
That's currently a known Gradle issue as Gradle by default uses the parent directory name as the project name. You can work around the issue as described here by assigning unique subproject names in the root project's settings.gradle like so:
include ':subprojectA:models', ':subprojectB:models'
project(':subprojectA:models-a').projectDir = file('subprojectA/models')
project(':subprojectB:models-b').projectDir = file('subprojectA/models')

Resources