Maven multi-module project and Jenkins - java

I have the following projects organized in a flat structured way:
parentProject
+-pom.xml
projectWeb <depends on libraryA and libraryB>
+-pom.xml
libraryA
+-pom.xml
libraryB
+-pom.xml
The pom.xml inside the parentProject has references to the other modules and its used for inheritance and dependencyManagement, here is a snippet:
<project>
....
<modules>
<module>../projectWeb</module>
<module>../libraryA</module>
<module>../libraryB</module>
</modules>
<dependencyManagement>
...
</dependencyManagement>
<build>
...
</build>
....
</project>
In Jenkins I have one maven job for each project, and it works fine when I build the parentProject, ie. builds every project referenced in the modules section.
The problem that I have is when I commit to the SVN a change in libraryA, I would expect that after building libraryA, a rebuild to projectWeb to be launched, but that didn't happen.
Anyone knows what am I doing wrong?
Thanks in advance.
EDIT
When I remove the modules section from parentProject\pom.xml, it works as espected, but I loose the aggregation advantage of having a parent pom.

It looks like you're asking your parent POM to do two things:
Set up dependency management stuff
Aggregate your build
It's generally better if you split this out into two poms - a parent pom for #1 and an aggregate pom for #2. You'd then have something like..
[root dir] aggregate pom.xml
+ /parent
+ /web
+ /libA
+ /libB
See this answer for more details: https://stackoverflow.com/a/3301162/211993
You'd then configure Jenkins to check out the root dir and run "mvn clean install"

This should be configured in jenkins job. See "libraryA job"/"Configuration"/"Build Triggers"/"Build after other projects are built"

Related

How to include the modules in a top-level POM in another project?

I've googled and stack-overflowed everything, but maybe not enough as I'm still not clear how one adds a module of a Maven project as a dependency in another.
So for example let's say we've got:
MajorPager
|___ POM.xml
|___ chuck-commons-core
| |____POM.xml
|____rajni-commons-core
|____POM.xml
Now I want to add chuck-commons-core but not rajni-commons-core. If I do it directly, it can't find the module. So I ran across the following discussions on stack-overflow and my old friend Guggal:
In summary, the below discussions talk of how to create multi-module projects but not really how to include the sub-modules in a top-level POM into another project.
Useful discussions for context
SO Adding a reference to a parent POM project
SO How to add a parent POM as dependency to a different maven project
SO Adding a reference to Parent POM
SO Maven Parent POM vs Modules POM
SO Depend on multi-module aggregator project
SO How to add dependency in Eclipse?
SO How do I configure Maven multi-module-dependency on sub project with different package?
SO How to add a module in parent projects POM as dependency?
SO How to add a dependency in Maven?
Maven dependency mechanism
Maven POM aggregation
Baeldung Multi-module project
Codetab Maven multi-module
Howtodoinjava Maven parent child POM example
Mastertheboss Maven multi-module tutorial
Codetab Multi-module hierarchical project
Sonatype How to share resources across projects
Spring Multi-module project
Concretely, I'd just like a summary from an expert how they add a sub-module of a Parent POM as a dependency to another project.
As of now, I think this is the best solution - to add the following ccodee to the POM.xml of the MajorPager.
Code block 1 incoming
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.teachme.how</groupId>
<artifactId>MajorPager</artifactId>
<version>0.6-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Code block 2 incoming
<dependencies>
...
<dependency>
<groupId>com.teachme.how</groupId>
<artifactId>norris-commons-core</artifactId>
<version>0.6</version>
</dependency>
...
</dependencies>
When you do so enables Maven to find out where the dependency are - and so Maven picks them up with mvn clean -U install or mvn package -U -DskipTests. And I should like to be educated if this isn't the most effective pattern. Or if any of the fields above are optional that Maven doesn't want me to specify because it can derive it on it's own (say for example, version tag?) - please let me know if that's case as well.

Submodule dependencies with Maven

I have a project structure like:
However, whenever I run mvn clean test -DskipTests from the Project 1 directory, it ends up NOT including the Project 2 module in the Maven reactor even though I've listed it as a dependency in Project 1 as follows:
<dependency>
<groupId>com.main.sub</groupId>
<artifactId>project2-artId</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
What could be happening and why isnt the dependency being recognized?
From https://maven.apache.org/guides/mini/guide-multiple-modules.html; the reactor "Collects all the available modules to build". (modules of the project that is currently being built)
You need to: create a parent project, with packaging pom; add two modules to this project (one for Project1, one for Project2), and submodules for project1.
Then, when you build the parent project, the build order for all modules are decided by the reactor-

How to pass maven "--also-make" option via pom.xml to command line

Let`s say there is a parent project A that has modules B and C in its pom.xml.
Project A
|-pom.xml
|----------->ModuleB
| |->pom.xml
|----------->ModuleC
| |->pom.xml
<modules>
<module>B</module>
<module>C</module>
</modules>
The module C itself has some dependency that belongs only to this submodule. This dependency should be built before module C, so I want to call "-am" (--also-make) option when "mvn install" is called for C.
Maven is being executed remotely, all I have is pom files. Build job runs on remote Jenkins, it uses the current profile in project A parent pom, only this profile must be used.
I though it can be done in module C`s pom, in configuration of maven-compiler-plugin, for example?
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${jdk.source}</source>
<target>${jdk.target}</target>
**<arguments>-am</arguments>** <!--smth like this maybe?-->
</configuration>
</plugin>
I also thought about creating another pom.xml to have only submodule C and its dependency in the right order, and to be used instead of current submodule C in parent pom, but want to try -am option first. Besides, I do not quite see now where to put this new pom, because we are already at parent A level.
Probably the whole project structure should be refactored, but it is what I have for now.
Upd: below is less simplified current project structure.
Project A (maven parent for B, C, D)
|-pom.xml
|----------->ModuleB
| |->pom.xml
|----------->folder
|----------->folder
|----------->ModuleC
| |->pom.xml
|----------->ModuleD
| |->pom.xml
<modules>
<module>B</module>
<!-- <module>D</module> | initially was here, now needs to be only C's dependency -->
<module>C</module>
</modules>
--also-make option can be used when projects specified are also listed in the modules section of the aggregator(reactor) pom.xml. Since you don't have the required projects in your modules section You can't use it in your current setup.
You can just add the extra projects to your current modules section and this will fix your problem. (You don't have worry about order of modules you write, Maven will build them in the correct order for you. And you don't have to use also-make)
You can also use the solution you suggested in the question. It does not have to be parent of C, It can be just the aggregator of C and its dependencies.( I don't think this is neccessary. You can just add all of them to your current modules section)
Also parent pom and aggregator pom are different concepts.

Maven Modules with Variable as Version number

I got a Maven project with the following structure:
Module A (parent), Submodule B and Submodule C
In the parent pom.xml I am using a variable for settings the version of all projects:
...
<version>${revision}</version>
...
<properties>
<revision>1.1</revision>
</properties>
...
<modules>
<module>moduleB</module>
<module>moduleC</module>
</modules>
</project>
Module C is my distribution package which uses the shade plugin for packaging everything into one single jar.
In the submodules I set the parent like this:
<parent>
<groupId>group</groupId>
<artifactId>moduleA</artifactId>
<version>${revision}</version>
</parent>
Now I want to use Module C in another project, however I only get the following error when doing so:
Failed to execute goal on project newProject: Could not resolve dependencies for project group:newProject:jar:0.0.1-SNAPSHOT: Failed to collect dependencies at group:moduleC:jar:1.1: Failed to read artifact descriptor for group:moduleC:jar:1.1: Could not find artifact group:parent:pom:${revision} in nexus (NEXUS_URL)
I assume the problem is, that the variable value is not filled in when referencing Module C as dependency. How can I solve this issue? I already tried to clean the project before building and forcing to update all artifacts without success.
Maven expects all modules to have a hard version.
To avoid editing lots of poms, use the versions plugin, example:
mvn versions:set -DnewVersion=1.0.1
If you run the above command on the parent it will fix all the child poms.
See here for documentation.
Thanks to the comment of hadu.mansouri I could fix it. I used flatten-maven-plugin for flattening the pom.xml files. However, it seems to have a problem with the shade plugin, as the shaded module was the only module where it did not work. Thus, in the released shade module pom it said:
<version>${revision}</version>
for referencing the parent. I used the approach of the article linked in the comment. There, this extension was used: https://github.com/jcgay/unique-revision-maven-filtering
Using this instead of the flatten-maven-plugin, Maven builds the multi module project correctly with the single version property, and I can also use the shaded module in other projects properly.

How to restructure Maven multi-module project?

I appologize for the length of this post, but I had trouble making it more concise without presenting the picture. I've recently inherited the job of build-master for a maven 3.0 multi-module project. The problem is that the structure of the project/modules is a disaster. From the way things are currently stored in Source Control (we use RTC) to the pom structure of the modules, I'm tearing my hair out trying to get a full build cycle completed each time.
As a project hierarchy goes, all the modules are stored "flat"; ie: everything is at the same level. I have a parent pom, and all modules depend on the parent. However, the parent is at the same level as all my other modules.
Ex:
c:\dev\MyEarProject
+ parent-pom
- pom.xml
+ module1
- pom.xml (depends on parent-pom)
- src
- main
- ...
+ module2
- pom.xml (depends on parent-pom)
- src
- main
- ...
+ module3
- pom.xml (depends on parent-pom)
- src
- main
- ...
The parent pom defines all the modules required to build the project, as well as a bunch of properties for artifact version numbers used throughout the different submodules:
<modules>
<module>../module1</module>
<module>../module2</module>
<module>../module3</module>
</modules>
<properties>
<org.springframework.version>3.0.5.RELEASE</org.springframework.version>
<slf4j.version>1.6.4</slf4j.version>
<repositoryAddress>${snapshots.repo.url}</repositoryAddress>
<my.hibernate-module.dao.impl>1.2.3</my.hibernate-module.dao.impl>
<my.hibernate-module.dao.api>1.2.3</my.hibernate-module.dao.api>
</properties>
Each module's pom, in turn, depends on the parent pom via the pom's artifact number:
<parent>
<groupId>com.cws.cs.lendingsimulationservice</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.6</version>
</parent>
To make things even more confusing, the actual artifact name may, or may not (depending on the module), match the module path. For example, module1 may be located in path c:\dev\MyEarProject\module1 but have artifact name hibernate-module. However, due to the way it is stored in RTC, the directory is called module1 when it is checked-out.
The easiest way to build everything, of course, is to go into c:\dev\MyEarProject\parent-pom\ and run mvn clean deploy. This works fine when in SNAPSHOT mode as the SNAPSHOT repo allows for multiple deployments of the same artifact version. But in release mode, this fails.
This structure is causing 2 problems for me.
Everytime I need to make a version change to a property in the parent, I have to update the parent-pom version number, and all the child modules parent pom's version, and all the child modules version themselves (since the parent changed).
Whenever I need to deploy a release cycle, mvn will throw an error if one of the modules has not changed since the last cycle and consequently cannot be redeployed to the same repo (the repo does not allow overwriting existing artifacts)
So I'm looking for the best way to restructure this project to avoid these problems. For the parent pom, I know I can use a relative path to point to the parent instead. However, given the "flat" structure of the modules, is this a recommended approach (ie: the parent pom relative path would be ../parent-pom/pom.xml - seems a little odd to me)? Additionally, given that the versioning control of the parent is independent of the modules, would using a relative path not just open the door to additional confusion (ie: there would be no way to know which version of the parent pom is associated with which version of the submodule).
Secondly, how can I build the entire ear without encountering the deploy errors I am having? Since the artifact already exists in the repo, I don't need to rebuild and redeploy it. I tried using --projects but with the number of modules involved, it gets extremely difficult to manage.
The first thing I really recommend is to restructure the projects folders ...which means to have the projects folder represent the structure which means NOT flatten the structure.
+-- parent-pom (pom.xml)
+--- module1 (pom.xml)
+--- module2 (pom.xml)
+--- module3 (pom.xml)
As a result of that the modules section your parent will be simplified like this:
<modules>
<module>module1</module>
<module>module2</module>
<module>module3</module>
</modules>
Furthermore the parent entries in your modules can be simplified as well like this:
<parent>
<groupId>com.cws.cs.lendingsimulationservice</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.6</version>
</parent>
...which brings me to the next point:
If all your current project define their parent as above this is simply wrong, cause will try to find the parent within the repository and not in a upper level folder. In other words this is causing of much of your problems with releasing etc.
If we would fix this problem it has to look like this which I can't recommend:
<parent>
<groupId>com.cws.cs.lendingsimulationservice</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.6</version>
<relativePath>../parent-pom/pom.xml</relativePath>
</parent>
An other thing which I observe is that you don't use SNAPTSHOT's which will be replaced by the release plugin during the release phase. And in relationship to that it will automatically change all versions in the appropriate parents etc.
In ideal case your modules should look like this:
<parent>
<groupId>com.cws.cs.lendingsimulationservice</groupId>
<artifactId>parent-pom</artifactId>
<version>1.0.6</version>
</parent>
<artifactId>module-1</artifactId>
<!-- No Version or groupId -->
Cause all modules will inherit the version and groupId from their parent. Sometimes it's useful or needed to change a modules groupId but it's an exception.
On thing I reread is about the separate versioning of the parent. This simply does not make sense, cause it's the parent of their modules so put it into the same structure and of course the same VCS.
If you want to make some configuration/plugins versions, dependencies which should be used for other projects as well than make a separate corporate pom.xml which is a separate project and will be separately released etc.
After you finished your structure changes you can simply go into the parent-pom directory and do mvn clean package or mvn release:prepare release:perform from that folder and everything will simpler.
If you're publishing your POM, you'll have to release any updates but you don't need to modify POM versions by hand - you can update versions automatically using the versions plugin or the release plugin. I tend to prefer the release plugin as it'll commit to SCM for you too.
mvn versions:set
http://mojo.codehaus.org/versions-maven-plugin/
mvn release:prepare release:perform
http://maven.apache.org/plugins/maven-release-plugin/
Your repository manager may also allow overwriting an existing version but it's better practice to just release a new version.
I tend to prefer the flat module structure as it allows use of the parent folder to store common files e.g. checkstyle configuration. I also find it useful to share the group id across modules then name the module directory the same as the artifactId.
You are presenting contradicting requirements. You want to restructure your project but can't move things around. You want to simplify your deployment and release cycles but do not want to use a single version.
Given that changes in one module will inevitably affect all of the dependent modules, I would use a simple version'ing scheme where all the sub-modules inherit their parent's version. maven release:prepare and release cycles become simple. Use a release notes to track your changes and justify skipping unnecessary testing of unchanged modules (changes to a version do not change the build/binary output of the build process so you can use that as your primary argument).
Good luck with your project.

Categories