How does gradle evaluate dynamic dependencies? - gradle

The Gradle documentation is very sparse on how dynamic dependencies are resolved.
There are two styles of dynamic dependency declaration: lib:20.+ and lib:20.0+.
Are they equivalent?
Do 20.1 , 21 and 20.0.1 match these declarations?
Typically, I want to get fixes (x.y versions with x fixed) automatically and manually update to the next major version which can include breaking changes.

I have finally found an answer, in the Ivy documentation of all places :
Revision Matches
1.0.+ all revisions starting with '1.0.', like 1.0.1, 1.0.5, 1.0.a
1.1+ all revisions starting with '1.1', like 1.1, 1.1.5, but also 1.10, 1.11
source : http://ant.apache.org/ivy/history/latest-milestone/settings/version-matchers.html

Related

Exclude certain semantic from dynamic versioning

I want to use dynamic versioning and lock the dependencies. Is there a way to do sth like:
1.+.X, where X means that I want to exclude the patches from dynamic dependency resolution, but I want to keep track of the minor releases? Sth like::
1.1.1 is used in the gradle.lockfile
1.2.1 is released
1.2.2 is released
I do ./gradlew dependencies --write-locks
gradle.lockfile is updated and 1.2.1 is used

Gradle dependency library updated by another library

My gradle has for some time had a dependency on the (amazing) Android library Picasso. It has always been set to version 2.5.2
implementation 'com.squareup.picasso:picasso:2.5.2'
I recently updated all my Firebase libraries from a fairly old version to the latest. At which point something odd happened.
My Picasso method calls began to error
Picasso.with(context)
Which I know from this SO article results from a change to Picasso.
cannot find symbol method with() using picasso library android and I need to change to
Picasso.get()
OK not a big deal, but it got me wondering. Obviously Firebase uses the latest version of Picasso and is making my project use the latest version as well. My question is why is my local gradle file ignored and the newer version of Picasso defaulted to?
Off the top of my head: Since you declare a specific version that requirement is not flexible. To allow for a newer version if available a + declaration is required. My guess is that another dependency is also dependent on Picasso after the updates. Gradle, when given a redundant dependency, will select the newer version.
This is in alignment with what you said, if I understand correctly. If Firebase uses a newer Picasso version, because it requires that version, then Gradle is given two versions to choose one from. This will always result in the newer version being chosen. At least this is default behavior afaik.
It seems to me that you already know Picasso is used by Firebase. If you want to see where which dependency comes from however, you can look into build scans:
gradle build --scan
https://scans.gradle.com/?_ga=2.166196030.1236003146.1565212874-222812074.1565212874
A little bit more advanced dependency management:
1) Set Gradle behavior on dependency conflict:
https://docs.gradle.org/current/dsl/org.gradle.api.artifacts.ResolutionStrategy.html
2) Declare version constraints (see Rich version declaration):
https://docs.gradle.org/current/userguide/declaring_dependencies.html
You can check the official doc:
Gradle resolves version conflicts by picking the highest version of a module. Build scans and the dependency insight report are immensely helpful in identifying why a specific version was selected.

Maven Version Range - downloads all the available versions not just the latest one

I have two modules: A and B.
A depends from B.
In the module A there is a dependency to B with the following version setting: [1.0.0,)
From the B there are two versions: 1.0.0-1 and 1.0.0-2. The 1.0.0-1 is out of date, it has some missing dependencies, hence I cannot create a build from it. But the 1.0.0-2 is working fine.
When I use the install for the module A I get an error that B:1.0.0-1 has a missing dependency.
That's happening because the maven downloaded all the versions from the 1.0.0 not just the last one.
If I would use LATEST then just the 1.0.0-2 would be downloaded, but it's not what I want. Basically I would like to download just the latest from the 1.0.0.
How could I do this ?
Thank you for the answers!
(Maven version: 3.5.0)
First don't use versions ranges cause they make your build non reproducible.. If you like to update things like that you can use versions-maven-plugin to update the dependency. Apart from that what is the difference between 1.0.0-1 and 1.0.0-2..From your explanations i would assume you should change your versions schema cause the second one is not compatible with the first one so I would say 2.0.0 instead of 1.0.0-2..or is see it as a bug fix than 1.0.1...(following semver). Another point LATEST is marked deprecated for a long time and will produce a WARNING in the next Maven versions..
Coming to you explanations: I have my doubts that all artifacts are being downloaded...If you take a look at the logging output I assume there are some line saying ...maven-metadata.xml will be downloaded...
First part of the answer...

Maven dependencies - version vs updates

mvnrepository usually lists "version" and "updates" for each dependency.
If I'm publishing my own package, how do I specify the "updates" version
Which dependancy does Maven used when resolving transitive dependencies? So if my package depends on package A, which depends of package B with - version = 1.0 and updates = 1.1. Which version of B would I get?
You're asking what the meaning of the information in the "Updates" column of MVNRepository's "Compile Dependencies" table is.
It tells you whether there's an updated version of a particular dependency available and if so what the latest version is. If there's a check mark it means the library in question already uses the latest version of dependency X. You will always get the declared version of a dependency no matter what the latest version is.
Hence, if you use valdr-bean-validation 1.1.2 (example above) you'll also get jackson-databind 2.4.0 as a transitive dependency (1st row above). 2.7.1-1 would be the latest available jackson-databind version.
Notes: I finally understand your question. It would have been helpful for you to give us a concrete example right from the start.

Version ranges in gradle

What are the possible ways of specifying version ranges in gradle dependencies? I saw some 1.+ notation but I have not found a document which really says what is possible and what is not. Furthermore, I do not know whether the Maven ranges can be used as well.
Can somebody give me a short overview so that I can understand the rules?
The book "Gradle Dependency Management" states on p. 12 and 13 that, in addition to the +-notation (2.1.+ means the range from 2.1.0 inclusive to 2.2.0 exclusive) you can use the Ivy notation for open and closed intervals of the form
[1.0,2.0]
[1.0,2.0[
or also
[1.0, )
for "all versions starting from 1.0".
Preferred alternative
Specify the version range using Ivy notation. Here are some examples copied from this web page:
[1.0, 2.0]: all versions >= 1.0 and <= 2.0
[1.0, 2.0[: all versions >= 1.0 and < 2.0
[1.0, ) : all versions >= 1.0 // avoid. Unbound is dangerous!
Troublesome alternative
Use '+' in the major, minor or patch number. This approach has at least two issues:
If you're building a lib and generating a pom file, the pom will be incompatible with maven, unless you apply some workaround to resolve the version and prevent the pom dependency to use '+' in the version element. See this Gradle github issue.
The meaning of '+' is prone to confusion. Well, maybe not, but ask around to see if all your peers know exactly the difference between 1.1.+ and 1.1+ in a gradle dependency.
Ideal alternative
Avoid dynamic dependencies (using '+' or version ranges) altogether. Instead, use a fixed version dependency and update the version often with good testing. Here's why:
In the old days, backwards compatibility was sacred. That's not true anymore. New versions often move/remove/rename classes and functions.
If your dependency is dynamic (especially with '+' or unbound range), the next build may pick a new version that is incompatible with your project. The incompatibility may be detected only at rutime.
Version X of your library as built today might be different from version X of your library built tomorrow if one its dependencies is dynamic and a new version is released overnight. This level of uncertainty is not desirable for libraries.

Resources