Building different project versions from the same source code branch - maven

I am trying to build my Java project into two different version, each one based on different versions on the same dependencies. Specifically, my project A requires a dependency B, which has two different versions (e.g. v1 and v2). I am looking to build project A with each dependency version of B and get as artifact two different jars: A-v1.jar and A-v2.jar. The source code is the same so I wouldn't want to duplicate it into two different Maven projects, as I am looking to scale it when new versions of B will be released.
What I have tried so far: I defined two build profiles v1 and v2 where I have specified the dependency B version. This works fine as I can build the two profiles, but the issue is that I have no idea how to tell Maven to add a version number to the build artifact. It always builds project A into A-1.0.jar, where 1.0 is the project A version in the pom.
One update of my investigation: I have added a finalName element in the build section of my parent pom to override the default artifacts naming. Now the naming will be like ${artifactId}-${project.version.mycustomver}, where project.version.mycustomver property is defined in each build profiles. This seems to generate the correct naming of jars, however maven-install-plugin is changing the artifacts names back to ${artifactId}-${version}. No idea why and how to avoid it.
I appreciate any suggestion. Thanks,
DanP

You can either use classifier which is somehow made for that.
But you should also be able to change the version using a property that is overridden in the profiles.
Since you need two distinct POMs, one per "version" of your project, you in fact need two projects. However, you can have one normal version A. And a second one which is empty but uses dependency management to exclude and replace the dependencies that changes from A-v1 to A-v2.

Related

How to built a multi-module Maven project with 4-digits of version string that includes CI build numbers?

I've been asked to do this, so please don't suggest that I shouldn't need to. :-p
We currently build a multi-module project with Maven. We have no problems doing so. We're using the Maven release plugin, and we get SNAPSHOT builds for development and release builds in Jenkins. The release plugin automagically increments the 3rd place of the version string. Life is good.
But, I've been asked to add a 4th place in our version strings, which is populated with the Jenkins build #.
The canonical way I see suggested to do this works fine with a single module: You define a property like build.number, to have a default value of "0-SNAPSHOT", and you define your POM to have a element value like "1.9.${build.number}". And, you set your Jenkins job to define build.number to be the Jenkins build #, for its invocation of Maven.
That would be great, if we had a single module, but we don't. We have multiple modules, and in Maven I can't either
1. not specify a version in the child module POMs, nor
2. use a property in the version of the child module POMs.
I gather it's a bad idea for Maven POMs to try to produce multiple artifacts in a single module (using. say, profiles), so I don't want to try to smoosh this project down to a single module.
I probably could try instead splitting it into separate projects, except that seems drastic, and besides, this project really is producing very tightly-related artifacts, so I want to be sure to build all the artifacts for any source code change in the project.
Any solutions?
The maven-release-plugin has two parameters named releaseVersion and developmentVersion. There you set the version to build and the next version, respectively.
Using Jenkins, you can fill these variables with Jenkins generated content, using e.g. the build number. If you want to read the parts of the version number from the POM, you can use build-helper:parse-version and use terms like ${parsedVersion.majorVersion}.

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.

Pick Version with Branchname as Classifier with Gradle

I am evaluating gradle for our project. We have multiple small project that contain small util libraries. Most projects are in an extra repository and cannot use a shared buildscript.
When working across multiple project the same feature branch is used. I already managed to get gradle to put the branchname into the created maven artifact as classifier.
For our continous integration it would be really helpful to resolve a dependency to such a library to the one using its own branch name if it exists. If it doesn't it should fallback to the normal declared version.
I managed to change the versions via resolutionStrategy.eachDependency but I couldn't find a way to implement the fallback if no version for this branch exists.
Is there any way this can be achived?
Regards,
arne
You'll have to write some code to achieve this. For example, you could copy the configuration, set classifiers for the copied configuration via resolutionStrategy.eachDependency, resolve the copied configuration via configuration.resolvedConfiguration.lenientConfiguration, check which dependencies could be resolved, and then choose classifiers for the original configuration accordingly (again via resolutionStrategy.eachDependency). The best place to do all of this is in configuration.incoming.beforeResolve.

Update dependencies in Project B when Project A is released

I have two multi module projects. One is the main project tree. The other project tree pulls in the artifacts (WARs, JARs, etc) from the first project. They each have their own separate parent pom.
I would like to keep their version numbers identical. Project 2 has a dependency management section that has the artifacts from project 1 in it. The problem with this is that I can't release the project due to snapshots.
For example. The version number (for both projects) is 3.4-SNAPSHOT. I can release a version 3.4 of project 1 and all the pom versions will be set from 3.4-SNAPSHOT to 3.5. When I go into project 2, I want to do the same exact thing. The hitch is that dependencies of project 1 are at 3.4-SNAPSHOT and I can't figure out how to automatically get them to be 3.5. It's like I want the dependencies to be updated to the release version, before actually releasing.
I understand that if I make both trees extend from the same parent pom, the maven release plugin would detect the dependencies as submodules and update them automatically.
I read a little bit about the versions plugin but I didn't like the use-latest-versions part of it (it seems way to dangerous). The Update-properties seemed promising but it upon a second cursory look, it looked like the use-latest-versions plugin packaged slightly different.
Also, I tried just using ${project.version} but that's basically the same as putting 3.4-SNAPSHOT in as the dependency - it'll error saying it can't release due to snapshots since the version actually hasn't been updated yet.
The way you have the projects configured they are totally independent. You might as well be asking for the version of your log4j dependency to be the same as your current project B version.
While it won't be automatic, you should replace the versions of all references to Project A within Project B to use a property that is defined in the parent pom for Project B. Then, when you release Project A, you only have to change one pom so the project.a.version property is now the released version instead of SNAPSHOT. After the release of B you could then change it back to ${project.version} to keep them in sync.
As you admit, the right answer here is to re-arrange your project to have a common parent. Anything else is just a workaround.
However, it looks to me like versions:use-releases might achieve your goal. You can specify an includes list to ensure only project 1 dependencies are updated.
If you wanted this to be automatic, you could consider binding this goal to one of the lifecycle phases prior to compile.
Edit: sadly this looks like its not possible. At least, that's how I understand by the "Executes by direct invocation only" mentioned at the top of the page.

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