Best Practice for encoding architecture in maven artifact? - maven

What is the best place to put platform/architecture info?
My temptation is to use the version field by prefixing the architecture designator to the version, since that would appear to be the simplest to wildcard and also will prevent accidentally mixing and matching of different platforms:
version = <architecture>-<version>[-<branch>]
Alternatively, one could append the architecture to the artifact id:
artifactId = <name>-<architecture>
Both ways lead to the same artifact name.
What do other people do, and why?

If you are developing for different architectures independently, any of these solutions may be good. You may have a situation, though, where the version number would be the same across architectures. This may typically be the case if you're building for the different architectures off of the same code base, e.g. either you have an artifact that is built into different distributables, or you have different artifacts that depend on the same common core. In that case, you would not want to pollute the version number with the architecture or branch information, as it renders Maven unable to treat it as the same version. The proposed solution for this is the use of classifiers. As per the Maven POM Reference:
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.

Related

Building two versions of maven artefacts

A dependency that we rely on (https://github.com/bytedeco/javacpp-presets/tree/master/ffmpeg) has recently split into a LGPL and GPL version, depending on how the underlying ffmpeg is configured.
There are two different sets of artifacts that are released (e.g. https://mvnrepository.com/artifact/org.bytedeco/ffmpeg-platform-gpl/4.3.2-1.5.5 and https://mvnrepository.com/artifact/org.bytedeco/ffmpeg-platform/4.3.2-1.5.5).
The API is the same for our purposes - we don't need to change our code. Its dynamic at runtime in terms of what is supported, but that is OK. Its already flexible given different hardware support.
I'd like to build two sets of artifacts as a parallel path up through our tree (e.g. two versions of core, api, viewer, examples, etc) as jar with different license dependencies to allow the user to choose which one they prefer. The goal is that the user can choose a particular version of our code and the dependencies "just work" in that the right dependencies are either included in the uber-jar or get pulled in via maven.
So I have a jmisb-api-lgpl-${version}.pom/jar (and maybe jar-with-dependency uber-jar) that depends on jmisb-core-lgpl-${version}.[pom, jar] that in turn depends on ffmpeg-platform-${other version}.[pon,jar]. And built at the same time, jmisb-api-gpl-${version}.pom/jar that depends on jmisb-core-gpl-${version}.[pom,jar] that in turn depends on ffmpeg-platform-gpl-${other version}.jar.
What is the preferred / recommended way to do that, or alternatively, what is a relatively clean way that builds both without needing to manually select which one to generate?

Semantic versioning (semver) versus Maven convention versus artifact repository conventions - What versioning scheme to use?

I am setting up a versioning scheme for a greenfield project and read a lot about semver and the Maven convention. I'm using the Nexus OSS repo manager (v3.13.0).
It's hard to settle on an authoritative scheme when in comes to versioning but I believe in the power of convention. While the semver document (link above) seems well written I notice clashes with how Maven seems to treat version numbers. The goal is to settle on a scheme that gives good ordering. Semver mentions that the pre-release label (the part that follows Major.Minor.Patch-) may have dot-separated segments, some of which are numeric and are to be compared as such, so one should not have zero padding such as RC.09. In practice, however, Maven (oracle link above, but is that authoritative?) treats everything after the first dash as one alphanumeric field, hence, one should use RC09 and RC10.
My question is, use zero-padding or not? I would love to adhere to semver, but I also need something that works.
The added complexity is I'm not using Maven, but Gradle! But does that even matter? --> where is version ordering computed, in the build system or in the repo manager (Nexus in my case). See what Nexus says on the topic - BUT, it references Maven, so I'm not sure if that applies to Gradle clients (or rather, to the maven-publish plug-in). Then again, Gradle tries to mimic Maven when it comes to publishing standards. It's a mess!

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.

Automating Maven artifact releasing

For a project with a large number of Maven artifacts (both internally generated as well as external ones), how does one go about automating the releasing of the internally controlled artifacts as part of an overall product release.
Things to be aware of about this question, we use Jenkins and the Maven release plugin. So the operation of releasing a single artifact is automated (albeit the operation to kick-start the process is manual). However the process of releasing all the changed artefacts over the course of a release is not automated (i.e. one has to manually kick-start the release of each artifact). Part of the problem is that almost nothing is released until the end of the release, prior to that everything remains in SHAPSHOT. We have a huge number of components as well as numerous applications/services (over 30) which rely on the plethora of components. So it is not just the case of picking a component and releasing, there are release dependency hierarchies that must be followed (i.e. start at the bottom releasing components that do not use other components and then work your way up until all the applications/services are released).
It is also worth noting that we use two common parent poms which, for the most part, control the versions of the external artifact dependencies and the internal component dependencies. Some pom files for components and applications may override this, but this is (or should be) an exception and should be for a good, but temporary, reason. So when an internal artifact is released, the version in the corresponding parent dependency pom should also be updated.
The product has a release number (of course), however the various pom files technically do not share this version number. While this is not strictly true, the idea as that when parts of the software are set to end-of-life, they will not be updated in the future, thus while a limited number of artifact versions match the product's version at present, this will eventually not be the case.
Any thoughts on ways to get this process automated would be greatly appreciated. Also if you feel what I have described seems to be a crazy way to manage the software, then please provide a comment. Thank you.
You might be able to make use of the Maven Versions plugin which can help formalise versions for projects.
For example, the use-next-releases goal may allow you to release the lowest level of project and then more rapidly bring those released versions into their dependencies.
There may also be scope to use the use-next-versions goal if you fancy releasing components as necessary and simply bring your projects to the "latest" version thats been formally released.

Maven : Multimodule projects and versioning

What are the best practices for software versioning and multimodules projects with Maven?
I mean, when I create a multimodules project with Maven, what is the best approach for the versioning? To use a single version for all the modules (defined in the top project)? To use a version for each module (defined in the POM of each module)? Is there another approach that I'm missing? What are the pros and cons of each approach?
In general, are the different modules released together (possibly sharing the same version number)?
Thanks
Honestly it depends on what you would like to do. Multimodule projects are created for multiple reasons, one of them being you only need to deploy what has changed instead of all modules.
Think about it this way: if you had a non-multi-module project and you only had to change one line in the services layer, you have to rebuild the entire project and deploy all of the code again...even though only your services layer will change.
With multi-module projects, you can regenerate your project and deploy only what changed...your services. This reduces risk and you're assured that only your services module changed.
You also have a multitude of benefits to using multi-module projects that I'm not listing here but there is certainly a huge benefit to NOT keeping your version numbers of your modules in sync.
When you build your project, consider deploying it to a repository that will hold all compatible jars together for builds (each build creates a new folder with the parent-most pom version number). That way, you don't need to keep documentation about which jars are compatible...they're all just deployed together with a build number.
I was looking for a solution for this exact problem myself and versions-maven-plugin was exactly what I needed. I don't like the release plugin communicating with the SCM system. The versions plugin does just what we need: it sets a new version number in all poms of the project:
mvn versions:set -DnewVersion=2.0.0
Then I can proceed with commits, tags and an official build server build...
EDIT:
The versions plugin depends on how a maven multi-module project has been organised: as a result, it often does not update all POM files in a complex multi-module project.
I've found that sed and find do the job much more reliably:
sed -i 's/1.0.0-SNAPSHOT/1.0.0-RC1/g' `find . -name 'pom.xml'`
Typically you create a multi-module project because you have deemed that the various modules are parts of a single whole. Maybe the client-piece, the controller-piece and the services-piece. Or maybe the UI with services.
In any case, it makes sense to have the version numbers for the various modules to move in lock-step. However Maven does not enforce that as a rule.
As to your question
are the different modules released together (possibly sharing the same
version number)
I would think so. That is one of the reasons for having it a multi-module project. Otherwise you could have the modules as independent projects.
Of course this is the kind of stuff that is rife with edge cases and exceptions ;-)
I had the same problem with a project I`m working on. I also decided to use separate versions and even the dependency to the parent pom only has to be updated if some of the managed dependencies change. (so mostly as #vinnybad describes it)
Two additions
exists-maven-plugin
With the usage of the "org.honton.chas.exists-maven-plugin" only the modules will be deployed to the repository that have actually changed, which is really great, because also the according docker-images will only be published if something has changed on one of the service. This avoids "polluting" the image repository with different but unchanged versions.
versioning
One main downside of the "separated versions" approach are the questions regarding versioning:
What's the current version of my project?
Which module versions work with each other? (even thought they don't directly depend on each other, one does rely on what another does, e.g. they share the database schema)
To solve that I put all module versions into the dependency management part of the parent pom, even if no other module depends on them. A "integration-test" module could solve that by depending on all of the modules - and of course testing them together.
This way I would be "forced" to update the parent pom with every change, since it's referring the released module versions. This way the parent pom would have the "leading" version and at the dependency-management block state the versions of all modules that are compatible with each other (which will be ensured by the integration test).

Resources