Best maven practices for modifying built war-file with generated resources - maven

Currently I'm working on integrating grunt build process to our maven build process.
Here are two options I can think of:
Pointing some folder in resources as a target build dir for grunt project.
Building grunt project wherever and enlisting this this non-standard folders as included resources in the pom.xml.
It looks like there is yet some space to enhancement. Basically, since grunt subproject
does not depend on any external resources, it would be nice to learn how not to rebuild war-file that had been already compiled, but modify it after rebuilding grunt-project.
So, the question is:
What are the best practices adding generated resources to an existing war file.

The approach of adding resources to a war file amounts to modifying a maven-built artifact after maven builds it. That runs counter to the maven philosophy of tightly controlling the entire build of every artifact. You really have three choices:
Include the grunt generated source in the war's source and build a single artifact with maven. In this case you rebuild the war every time grunt resources change, or
Put the grunt generated sources in a second maven artifact and make that artifact a dependency of the war artifact. Maven will still rebuild the war every time, but you get the separation of builds you seem to be implying in your question, or
Make the dependency in (2) a runtime dependency, if possible. You basically make the scope of the grunt artifact dependency "provided" so you don't have to rebuild the war every time your grunt artifacts change. You only have to rebuild your grunt artifact.
It sounds like you want to go with option (3).

A war file is just a zip file with a certain file layout, you could just add to the archive using a zip tool. For example my linux platform zip command has the -g command.
-g
--grow Grow (append to) the specified zip archive, instead of creating a new one. If this operation fails, zip attempts to restore the
archive to its original state. If the restoration fails, the archive
might become corrupted. This option is ignored when there's no
existing archive or when at least one archive member must be updated
or deleted.

Related

target folder vs local repository

I know that Maven houses the outcome of the build in the local repository (artifacts goes installed under ~/.m2/repository/), but it also outputs the compiled classes in the target folder next to src.
Is there any difference between what goes in the local repository and what goes in the target folder?
They are completely different and shouldn't be mixed up.
target represents the build directory. This is to say, every temporary file that is generated during the build from the sources ends up there. Quite notably, you'll find the compiled classes of the main and test Java sources, but you'll also find lots of things in there (generated source files, filtered files, etc.). What matters, is that everything that is contained in this folder is inherently temporary. You can delete it at any time, running mvn clean, and be assured that the next build will (or at least should) work just fine. All the files and folders generated under target serve a single purpose: create the artifacts of the project. A Maven project, for example with jar packaging, will have a single main artifact, which is composed of its final name with a jar extension, and will contain the compiled Java classes. The final name can be a custom name, set within the POM, or the default one derived from the Maven coordinates of the project. Such a project can also have additional attached artifacts, like a test JAR, or a sources JAR.
The local repository only contains the artifacts. There are no temporary files in there. What is installed when running mvn install is strictly the generated artifacts of the Maven project, i.e. the end products, plus the POM file of the project. Everything that served to create them isn't put in the local repository, and the build of a project must never put temporary things in there. Keep in mind that the local repository is a Maven repository, and, as such, follows a strict naming scheme: a project with a group id of my.groupid, an artifact id of my-artifactid and a version of 1.0 will get installed in the folder my/groupid/my-artifactid/1.0; in which you'll find the POM file, and all the other artifacts. The name of the artifacts themselves cannot be overriden: it will be my-artifactid-1.0.jar for a JAR project (perhaps with a classifier added).
This is generally a source of confusion: the name of the main artifact file that is generated under the target folder is completely distinct from the name that it will have in the local repository when installed, or in remote repositories when deployed. The first can be controlled, but the latter is defined by the naming scheme of the repository, which is calculated from the coordinates.
To recap: target contains all the gory temporary details during the build which creates the artifacts of a project (main JAR, sources, Javadoc... i.e. everything that is supposed to be deployed and released by that project), while the local repository (and remote repositories) will contain only the artifacts themselves.
Not much in terms of the generated module.jar if that's what you are really concern about. The .jar generated is the same, also considering recompiling the code would clean your /target folder but not the .m2 one.
Though /target folder would generally be composed of the compiled source classes /target/classes and /target/generated-sourceetc along with a module.jar.
On the other hand the local ~.m2/repository would consist of module.jar along with the pom.xml for that module and all the configs(repositories, dependencies etc) to rebuild that module from if required.

How to download maven dependencies from Jenkins without a binary repository

Are there any plugins or ways to download the dependencies for a maven project from Jenkins? I am using Jenkins for a multi-module desktop application. Although I know I could just archive all dependencies, I don't see why there isn't the ability to download dependencies using maven which installed on the same machine as Jenkins. Preferably one would specify the location of a pom and then have the ability with one click to download all the dependencies for that pom. Can you do this? I do not need or want an entire binary repository for this feature.
Edit: I will try and rephrase this as I don't think people are understanding.
In Jenkins one has the ability to archive artifacts at the end of a build. Also in jenkins you have integration with maven. When building a jar in maven you have arguablly 2 options:
You can either use the assembly plugin which zips all .class files
together with those produced from your source code resulting in 1 jar
You can create a jar just source code which references all
dependency jars which are located in a separate folder.
In Jenkins one also has the ability to download the latest artifact. Now if I am using Option 2, I can either archieve just the jar which my sources produced, which I would say is more desirable for space and is the whole purpose of the archive functionality, or you can also archive the libraries too.
Here is the PROBLEM!! If I don't archive the libraries then I cannot easily run this jar, as it is a desktop application and its dependencies cannot be obtained in the same mannor as clicking on a link from jenkins. So lets say my question is what is the easiest way to obtain them? Extra info: assume jenkins is running as a server and you can't use artifactory or another server application, that seems to me to be massive over kill.
Use the maven plugin and create a maven job for your project. Jenkins will then use the maven command you provide in the job configuration to build the project. This means maven will download the projects dependencies and store them on the machine jenkins is running. Normally this would be <JENKINS_HOME>/.m2/repository. This way you get a local repository that only contains the dependencies of the projects you created maven jobs for.

How to add ChargifyNET as a dependency to a TeamCity project?

We have recently switched to TeamCity 7.1.4 for our automated build system and attempting to add ChargifyNET dependency to an existing project. I have read up on the Build Artifact concept and the Dependent Build concept and they both seem pretty straight forward. However, the documentation really isn't clear on how to add a dependency that you do not need to build/compile.
Ideally, I would like to store the archive containing the ChargifyNET binaries in a folder and be able to reference that archive as an artifact when configuring dependencies for my project. How can I set this up?
So far, I've configured a separate project for ChargifyNET and declared the individual binaries from the archive as artifacts for this project (for example, %teamcity.agent.work.dir%/Chargify.NET/1.0.7/ChargifyNET.dll). Then I added a dependency to the main project for the ChargifyNET project artifacts.
When I build the main project I get a "Artifacts resolving failed" error. In the build log, under "Resolving artifact dependencies" I see no mention of the ChargifyNET artifacts.
How can I add ChargifyNET as a dependency to a TeamCity project? Do I need to get into a custom Ant script or can this be done from the UI?
Maybe the issue is with the artifact paths. Should 3rd party libraries be stored under the agent work directory or some other folder?
Is it best practice to have all 3rd party libraries checked in to a VCS repository? Perhaps a different solution would be to add an additional VCS root to the main project that points to the VCS repository holding 3rd party libraries.
Creating the Chargify.NET project as mentioned in the question was on track.
Create a build configuration under this project and enter a static build number (i.e. 1.0.7).
You have to "Run" the Chargify.NET build so TeamCity will create a dynamic build folder for it in the agent work directory.
Copy the Chargify.NET binaries into the folder created in step#2.
Modify the artifact path(s) from "%teamcity.agent.work.dir%/Chargify.NET/1.0.7/ChargifyNET.dll" to just "ChargifyNET.dll". This new path should refer directly to the files mentioned in step#3.
Modify the artifact path(s) in the Build Dependencies section of the main project to for Chargify.NET. They should look the same as in step#4 except that you may want to add a destination path (like so "ChargifyNET.dll=>trunk/bin").
Build the main project and you should see the files importing correctly.

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.

How do I get Maven to check if source code has changed before deciding a dependency is resolved?

Maven does a lot of neat things, but I find my self having to "mvn clean" far more often than I would like. It quits doing its dependency resolution/up-to-date check as soon as it finds the jar file for foo-0.1.0-SNAPSHOT in my local repository, even if the source code for that jar has changed. Having to purge everything (or go through each of the affected directories myself) every time I make a change in the next directory over is getting old.
I want a way to flag my intra-project module dependencies to tell Maven "Hey, this is built locally so don't use the foo.jar from ~/.m2 until you've checked that foo's sources haven't changed and rebuilt it if necessary." This is way easy in Ant, but I haven't figured out the Maven way to to it.
In a multi module build that is set up correctly it will just do what you want fine. This is referred to a reactor build. It just depends a bit on your setup.
If you have separate projects it will always get its dependencies from the local repo so you will have to make sure they get there by building them. You can either do that manually or create a multi module pom that ties things together.
The project which creates the foo-0.1.0-SNAPSHOT should do a
mvn deploy
everytime it has changed something. And than you will be able to get the changes simply by doing an other mvn clean compile in the project which use the foo-0.1.0-SNAPTSHOT as dependency.

Resources