Question

I'm currently working on optimizing a maven build of a multi-module maven project. The Project consists of about 90 Maven modules. In general there are some cross-cutting libs making up the core and then there are about 15 "application modules" making up the entire application (Which is then deployed as in a WAR)

Now in general the entire project has a major version "2.5" so when a new major release is done all "application modules" have the same version "2.5.0". So far so good.

If a module has a bug that needs to be fixed or needs improving, a new version of that "application module" should be released. So for example Module A got a bug fixed, then A.jar should be in version "2.5.1" while the rest should still be "2.5.0".

parent (2.5.0-SNAPSHOT - Module A (2.5.1-SNAPSHOT) - Module B (2.5.0-SNAPSHOT) - Module C (2.5.2-SNAPSHOT) - War (2.5.3-SNAPSHOT) <-- 3 at the end, because C had 2 re-releases and A one and was released after every module release for simplicity.

We settled for managing the artifact versions in the master pom so we don't need to update the dependency versions of each artefact after releasing one module.

So now whenever an updated "application module" is ready, we use the maven release plugin to perform the release of that module (We are releasing one module, not the entire project). So let's say we are releasing Module A in version 2.5.4 resulting in A.jar being deployed as version 2.5.4 and finishing by updating the module code to 2.5.5-SNAPSHOT.

After this is done we need to update the version in the master pom, so all modules continue to reference the right version.

Thanks to the dependencyManagement section of the master pom, if I build the War module, it automatically picks up the new version of module A.

Now comes the tricky part: As soon as all modules are released, a new version of the Web application should be released. This should contain all the unchanged Modules as well as the ones that were just released. I am currently struggling on how to do that. If I depend on the parent poms version, the release would contain SNAPSHOT versions (all one version increment too high), which I and the release plugin don't allow.

What would be the best solution for this dilemma?

I had one idea to out-source the dependency management to a separate pom, which is then imported into the master poms dependencyManagement using the "import" scope.

Is this sort of szenario a stupid Idea? Are there alternatives to developing and maintaining a large multi-module application like this? Simply having all versions in sync ans using the release plugin on the entire project is not an option as the application is big and the client applications have to load updated module versions. Some of our customers have really slow connections, so rolling out all modules every time would make them really unhappy.

Help greatly appreciated,

Chris

Was it helpful?

Solution 2

Well I came up with a solution for my problem. It's a mix of a small releaste-plugin patch and a Jenkins Plugin to handle the pretty intense commandline-configuration needed.

Description of the Release process: https://dev.c-ware.de/confluence/display/PUBLIC/Releasing+modules+of+a+multi-module+project+with+independent+version+numbers

Description of the Jenkins Plugin: https://dev.c-ware.de/confluence/display/PUBLIC/Developing+a+Jenkins+Plugin+for+the+Maven+Release+Plugin

Code of the Plugin: https://github.com/chrisdutz/jenkins-release-plugin

OTHER TIPS

First of all, it's important to realize that version numbers, while important for dependency management, are completely arbitrary. At least, the form of the version number is arbitrary (yes, I'm aware of the syntax for Maven version ranges, which I've never heard of anyone using). Some OSS projects eschew "traditional" version numbers entirely and only use SVN repository versions or dates for versioning.

One option is to not have a "project-wide" version, and rather allow each of your components to have different version numbers. I feel this is a completely acceptable solution.

Another solution is to release using snapshot dependencies. You're not "supposed" to do this, but nothing is stopping you from hard coding the snapshot version (which is incredibly verbose and timestamped). Nothing except the specter of unrepeatable builds, anyway.

If you must have all components have the same version number, I suggest incorporating a build number into the minor component of your project version.

In this approach, you leverage the Maven Build Number plugin to distinguish incremental releases within a version as described in this question: Can I set the project version with a buildnumber-maven-plugin?.

Note you would only do this in a "final release" profile that is only used by your build server (or by your build engineer).

Version Numbers plugin is also your friend here.

The final release workflow would be something like the following:

  1. Start with version 2.5.5-SNAPSHOT.
  2. mvn versions:set -DnewVersion 2.5.5.
  3. Commit and tag your release (or create a branch - whatever your strategy is here).
  4. mvn deploy -Prelease which activates your "release profile" that adds the build number to the artifact finalName.
  5. mvn versions:set -DnewVersion 2.5.5-SNAPSHOT.
  6. Commit your "post-release" version.

Increment to version 2.5.6, 2.6.0 etc. when you have a truly "major" release.

Good luck!

Last night I realized that the build I scetched in my question had another major issue: The modules have deps to each other and these would not be handled by the release plugin. These SNAPSHOT dependencies would make the plugin fail (Which is good).

So I just had another idea that might solve my problems: I would create two maven pom artifacts "versions-dev" and "versions-rel" which contain a dependencyManagement section that defines the dev and rel versions. In my master pom I would now create two profiles "development" (active by default) and "release" which has to be manually activated. These profiles contain a dependencyManagement section and each import the dependencyManagement of the corresponding version-pom artifact using scope "import".

Now for a release would have to do the following steps: - Update the versions-rel and versions-dev to new versions. - Commit - Tag - run the release:perform target of the release plugin

There is still one thing that could cause problems: Assuming all modules have been modified, but only one should be included in a new release, then this approach would also re-deploy all of the modules, even the ones I didn't want to release. This would cause changed versions to be deployed with the same version as the previously released versions. Now I could avoid this by not releasing the main project, but only the individual modules. If however it were possible to only deploy those versions that are not allready deployed, it would make the release process a lot easier.

Any suggestions, objections, things I forgott?

Chris

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top