Maven dependencies with jenkins using incremental builds - maven

I have a multimodule project, with one of the sub-modules depending on another as this:
pom.xml (parent pom)
|
+---- pom.xml (project A)
|
+---- pom.xml (project B) depends on A
I'm building it in jenkins, using the option "Incremental builds" (Maven job type). My problem is that when only project B has changes (that implies that jenkins is building ONLY project B), Jenkins is downloading latest snapshot from project A, instead of using binaries present in "target" directory of project A (generated in a previous build).
If full build is triggered, the problem goes away, and Jenkins uses correct binaries.
Has anyone have the same problem?
Thanks!

its not a problem, its the way maven operates. artifacts are always brought from the repository, even for multi-module builds. if you build the whole tree you just dont notice because the artifacts pulled from the local repo are the ones your build put there just a few minutes ago.
you'll get the exact same behaviour if you opened a command prompt to project B's root dir and executed a maven build from the command line - maven would look for A in the local repository (and the remotes, if not found) and wont look in A's /target directory.
if this was standard maven you could use maven's also-make flag from the root directory and tell maven to build project B and all of B's dependencies, which would make maven also build A.

Related

maven pack too many jars to WEB-INF/lib, clear the local repository and re-execut mvn can make things right

In our company, thousands projects are build on 3 servers, with mvn commands.
A few projects occasionally pack too many jars to its WEB-INF/lib folder, the unwanted jars looks like another projects business code and its dependencies.
This is
the diff in WEB-INF/lib between right one(left) and too many jars one(right)
The jar in red frame looks like another project' jars, project name is "jd-common", and the other green jar on right is another project's dependencies.
This situation always reappeared until I clear local repository.
I guess the another project uses "mvn install" to install jars into local repository on build server, and our project is actually depend on jd-common-cached and jd-common-util only.
How can I avoid this?! Thanks for help.
First of all if the jars are there - you depend on them. You may depend on them implicitly (transitive dependencies). Run mvn dependency:tree to list all the dependencies (including transitive). You may find out that you depend on another project that in turn depends on those red/green jars.
Second, on the Build Server you don't want to share local repo with other projects. That's why, at least in Jenkins, there is an option Use Private Repository - this way all the project are going to be separated. This protects you from the situation when the artifact is not in remote repo anymore but the build is still green since that artifact is in local repo. But this has nothing to do with the problem you described.
It's finally be resolved!
The project A depend on a jar which deployed by another project B, the depend jar is a sub-module in B. (A->B)
Unfortunately:
1. A and B are packaged on the same build server
2. B's sub-module jar has the parent config in its pom.xml.
3. B use "mvn clean install -DskipTests" as the build command, so all the B's modules are installed in local repository.
Maven always package the local installed jar, and use the installed jar's pom file to find the sub dependencies, so when maven is executed, project A found that:"one of my depended jar has a parent, it's B, and all the B's sub-modules are found in local repository because of B installed all of them, I should package them all!".

How to run a maven plugin without a POM in Jenkins?

I have a plugin which can run either using a pom.xml or without (depends upon the version of the artifact we're building: new versions go without a pom. Strange, I know).
I want to have that plugin run in Jenkins.
But when creating a maven project, I have to set a pom (or as a default, Jenkins suppose there is one in the base folder given).
Question: Is it possible to configure Jenkins to not use a pom when there is none?
As per my comment, you should use a Jenkins freestyle project build in this case, in order to have more flexibility and avoid the default assumptions of a Jenkins Maven build.
In such a build, you can then configure a build step executing a shell or a Windows command (depending on the Jenkins server OS).
Indeed, in the Jenkins Maven build, a pom file is always required, as mentioned in the help support of the Configuration > Build > Root Pom entry
If your workspace has the top-level pom.xml in somewhere other than the 1st module's root directory, specify the path (relative to the module root) here, such as parent/pom.xml.
If left empty, defaults to pom.xml

IntelliJ uses snapshots with timestamps instead of -SNAPSHOT to build artifact

I have a project with snapshot dependencies. For simplification let's say that there is an project A which depends on library B-0.1-SNAPSHOT.
A depends on B
B resides within Nexus repository as a snapshot. I can see that it is stored with timestamp so the actual name in Nexus is something like: B-0.1-20141126.171716-67.jar
After executing:
mvn clean install -U
on project A, dependency B is downloaded from Nexus to my local repository. There I can find two jars of library B:
B-0.1-SNAPSHOT.jar
B-0.1-20141126.171716-67.jar
So far so good.
After maven build is complete I can see that B-0.1-SNAPSHOT.jar was taken to build A artifact (.war file)
I also have project A imported to IntelliJ as a maven project. There I run it on Tomcat. Project is build by IntelliJ and B-0.1-20141126.171716-67.jar is added to .war file.
At the end I have .war with both B-0.1-SNAPSHOT.jar and B-0.1-20141126.171716-67.jar within WEB-INF/lib directory.
For me is seems like a bug in IntelliJ because B-0.1-SNAPSHOT.jar should be taken from local maven repository... not the timespamped version. Is there any way to force IntelliJ to act propeply?
Maven version is 3.2.3, IntelliJ 14.0.1 (but the same behavior was on 13).
I was faced to the same problem today, and I found how to disable this feature.
F4 on your module, and go to artifacts then select the name of your artifact webapp:exploded and check the show contents radio at the bottom of the frame.
Go to WEB-INF/lib and search for your dependecy B-0.1-SNAPSHOT.jar and expand the line you will see a compile output folder in it, just remove it, then repackage and run, you will now only have the B-0.1-SNAPSHOT.jar and the one with the timestamp should be gone.
The downside of this is that you will have to make sure to mvn install your B module before running the A module within IntelliJ, because IntelliJ won't package your dependency and bundle it with the code you've just edited but not installed in your local maven repository.

Maven: Change the "test" phase directory from local .m2 to target?

Forgive me if this is remedial, but I am still new to Maven and it's functionality.
In my project, when it "builds" and gets to the compile phase, it will create a target directory with just compiled libraries and update (or create if not there) the local .m2 directory.
When I get to the "test" phase, I want it to build against the target directory's library files, and not the local .m2 directory.
Any hints, recommendations, or suggests would be greatly appreciated. Thanks!
Maven has this concept of “the reactor”, which is just a fancy term for the list of projects being built. At the start of a Maven build, and at the end, Maven prints out this list of projects (using /project/name if defined or groupId:artifactId otherwise).
For each project in the reactor, Maven maintains a list of artifacts that have been attached. By default, each module's pom.xml is attached, and as each plugin runs, they have the option of attaching additional artifacts. Most plugins do not attach artifacts, here are some plugins that do:
jar:jar creates a .jar and attaches it
war:war creates a .war and attaches it
source:jar creates a .jar of the source Java code and attaches it with a classifier of source
java doc:jar creates a .jar of the JavaDocs ad attaches it with a classifier of javadoc
There is also a default primary artifact (this is the one that gets replaced by jar:jar) which is actually a directory and not a file, as such it will not get installed or deployed to the local repository cache or a remote repository.
So when in the reactor, and a plugin that attaches the primary artifact has not run yet, and another plugin asks for the primary artifact, it will be given the directory ${project.build.outputDirectory}. If after the primary artifact as been attached, then that primary artifact will be provided.
The test phase happens before the package phase, so will use the directory and not the .jar. The integation-test phase happens after, so will always use the .jar.
Things get more complex in a multi-module project (which is where my long intro should help you out)
Maven has to build the test classpath. If one of the dependencies is within the reactor, Maven will use the artifact attached to the reactor. Otherwise it will use the local cache (populating from the remote repositories if necessary).
When you run
mvn test
In a multimdule project from the root, there is no replacement of the default (directory-based) artifact, so intra-module classpath will be to the target/classes directories.
When you run
mvn package
In the same project, however, because each module completes its life cycle sequentially, all the dependent modules will have swapped in their .jar files as their attached artifact.
All of this should show you that Maven is doing the sensible thing. Hope this has helped.
The test phase is going to execute tests on your project. The project won't reference itself via the dependency mechanism. Only dependencies will be referenced via your local repository, i.e. .m2/repository
Also, it's not the compile phase that installs the artifact to the local repository, it's the install phase. And, then, there's a later phase, called deploy, that will deploy the artifact to a remote repository, provided you have a remote repository configured as the deploy target. Note, install and deploy are nearly identical phases except install is a local only thing; thus, it's the common build phase to hit when doing dev environment work. Normally the build server will do the deploy stuff.

Independently building Maven submodules

After being introduced to Maven in my most recent project, I've been experimenting with it for the past couple of weeks.
I currently have a multi-module project in my development environment. Project "A" and Project "B" are child modules of Project "root", with B having a dependency on A.
I am aware that I can build B independently by using mvn reactor:make... as outlined here. However, I'm curious as to why am I not allowed to build B from inside B's root folder.
To illustrate this, I first built A independently by running a clean install from within A's root directory. However, when I tried doing the same action from B's root directory, Maven reported an error as below -
Could not find artifact org.divesh.mavenrnd:root:pom:1.0 in central
It looks like Maven is not able to resolve the parent's POM file. Any thoughts on why this is happening? From my initial understanding of Maven multi-module projects, the main reason to split a project into sub modules is to share dependencies. This should not, however, prevent me from building a particular module independently from within its folder.
Thanks.
EDIT
Ran an mvn -N clean install to install only the root project's POM in the rep. After this, I was able to successfully build B after building and installing A. There is still one thing I'm not quite clear about -
Assuming I've installed the root project's POM in the repository, if I try to build A, does it refer to the parent root POM directly above it or the POM that is installed in the repository?
That's right. The error you mentioned tells you that maven cannot find parent's pom.
You have 2 options here:
First call mvn -N install in your root project directory to install parent pom to your local repository. Then you can go to B's directory and build the submodule.
Specify <relativePath> in your submodule pom. By default maven will look for parent pom only one level up the file system. If you have other directory structure in your project, you have to specify this option in order for maven to locate your parent pom.
Here's a sample:
<parent>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<relativePath>../../pom.xml</relativePath>
</parent>
You should use mvn -pl ProjectToBuild lifecycle like from the root of your tree:
mvn -pl module-b package
You shouldn't use mvn reactor:make anymore. Except you are using maven 2.0
If you wan't to be sure that everything is depending on module-b is build as well you should use:
mvn -amd -pl module -b package
The best is having a folder layout which represents the appropriate structure of your project and not using relativePath is necessary.

Resources