Is there a way, in Maven, to declare a dependency version range and have it resolve against the lower bound for the compile phase of the build?
eg. I declare a dependency using version range [1.2.0,1.999.999]. I would like for the compile phase to use version 1.2.0, specifically, but for the deployed POM to still show my compatible version range as [1.2.0,1.999.999].
My project is a library. For a non-library project I would just pin a specific version.
I see your point, but I am not sure this is the right idea.
First of all, version ranges are not very popular nowadays. People tend to avoid them because the build is not reproducible. AFAIK, they are not really deprecated, though.
Using version ranges to show compatibility is unexpected. Maybe a comment in the POM would be better.
Related
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 by default uses these versions of plugins such as clean, compile, jar etc. if I don't override them in my pom.xml.
Should I be using more recent version of these plugins? For example, the current version of maven-compiler-plugin is 3.6.1 while the default is 2.5.1. Or, are the default versions reasonable enough that anyone not consciously depending on newer features need worry?
The maven way is "convention over configuration", so if you're wondering about not using the default parameters when running a maven build, you should have a specific use case that is not covered by the default version.
Here for example, (according to here) the install plugin is still at version 2.5.2, so that would point to me that using 2.5.1 is not such a bad choice by default.
I think the biggest difference comparing version (I might be wrong) is the upgrading of compatible version as for example this pseudo release note of the maven compiler.
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.
We are using mvn pom.xmls to specify interdependency between our various modules that make up the project.
The numeric version for every module is incremented by the build system automatically when the module is released.
However, in this case, this would necessitate notifying every team to update the version their module depends on to the version we just released.
Can Maven instead just work in a way that users of a library specify something like, "depend on the 'STABLE' version of this module", and then with every build it would figure out which actual version number that translates to?
Why don't you just depend on the major version, and release minor versions?
<version>[1.,)</version>
You can also use RELEASE
<version>RELEASE</version>
However I guess that's not supported in Maven 3.
See more discussion about the same topic from this thread.
How can I tell maven to always use the latest stable version of a dependency?
I know that I can depend on latest release version or just the latest version whatever that is from this question. I also know I can use the dependency plugin (also from that link).
However, I use google's guava library which seems to get an update every week. I find myself updating the version all the time. It's the google versioning system where it is more an incremental update than a big bang update and thus it is very unlikely that it will break anything especially given the nature of this library.
So I Would like to not have to keep changing the version identifier of my maven dependency.
So I could do this:
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>[12.0.1,)</version>
</dependency>
Which would give me version 12.0.1 and later... and since I don't depend on any repos that are going to supply any snap shot versions of this dependency this will ensure I always have the latest release version.
However, it will also give me the "rc" versions as well (13.0-rc1 and 13.0-rc2). This is what I want to avoid.
Is it possible to make maven only depend on the stable release? i.e. that don't have any "rc" or "beta" or "alhpa" in their name and are just plain "13.0".
You can use RELEASE value in version element for your dependency to make Maven use the latest released version. However this is not the best practice, because it can break build reproduceability.
Also, Maven don't make logical differences between versions like 12.0.1 and 13.0-rc1. From Maven's point of view both of them are released versions and basically what you're trying to do is breaking Maven releases ideology in several ways.
So, instead of versioning artifacts like 13.0-rc1, you should do a regular releases and use special repositories and artifact promotion process as par of your release. So, you could have a release-candidates repository that can be used during testing and once test pass you'll promote those artifacts to a final release repository. But if you need to make changes, you'll just update released version, so 13.0, 13.0.1, etc...
mvn versions:use-latest-releases -Dexcludes="*:*:*:*:*-M*,*:*:*:*:*RC*,*:*:*:*:*rc*,*:*:*:*:*-alpha*,*:*:*:*:*-beta*,*:*:*:*:20030203.000550,*:*:*:*:*Beta*"