Version ranges in gradle - 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.

Related

how to set default version in mvn pom

H, I have a multi project that have inner dependencies and I use ${project.version} parameter to the dependencies. I want to set a default version that if the version of the specific artifact doesn't extrinsic he will use the default version.
This is not possible. You cannot have dynamic versions. The only thing that comes close are version ranges (like [1.0, 2.0)), but they fell out of fashion.
I still cannot really imagine a case in which this would be useful. First of all, if you have a list of 10 repositories you can just look up if a version exists or not. Why should it exist "sometimes"?
Secondly, if you have a "default version", why not just always use that? What do you gain from having another possible version?

How to compile against lower bound in Maven dependency version range

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.

Ordering when using dynamic versions in gradle + beta versions

In a gradle file it's possible to specify a dependency with a dynamic version, like:
compile 'some.dependency:name:1.+'
This is documented to resolve the "newest" matching version. I have two questions:
[1] What does "newest" mean? Suppose the available versions are:
1.0
1.1-beta
1.1
Is the "newest" one 1.1-beta or 1.1? Does it depend at all on when the versions were published, or is it purely based on the version strings? If purely based on the strings, what ordering is used, because if it's just alphabetical then I think 1.1-beta would end up being "newer" than 1.1.
[2] As a publisher of a module, is there a sensible way of publishing a beta build such that developers who are depending on your module and using dynamic versions wont automatically pick it up? Is there a standard or recognized way of doing this?
Thanks!
[I'm aware using dynamic versions is discouraged. These questions are from the point of view of someone providing a module, and wanting to ensure that developers who do use it and ignore this advice still don't end up pulling in something unexpected]
I' m guessing you are publishing to maven, and as I know, there should be an xml file named maven-metadata.xml which holds the information of the latest upload to the corresponding artifact. So I guess it does not depend on your naming convention but what you upload the latest. If you would upload 1.0.0.1 the latest then it would be downloaded not 1.1-beta or 1.1 versions.
For more info check here.

Which Plug-in Version Comes After 1.17.0

This might be a bit of a weird question, so bear with me.
I've got a Tycho/Eclipse plug-in that only contains a lib folder containing a third-party-library. The library has version 1.17.0, so in an attempt to make the process more transparent, the plug-in has, too.
It exports all the packages of the lib and everything is fine. At least it was, because now I realized it would have been much, much better if I exported the packages with a version. Plug-in 1.17.0 is already released (I know, Tycho doesn't normally release, just assume I don't want to re-use a version that has been stable for a year).
As an OSGi bundle, I am not allowed to take the version 1.17.0.1 or 1.17.0B or something, but I can't just use the version 1.17.1, because it would imply the third-party library is 1.17.1 as well, and it isn't. Updating the third-party library is not possible at the moment, because time is critical.
I tried 1.17.01 just now and nobody complains, but I'm not sure how Maven and OSGI sort this version relative to 1.17.0 and 1.17.1. The Maven manual does not really talk about zeros, but I guess it would force the string comparison, yielding in completely screwed up version sorting.
So... what version can I use safely?
You could just use something like "1.17.0.p1" which indicates a "patch 1" - it should be ok with OSGi as "the qualifier can be any string, sorted lexicographically" (quote taken from your OSGi link). "p1" is similar to qualifiers like "beta1" or "RC1" or...
major.minor.micro.qualifier
This should work for Maven as well. Moreover, we can assume that you would not provide a series of more than ten patches (at least I assume).
Personally, I would avoid leading zeros, as this looks quite odd to me. A series of HotFix or Patch versions should lead to an increment of a higher version number once in a while.
I'm not sure about Tycho but the OSGI framework treats the first three parts of the version as numbers and converts them to int using Integer.parseInt (see org.osgi.framework.Version).
So '01' will be treated exactly the same as '1'.
For the new bundle version, you need to make sure that is is larger in terms of the OSGi semantics - the Maven semantics don't really matter here. So you either need to increase the numeric value of one of the first three segments (e.g. 1.17.1) or add a fourth segment. The fourth segment, the so-called qualifier, is a string, and OSGi considers a version with qualifier to be larger than the same version without a qualifier. So you could e.g. use 1.17.0.a.
One word of warning for the change that you want to introduce with the new bundle version, which is to add versions to the exported packages. It absolutely makes sense to export the packages with a version, but is is crucial that you pick the right version for the packages.
Experience has shown that using the library version as package version is a bad idea: When we built an OSGi wrapper for javax.mail 1.4.1, we also used the version 1.4.1 for the exported packages. But when Sun released javax.mail as OSGi bundle in version 1.4.2, they decided that the packages fulfill the 1.4 API contract and hence exported them as version 1.4. So our older version of the library pretended that its exported packages were better, and the OSGi resolve would therefore prefer it over the newer library version.
To make things worse, we in the meantime also had lots of other bundles that required the javax.mail packages with a minimum version of 1.4.1, so they couldn't even be forced to use the newer library version. In the end, it took us more than a year to clean up the mess we had gotten ourselves with the bad choice of package version in the OSGi wrapper.
Conclusion: Only use very small package version numbers when converting a library that you don't own to an OSGi bundle. When using package version numbers with zero as major version, e.g. 0.1.17, you should be on the safe side that the versions that you invented yourself are smaller than all future "official" version.

How do I set an upper bound on Gradle dynamic versions?

I can't find any explicit documentation on Gradle dynamic version syntax -- the examples in the official docs are 1.+ and 2.+, neither of which appears to have an upper bound.
Say I have 1.0-SNAPSHOT and 2.0-SNAPSHOT in my repository, and I want a certain project to pull in the first or any future stable 1.x, but not the second.
I've tried both Maven syntax ([1.0,2.0)) and Ivy syntax ([1.0,2.0[). Both of these pull in 2.0-SNAPSHOT. Why? Is 2.0-SNAPSHOT considered "less than" 2.0?
On that assumption, I tried the obvious hacks: [1.0,2.0-SNAPSHOT) and [1.0,2.0-SNAPSHOT[, but both of those just fail dependency resolution.
How can I tell Gradle I only want version 1.x?
Looks like the answer is that + includes an implicit upper bound. So 1.+ means "any version that starts with 1."
This doesn't seem to be anywhere in the Gradle docs, but it is documented for Ivy:
end the revision with a +
selects the latest sub-revision of the dependency module. For instance,
if the dependency module exists in revision 1.0.3, 1.0.7 and 1.1.2, "1.0.+" will select 1.0.7.

Resources