Ordering when using dynamic versions in gradle + beta versions - gradle

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.

Related

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.

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.

Named versions in Maven?

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.

Gradle: Show dependencies that have newer versions

Is there a plugin or sth. else for Gradle that informs you when there are new library versions available for a certain depedency?
Might be difficult if some libs do not stick to well-known version conventions but for the others I think it should be possible to find out!?
If there is not, any hints how to implement this feature are appreciated.
Thanks
No such plugin ships with Gradle. There might be a third-party plugin, but I'm not aware of one. To implement this, you would iterate over a configuration's resolved dependencies (using the configuration.resolvedConfiguration or configuration.incoming API) and query some website (e.g. http://search.maven.org) or web service for latest versions. For API details, see the Gradle Build Language Reference.

How do I deal with two near-identical release branches in Maven

At work someone has committed a lot of changes into a project that are JDK 1.5 specific. Unfortunately, some of the production environment is still at Java 1.4, and so they have resorted to creating a dual branch consisting of a jdk1.4 version of /trunk.
This 1.4-branch is likely to have at least a one year lifetime, during which changes in trunk are merged into the jdk1.4 branch.
The question I was asked is if there was any best practices on dealing with Maven artifact ids in this situation? Obviously best practices would probably avoided getting us in this situation to begin with, but now that we are ... what to do?
We thought about giving the other branch a unique artifact id, such as "myapp-jdk14", while keeping every other identifier field (groupId, version) in sync. Any obvious downsides to doing this?
You could use a classifier for this:
classifier:
The classifier allows to distinguish artifacts that were built from the same POM but differ in their content. It is some optional and arbitrary string that - if present - is appended to the artifact name just after the version number.
As a motivation for this element, consider for example a project that offers an artifact targeting JRE 1.5 but at the same time also an artifact that still supports JRE 1.4. The first artifact could be equipped with the classifier jdk15 and the second one with jdk14 such that
clients can choose which one to use.
Source: http://maven.apache.org/pom.html
In fact, there are 2 commonly used solutions for this:
Adding some special, custom suffix to artifacts' names, like jdk14. For example, Bouncy Castle or SLF4j use this strategy.
Using classifiers, that are in fact designed for such tasks like distinguishing variations about same artifact (exactly your case).
What is interesting from my experience, first solution is really more often used despite the fact that the second one is officially suggested for such stuff.
Personally, I use first solution, but - to be honest - I don't see any strong advantage (or disadvantage) of one solution against the other one.
You can use your solution but I would suggest to have different version numbers.
For example:
1.0.X for JDK 1.4
1.1.X for JDK 1.5
That doesn't mean my suggestion is better than yours. Your solution has the advantage to see based on the artifactId which jdk it is for very obviously.

Resources