Issue Details (XML | Word | Printable)

Key: MRELEASE-252
Type: Improvement Improvement
Status: Open Open
Priority: Major Major
Assignee: Unassigned
Reporter: Franck HUGOT
Votes: 16
Watchers: 12
Operations

If you were logged in you would be able to see more operations.
Maven 2.x Release Plugin

Support for multi modules project

Created: 15/Jun/07 04:33 AM   Updated: 27/Apr/09 07:35 AM
Return to search
Component/s: perform, prepare, stage
Affects Version/s: 2.0-beta-6
Fix Version/s: None

Time Tracking:
Not Specified

Environment: Maven 2.0.6


 Description  « Hide

I would like to prepare a release for multi-modules project.
I would create tags for all the modules and modify poms.
Not only the versionId in the pom but also the eventual dependencies between all the modules.
Indeed, if a module A has a dependency to module B, the version will be updated.

The dependency management is a hard task in multi modules project and this feature would be really appreciated.



Martin Andres Marquez added a comment - 24/Jan/08 12:33 PM

What about this issue?


Moshe Bergman added a comment - 30/Jul/08 01:23 AM

I would also like the maven release plug-in, to create a tag for each module rather then the whole tree.

This way, it will also be possible to release just a single module independently of the whole project.

The way I see it, it should work like this:
Option 1 - release all modules:
1) Version of parent pom is updated and all modules as well
2) Tag is created for each module.

Option 2 - release a single module
1) Version of the parent pom is updated
2) Tag is created of the single module
3) dependency to this module is updated across all modules.

Maybe add an option to support this model?


Sylvain Marié added a comment - 15/Jan/09 11:55 AM

+1:

option 2 would be greatly appreciated - as it is the most common use-case for us (release a bug fix on one of the modules only).


Sylvain Marié added a comment - 16/Jan/09 02:15 AM - edited

Actually the desired behaviour would be a bit more complex for option 2. Let's say I have the following layout:

parentPom 0.0.4-SNAPSHOT
.
— module O 0.0.1-SNAPSHOT
(depends on A 0.0.2-SNAPSHOT) (inherits from parentPom 0.0.4-SNAPSHOT)
.
— module A 0.0.2-SNAPSHOT
(depends on B 0.0.1-SNAPSHOT and C 0.0.2-SNAPSHOT) (inherits from parentPom 0.0.4-SNAPSHOT)
.
— module B 0.0.1-SNAPSHOT
(inherits from parentPom 0.0.4-SNAPSHOT)
.
— module C 0.0.2-SNAPSHOT
(inherits from parentPom 0.0.4-SNAPSHOT)

I would like to be able to prepare/perform a release on a subset, lets say parent + modules A and B. First I need to tell the plugin that I want this subset. There are several ways to do it:
a) in the pom, under maven-release configuration:
<partialReleases>
<customrelease1>this,A,B</customrelease1> // "this" designating the parent here
<customrelease2>A,B</customrelease2> // parent would not be released
//note : which names shall we use ? artifactIds or same as <module> names ?
</partialReleases>
One of these partial releases could be then chosen through commandline (-DpartialRelease=customrelease1)
b) through direct commandLine arguments (-DpartialRelease="this,A,B")
c) in the release.properties file
d) in a separate file (one per custom release), for example "customrelease1.subset". This file would be given to the plugin through a commandline argument (e.g. -DpartialRelease=customrelease1.subset )
...

Assume that I found a way to choose subset "parent, A, B". The output of the default behaviour should probably be:

Releases:

parentPom 0.0.4
.
---module A 0.0.2
(depends on B 0.0.1 and C 0.0.1) (inherits from parentPom 0.0.4)
.
---module B 0.0.1
(inherits from parentPom 0.0.4)

this is a "normal" behaviour except that dependency to modules not included (here, C) are by default set to the previous release (or another version choosen by user, if needed)

New Trunk:

parentPom 0.0.5-SNAPSHOT
.
— module O 0.0.1-SNAPSHOT
(depends on A 0.0.3-SNAPSHOT) (inherits from parentPom 0.0.5-SNAPSHOT)
.
---module A 0.0.3-SNAPSHOT
(depends on B 0.0.2-SNAPSHOT and C 0.0.2-SNAPSHOT) (inherits from parentPom 0.0.5-SNAPSHOT)
.
---module B 0.0.2-SNAPSHOT
(inherits from parentPom 0.0.5-SNAPSHOT)
.
— module C 0.0.2-SNAPSHOT
(inherits from parentPom 0.0.5-SNAPSHOT)

Here the new versions are set as usual, but modules that were not released are still updated too, to the correct dependency version and correct parent (O, C).

Another thought: maybe it would also be interesting to update modules A and B but not the parent (if you decide that the parent version should not change because its pom hasn't changed at all). In such case it is the same than for dependencies: previous version of the parent should be used.

Now I tried to reach this goal by creating profiles with partial subsets of modules, but this does not work well with current version of maven-release. Is by any chance such a fix planned ?


Stijn de Reede added a comment - 25/Feb/09 08:19 AM

+1

This is also a becoming a major issue for our development team. We're developing components for an ECM application. The multimodule project defines set of components linked together to be installed in a certain environment. When we update a single component, we want to make a new release of the multimodule project to be deployed to the Test environment. However, if we update a single component (=submodule) and release the multimodule project, every other component in it is also released and has it's version number updated.

Actually, the behavior I quickly thought of would be like this:

  • create an option like releaseUnchangedModules=false (defaults to true)
  • when you would run "mvn release:prepare release:perform" in a multimodule project, by default the release plugin would update the version number of each module from x-SNAPSHOT to x, do a release and set the new trunk version to (x+1)-SNAPSHOT. The aggregating project's version would also updated.
  • when you do "mvn release:prepare release:perform -DreleaseUnchangedModules=false", the release plugin could compare each module with the latest version in SCM. If the module hasn't changed, the version is set back from x-SNAPSHOT to (x-1). If it has changed, it is set to x. The new trunk version would be x-SNAPSHOT (unchanged) and (x+1)-SNAPSHOT (changed), respectively. The aggregating project's version would also updated.

Sylvain Marié added a comment - 25/Feb/09 08:33 AM

Hi Stijn,

This sounds like a good and very simple idea to me. However it does not cover the (ugly but frequent?) case where you have made changes to several snapshot modules in your trunk and only want to release some of them - the others needing some extra work to be declared as "released".

By the way if anybody has other ideas on the way to handle multi-modules please write them down here ; if we reach an agreement that is not too complex to implement I might find time to develop a draft patch.

In parallel I have asked Emmanuel Venisse for inputs on the dev. team's vision on this topic but I haven't received any reply yet.

Cheers

Sylvain


Stijn de Reede added a comment - 26/Feb/09 12:55 AM

Hi Sylvain,

I see your point, and I think this indeed might also occur with our development cycle. Of course you could add 'overwrite' parameters, like "-DholdbackModule=module1,module2 -DreleaseModule=module3,module4" but I don't think that's a pretty solution. It would be workable though.

Anyway, maybe we should switch from an aggregate project structure to a project that includes the other modules (components) as dependencies. That way, we would also have control over which version of a component is in a release to a target environment. Since components can be generic and be released to multiple target environments, maybe this is the way to go for us.


Moshe Bergman added a comment - 26/Feb/09 01:07 AM

To Stijn: It's not always correct that if modules are unchanged they should not be released, because sometimes if component X is released and Y depends on it, you would release Y as well, even though it's unchanged.

Seems the only way is to specify what modules to release.


Sylvain Marié added a comment - 26/Feb/09 03:28 AM

To Stijn: I don't understand how moving an aggregate project to a project with dependencies could do the trick.. You would probably need to update things by hand then ?

To Moshe: very interesting point. In such case I thought I would not release Y because from a code point of view it is the same. However for people compiling against it, it prevents transitive dependency to go and pick your new release of X so you might want to release it too to ensure that people benefit from new version of X.

> Seems the only way is to specify what modules to release.

I totally agree. Now the question is, how ? I suggest 4 ways to do it in a previous post ( 16/Jan/09, suggestions a),b),c),d)). Do you have other ideas ?


Moshe Bergman added a comment - 26/Feb/09 06:29 AM

In my projects we will not have fixed number of subsets, it will depend each time on changes and requirements. So I think files will not be good.

I suggest asking the user, like currently done for versions, as follows:
<module> is multi-module, select what to release: (A - All, C - Choose, N - None) (A):

For example:

Parent
Module1 (pom)
SubModule1
SubModule2
Module2
SubModule3
SubModule4
Module3

The following is a possible flow:
Parent is multi-module, select what to release: (A - All, C - Choose, N - None) (A): C
Module1 is multi-module, select what to release: (A - All, C - Choose, N - None) (A): C
Release SubModule1? Y
Release SubModule2? N
Module2 is multi-module, select what to release: (A - All, C - Choose, N - None) (A): A
Module3 is multi-module, select what to release: (A - All, C - Choose, N - None) (A): N

In this case the following would be released: Parent, Module1 with SubModule1 and Module2 (With all sub modules)


Sylvain Marié added a comment - 26/Feb/09 07:37 AM

Thanks Moshe, this is probably the simplest way to implement it, for sure. And nothing prevents us aferwards to implement the file-based one for enabling batch-mode releases.
Let's wait and see if other opinions are posted.
Otherwise I will try to patch it this way, probably in March or April depending on our project's load.

Cheers,

Sylvain


Christian Gleissner added a comment - 19/Mar/09 09:01 PM

Hi,

about a year ago, I wrote a Perl script which repeatedly called the Maven 2 release plugin to perform a release on a couple of projects which were dependent on each other. In the end, it worked very reliably, but it was a pain to get there as the release plugin was a bit unstable back then. Now, I am facing the exact same problem again in another project: performing automated multi-project releases.

It isn't an option for us to relate all the projects as sub-module under a shared parent POM as mentioned in earlier posts. This is because of the partial release problem mentioned above - we don't want to release all projects, but only specific subsets. Also, we don't want any interactive process requiring user input. Instead, everything should be controlled by an (XML) file.

Currently, we use a custom tool that gets configured via an XML file which contains the SVN URLs and target (post-release) versions of all modules to be released. It will then amend dependencies and POM versions to these target versions, thus eridicating all snapshot dependencies and preparing the stage for a lot of manual calls of the Maven release plugin. However, this is is still not as automated as we'd prefer, and each release takes us easily one to two days.

My intention is to automate this in the following way by using a multi release tool:

  • Build dependency graph based on one (or more) root modules to be released
  • Release all projects in the dependency graph(s), going from the leaves of the graph upwards towards the root(s). The releasing of each invididual module will be performed using the Maven release plugin. Recursive releases will be disabled as we need full control over which modules are released.
  • The new trunk versions and SCM URLs of all projects can be specified in a separate XML file which drives the releasing.

I think such a tool may very well be beyond the original scope of the Maven release plugin, as it focuses on multiple modules whereas the Maven release plugin is only concerned with a single module and its submodules.

Does anyone know whether such a tool already exists or is currently under development?


Sylvain Marié added a comment - 20/Mar/09 03:50 AM

Hi Christian,

I am glad to see that other development teams are faced with this issue too. I think that most of your needs could be covered by a maven-release plugin handling sub-modules correctly with an XML input file or an interactive behaviour about which sub-modules should be released (see Moshe's previous comment).

I have some doubts concerning the need for multiple root modules, though. Is it a need that you currently have in your projects ? I mean, I think you could just release one subtree of a root module, then one subtree of another root module, etc. Unless you have tight snapshot dependencies between projects that are located in separate root modules ?

Best regards,


Christian Gleissner added a comment - 20/Mar/09 04:54 AM

Hi Sylvain,

thanks for your reply. I agree - we don't need to release multiple top-level modules in a single call. However, there is an important difference between my suggestion and Moshe's previous suggestion:

I suggest that the multi-project release plugin uses the dependency graph to find modules to be released, rather than following module hierarchy. It would then traverse the graph and automatically modify any dependencies from snapshot to release versions. In the current release plugin, it only performs a validation to ensure these dependencies are all release versions.

So there would be three key components:

  • XML-based configuration to define groupId/artifactId and target release version of all modules to be released
  • Dependency graph traversal (optionally module graph traversal - not required in our case, but may be useful)
  • For each module discovered during graph traversal: Dependency adjustment from snapshot to release before invoking release:perform, and back to the next snapshot version afterwards

This could all be handled by either a new goal added to the existing release plugin or by a completely new release plugin to enable decoupled development. What do you suggest?

Thanks
Christian


Mark Struberg added a comment - 20/Mar/09 05:26 AM - edited

please note that not all SCMs support tagging of 'partial' trees of a SCM-module. e.g. for a Git repo a 'tag' always works on the whole repository and not on single files (in fact there is no such thing like a 'single file' for Git, but only diffs on the whole repository tree)

So you imho have to separate 4 different 'modularisation points'

1.) maven modules
2.) maven dependency structure (sometimes the maven modules do not represent the dependency structure, especially if more hierarchies are nested)
3.) file structure (how to handle 'flattened out' projects, or parent poms which reside in an own subdirectory?)
4.) SCM modules

Sadly, this is a really complex area...


Sylvain Marié added a comment - 20/Mar/09 08:19 AM
Christian:

a) In the current release plugin, it only performs a validation to ensure these dependencies are all release versions.
I think that the last version is now able to update the dependency in a smarter way: you can choose to make it update the version automatically. However the release version must exist: you need first to release it - and this is not done in the same process.

b) Although using the dependency graph to find projects to release might sound appealing, it seems to me that it is against the meaning of 'dependency' vs 'module'. Indeed imagine your projects depend of each other but have their own build cycle ; that is, they don't have a common aggregator project structure on top of them, they are build in separate "mvn install" commands. It means that one is a library for the other, they are not tightly coupled. They must therefore be released in two steps: first the 'low' one then the one built on top of it (thanks to (a)). However if you think that these projects are part of the same build cycle (built in one "mvn install") the release plugin should be able to release both att the same time.

> To sum up we would probably not want the maven release plugin to have to make a build that is more complex that what the "mvn install" build can do. We should play in the subset defined by the "mvn install" build IMO. Do you have the possibility to declare all your projects as modules of an aggregator one ? If so that would do the trick.

Mark :

You are right about the partial tags but in my opinion it is not problematic to TAG the whole repository, as long as the deployment of artifacts happening during the release-perform step only focuses on the modules that were selected. For the other modules, well the only thing that happened is that they were tagged one extra time in the SCM: not nice, but not a big deal ?


Sylvain Marié added a comment - 20/Mar/09 09:00 AM - edited

Below is a sum-up of our common requirements and decisions so far. Please don't hesitate to email me or post a comment so that I update this list, if things are wrong or missing.

Entry point of the maven-release command [EP]:

  1. One maven project (may be a simple project, an aggregator or a parent). This is because all traditional maven command have one project as an entry point.
  2. Should handle standard hierarchical structure (parent/aggregator pom in root dir) as well as flat structure (parent/aggregator pom in its own dir)

Impacted source files ( [sources] ):

I think we all agree that this is limited to the SCM where the entry point lies, for obvious simplicity reasons, and also because the only way for a "mvn install" to work on a fresh checkout of the entry point is that all sub-modules are part of the checkout as well, so are part of the same SCM.

Impacted maven projects ( [projects], subset of [sources])

  1. From the entry point [EP], retrieve a list of maven projects
    • from the aggregation graph
    • from the dependency graph (not relevant imo because we should play in a subscope of mvn install, but this point is still open)
  2. Other maven projects that would be part of [sources] are not considered

Released projects ( [released], subset of [projects] ):

  1. The user can choose which of all the [projects] will be released. see chapter about configuration

Pom updates (for SCM TAG):

  1. for each of the [released] projects, update its pom
    • update its version (release version)
    • update the reference to the parent module if it is in [released]
    • update the dependencies to other [released] modules
  1. for each project in [unreleased]=[projects]-[released] update its pom
    • update the reference to the parent module if it is in [released]
    • update the dependencies to other [released] modules

SCM TAG

  1. The release process should work even if TAGs can not be partially made (Git)
  2. a checkout from the TAG should be able to build (mvn install)! It is actually required by the release-perform step. So all projects required for a mvn install on the entry point should be here, even if they are not released.

Pom updates (New SCM TRUNK):

  1. for each of the [released] projects, update its pom
    • update its version (new snapshot version)
    • update the reference to the parent module if it is in [released]
    • update the dependencies to other [released] modules
  1. for each project in [unreleased]=[projects]-[released] update its pom
    • update the reference to the parent module if it is in [released]
    • update the dependencies to other [released] modules

Deployment of release in repository

No new relevant requirement.

Configuration to define groupId/artifactId and target release version of all modules to be released

  1. interactive configuration: when input is needed during the process, just ask (release or not? release version ? next trunk version?)
  2. file-based configuration
    • in the pom, define "release sets" under maven-release configuration and activate them with commandline or profiles
    • in release.properties
    • external file, e.g. XML-based. File selected using a command-line argument or in pom configuration
  3. the brand new -pl opion of maven 2.1.0 could also probably help us here

Sylvain Marié added a comment - 27/Apr/09 07:34 AM - edited

Hi everyone,

Concerning this topic we finally decided to give up and align with the "everything is a component" layout, where
1 SCM project(tag/trunk/branches) = 1 Maven project (1 pom of a component) and components become independent (no aggregator pom any more).

While this was clearly not possible for us with the old dependency mechanism (everytime a project wasreleased, you had to update all demendencies in other projects), this is not the case any more thanks to the scoped dependencies: a project A can depend on version [1.2,1.3) of another project B so that releases of bug fixes in B (1.2.1, 1.2.2, ... 1.2.n) will not impact A.

Best regards,

Sylvain