Named versions in Maven? - 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.

Related

Liferay versions and correct dependencies

I'm rather new to Liferay, Maven and Java so it may be more of a general question about dependencies. I am maintaining a Liferay portlet that has been migrated from 6.2 to 7.1 and there are a number of Liferay maven dependencies with version numbers (eg. com.liferay.portal.kernel).
How does one know which versions of these dependencies one is to use for the version of the product that they are using?
Is this a typical case where one should always be trying to use the most recent version of dependencies even if the version of the product is a minor release behind?
Probably the easiest thing to do to make sure you compile agains JAR version that is in your target environment is to use the respective BOM (bill of material).
You can have a look at this code sample's POM for Liferay Portal 7.2 for example. Note the dependencyManagement that indicates which BOM to use:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>release.portal.bom</artifactId>
<version>${portal.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Then note how the actual dependency for com.liferay.portal.kernel JAR does not have a version specified.
<dependency>
<groupId>com.liferay.portal</groupId>
<artifactId>com.liferay.portal.kernel</artifactId>
</dependency>
The JAR version will be taken from the BOM which ensures it will match with the one the given version of Liferay Portal contains.
For comparison, here is the exact same POM but for Liferay Portal 7.1. As you can see the only difference is the portal.version property.
how does one know which versions of these dependencies one is to use
for the version of the product that they are using?
There are several ways to know which dependency versions you are using. The simplest one is to open up your bundle's jar files and look at the manifest file.
Of course, opening manifests is pretty tedious. You can use your system's Gogo shell to obtain information about the bundles on a running system.
Or you could look for the dependency on git. Use the Liferay tag that corresponds to your system, and subtract 1 from the minor portion of the version you see in the bnd file.
Finally, the logs can help you telling when a dependency is missing or a package version exists with a mismatch in version numbers.
Personally, I would say that the Gogo shell and App manager option is the easiest way.. but sometimes you are on git already..
is this a typical case where one should always be trying to use the
most recent version of dependencies even if the version of the product
is a minor release behind?
No, this is not a good thing for you. Although minors portions of the version scheme usually indicate that things are not likely to break, they do. If you use a method that was added in a minor version, on your running system that method will not be available and debugging can be confusing as you will clearly see that you IDE is even auto completing nonexistent stuff.
Additionally, there is no real advantage on using the latest version to compile your modules as the one running on the system is not updated, the one that will be running is the one that comes with your product (if you have not changed it, installed or embedded it even inside your on module... but if you did adjustments on your bundle, then it is up to you to track...).
You can use version ranges like 3.1.+ to build your modules, assuming that modules compiled with that dependency will work with all dot versions of it in a running system. If the dependency is known to be compatible with the older versions of itself, you can use older versions to build while the system will run a newer one. Liferay does this all the time in their own code (sometimes hidden by the word default). Of course, if you do this you will not be able to enjoy the latest features and IDE provided autocomplete and verification.
You also need to be aware that in OSGi based systems, several versions of the same library is possible. Sometimes, only one runs (singletons) but sometimes several will be available on runtime...so, you can pick the latest of the available...
So, in short: do not use the latest version to build if your system will not be running it. Maybe a range works, but you need to check if that dependency actually cares about being compatible inside that range, according to its versioning scheme.
Useful links:
lib/portal/dependencies.properties
modules/modules.properties

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.

Manage dependency version centralized

I've got multiple projects using a certain Dependency of Version XX, if I release a new version, I have to touch every project to change it to version XX.Y.
I've came across an approach to edit my m2 settings <version>${my.version}</version>, to add a parameter and bind it into my POM.xml, but this implicit means, everyuser has to manage their m2 settings when I do a new release.
Is there a way to central (user independant) manage the versions as in SVN, so none has to change anything and it always uses the up2date version, if I release a new version?
In general, the maintainer of every project should decide for themselves if they update the version or not. Updating the version might break things, so they may choose to stay on the older version. Particularly, it is important that the maintainers notice that something has changed, so that tests are run.
For development, though, there are Snapshot versions. A Snapshot dependency always references the newest version, but the -SNAPSHOT indicates this to the maintainer of the project. Snapshot versions should not go to production - the builds are not reproducible.
If artifacts are so tightly coupled that they are build together, think about using multi module projects.
You can use a pattern called "Bill of Material".
I think your question is somehow similar to this question (but not exactly a duplicate), and my answer applies here aswell:
You create a new maven project (the bill of material) that only consists of a pom with dependency management block. Here you declare all your dependencies and their versions. The packaging should be set to pom.
This bill of material (bom) project is now used as parent of all other projects. When using a dependency, only group id and artifact id is specified, the version tag is ommited. In that way, the version will be taken from the bom and you have one central place to manage the versions of the dependencies.
More details with examples are here (in the lower part of the page) or here.

Maven aggregate pom skip released modules

This is probably supported, so I apologize if the answer is trivial, but I can't find an answer.
I have a multimodule (aggregate) pom containing a number of modules with interdependencies. Let's say something like:
infrastructure
framework
business-module1
business-module2
At a certain moment, infrastructure is stable, so I can release it. The version is updated to 1.0 and all dependencies to it are updated to that version as well.
When doing a local install, the module is still build. I know want to avoid building the 1.0 version locally, since it is released and costs build time. The question could be rephrased to, never build a released module.
I have quite a lot of modules in a multimodule setup, and only want to build snapshots. I know that I can skip modules using command line options, but don't want to repeat all these modules. Besides, from the version declarations, it should be clear to maven which modules to build.

Is there a way to tell maven to always use the latest _stable_ version of a dependency?

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*"

Resources