Maven in our development process. Part 3 - Configuring Maven projects
Sherali KarimovFebruary 27, 2008
Setting up your infrastructure is just one part of the process. The other part, and in some ways a more important one, is about how you set up your projects. A Maven project is configured through its pom.xml - also known as simply a POM. Among other things in this file you specify:
- Maven plugins you use to build your project and their versions
- configuration of some of the plugins
- repositories to deploy our artifacts to
- details of the release procedures
We wanted to specify generic enough bits of the above information in one base POM that everyone would then reuse.
This is important in order to make sure that every time someone runs a Maven build on one of our projects - it runs exactly as it should. In other words - we wanted to minimise the dependency on Maven plugin updates and environment differences.
In the base POM we also enforce (to certain degree) version requirements for JDK, Maven and other tools the build might depend on.
Instead of one super POM, we came up with a little POM hierarchy. Yes, you can use inheritance with Maven POMs.
Our POM hierarchy starts with a base POM.
The base POM contains the bulk of the configuration. Among other things it configures:
- Maven plugin versions
- a WebDAV extension for proxy and repository access.
- the Maven JavaDoc plugin for the release phase
- the details of publishing a Maven site for our libraries
- workarounds for some known issues of Maven plugins
- some of the Maven plugins such as Clover, compiler, unit test / surefire, IDEA etc.
The base POM is usually not used directly on its own. Instead we have extensions for each type of libraries we deal with:
These extend the base POM and configure their respective repositories to deploy to by default. There is an exception however. The closed source POM has some additional configuration trickery to split the deployment of sources into our private Maven repository since Maven does not support more than one repository for deployment.
Some general guidelines
Since most of the stuff is already configured in the base POMs, the developers responsibility is simply to maintain project specific configuration. Apart from the usual name, version, description and dependencies this only means to make sure that the SCM information is correct.
Dependency management is, of course, a responsibility of the project developers. However James, our Release Engineer, has been looking at various ways of automating some of that tedious process.
We also started playing with the Maven changes plugin that will generate a changelog from the relevant JIRA project. When we roll it out this will mean every project will have to have an issueManagement element correctly set up in its POM too. (issueManagement is another Maven configuration option that specifies where the issue tracking system for this project is. Therefore upon release it will be possible to retrieve the list of issues that was fixed for this version of the project)
More complex projects
We have a lot of common modules that can simply extend one of the base POMs. They are self-contained individual libraries that products depend on. However, for products themselves such an approach is suitable. Each product contains a few sub-components that have to be built together.
For products we use Maven aggregation. There is a parent POM for each product that specifies modules for each product sub-component. The product POM specifies a version for each dependency, SCM information, variables that sub-components share etc.
The modules reflect the natural components of the product. We did not have to do any extra decomposition for Maven. For example you can consider the following. Each product might have a web-interface part. This normally contains the UI code, velocity templates, JSPs, CSS etc. This is one module called confluence-webapp for example. There might be another module that contains specific APIs or implementation. This is another module that bears a relevant name.
Once organised that way all you need to build and package the product is call a Maven goal at the top level and each module is built and packaged according to its own POM. If you even need to upgrade a specific dependency - you only have to do it in the product level POM.
Archetypes
We also have set up a few Maven archetypes. This is mainly done for plugins since you are definitely going to need to start new Maven projects when writing a plugin than in product code.
We have a Confluence plugin archetype and JIRA plugin archetype available on public SVN and documentation on how to use them. Archetypes for the rest of the products are coming up fairly soon as well.
Once there is an archetype, setting up a new project is a command line away:
mvn archetype:create \
-DarchetypeGroupId=com.atlassian.maven.archetypes \
-DarchetypeArtifactId=confluence-plugin-archetype \
-DarchetypeVersion=6 \
-DremoteRepositories=https://maven.atlassian.com/repository/public/ \
-DgroupId=$MY_PACKAGE$ -DartifactId=$MY_PLUGIN$
One of the main benefits of these archetypes is that they are pre-configured to run functional tests. If you have written some tests that will run against a live instance of the product - all you need to do is call:
mvn integration-test
and a new instance of the product will be fired up locally on your box, tests executed against it and the instance shut down.
Plugin archetypes are also pre-configured to deploy your plugin to either contrib or contrib-snapshot repository as appropriate.
Maven processes we use
As a direct result of the Maven project and infrastructure setup our daily Maven processes are fairly simple and straight forward:
Development
In daily development we use:
mvn idea:idea
or
mvn eclipse:eclipse
to set up the development environment. There are, unfortunately, a few limitations in how well Maven supports IDEs and visa versa.
We also use
mvn test
or
mvn integration-test
for building and testing the code. Although a lot of it is also done from within the IDE. These steps are mainly used as a verification before committing to SVN.
To deploy a current snapshot or a release - all that you needed is:
mvn deploy
Release process
The release process is as easy as
mvn release:prepare release:perform
in most of the cases...
More on the Release process
The above described release process only releases the product JAR and WAR files to our private Maven repository. This is not what we ship to the end user however.
Distribution builds
We have a separate project for each product. We call them distribution builds and they fall under release engineering.
Distribution builds produce a few final packages that you can find on the downloads page. These are source build, standalone build and WAR build. Some products have a few additional builds such as development bundles etc.
Distribution builds mainly rely on Maven assembly plugin to build a package. For the source build however, we had to build our own Maven plugin.
Source build plugin
Our source build plugin looks at the project it is meant to build and gathers its dependencies. Then it retrieves metadata for each of the dependencies and extracts from SCM locations for each project. Once that is done - making up a source build is simply a matter of checking out the source and passing the process over to the assembly plugin. That is all our plugin does at the moment.
Summary
There is a lot of design that goes into making Maven projects work on a large scale. It is not something to take lightly. The above design made our builds much more stable and robust. After all - pain amplifies tenfold if your build system does not behave in a predictable way.
Despite all of this work, there are still some issues that crop up every now and again. In the final part of this series I will describe them and our efforts in tackling them.


9 Comment(s)
Sherali,
I've been keenly following your last couple of articles on how Atlassian use Maven, comparing with our own internal use of Maven. Your section on "More on the Release process" was a bit thin on details and is the biggest problem we have with our Maven installation.
I don't know how much information you're allowed to share, but was hoping I could get your insight on a few of the issues with regards to distribution builds:
1) Who is allowed to run release:perform, are there any restrictions?
- If there are no restrictions, how do you avoid the case of "it runs on my computer", where it might be failing on Bamboo?
2) Your use of maven assembly would yield gz/zip files, are these automatically deployed as part of some plugin?
3) Assuming you generate some sort of installer beyond a simple WAR, ie. exe/rpm/deb, is this done as part of the maven plugin process attached to the install goal, or is this manually done?
Thanks,
Andrew
By Andrew Franklin at February 27, 2008 6:38 PM
Andrew,
Indeed I just touched upon the release mechanism. I might actually make a separate post on the subject since, you are right, it is a very important bit.
Meanwhile just to answer your questions:
1. We have a Release Engineer, James Dumay, whose responsibility is overall the maven process and specifically - releases. At the moment we have a guideline for making a release which prescribes:
a) to ssh to a specific box we have for releases
b) invoke 'screen' in order for the release not to be interrupted if the network fluctuates
c) make sure the versions of java, maven, svn and the settings.xml are correct
d) check out the project
e) invoke mvn release:prepare release:perform
In the long term we are planning to enforce as many environments conditions as we can via the 'enforcer' maven plugin. We are also planning to automate the releases so that anyone authorized can use a nice web interface to produce a release.
2. I am not sure what you mean by 'deployed' here. Indeed the distribution build produces tar.gz or zip files which are them made available on the downloads pages of various products: http://www.atlassian.com/software/. This is controlled by our internal system. It provides a web interface for deploying each version to it. At the moment this is manual but we are working on closing the gap between mavn release and deploying to our downloads page. Ideally we want our internal system to point to our Maven repository for downloads.
3. The distribution build for each product consists of several modules that produce gz/zip files of the WAR, Standalone and Source distributions. There is also a module that produces an installer binary. Therefore Maven release will produce those as well.
I hope this answers your questions. Will try to write up a separate part on the release process soon.
cheers,
sherali
By Sherali Karimov at February 28, 2008 1:43 AM
Sherali,
Sounds like in many ways we share the same process. I guess it seems like there's a couple of areas where maven doesn't quite fill the gap yet everybody is tackling the problem in there own way. Maybe I'll catch you at an SJUG some time and we can discuss more.
Thanks again,
Andrew
By Andrew Franklin at February 28, 2008 2:49 AM
Andrew,
granted, there are a few things maven does not do automagically for us yet. I prefer to think that it is only because we have not set it up yet. Once we do - I will definitely post an update here.
I am looking forward to catching up sometime.
cheers,
sherali
By Sherali Karimov at February 28, 2008 4:15 AM
Andrew,
I think I understand your third question. We had similar issues and solved them by modifying the jar-plugin. What we wanted to do was to create a jar packaged file, that contained a META-INF folder with a descriptor xml, some libraries under a lib folder and the actual artifact as a jar file (within the jar). It did not require too many lines of code to modify the jar plugin. The distribution unit is then "attached" (which I think is a loosely defined word within Maven) to the main artifact (which is the jar file) in order to then make it possible to create an assembly that contains the attachments.
I am planning to write an article about our solution (named: Custom Packaging in Maven -- or how I Lost Four Nights of Sleep Trying to Rename a File). Please tell me if you think that would be of interest.
By Viktor Nordling at March 3, 2008 4:25 AM
Viktor,
Sounds Interesting for sure, although the jar solution you mention isn't quite the problem I've got for my third question (at least I don't think it is). I'm just really interested in how others are using maven in their release process at the end stage, the cutting of installers.
Basically we need to deploy our application as an rpm, so it ends up in our yum repository which is deployed to all our servers through cfengine. Essentially all our projects have spec files which as part of the %build directive call maven package/install. When we want to ship, we have a special tool which checkouts the project, tags a release, then calls rpmbuild, the resulting rpm is then deployed. The point is much of this process is legacy in that it was great for ant based projects, but seems like maven does much of the above out of the box, just needs a couple of extensions. Got my eye on the rpm-maven-plugin, but doesn't support all the options in our spec files, so I'm thinking about contributing to the project if the building of installers from within maven seems like an appropriate approach.
With all that said and done, I definitely will be reading both your and Sherali's followup articles.
cheers,
Andrew
By Andrew Franklin at March 4, 2008 2:04 AM
On reading this article my eyes were first drawn to the diagram. A quick scan left me a little confused... "public-porn, private-porn, contrib-porn... huh? Is this a witty example or... oh... Maven... POM!" :)
Along the same lines as the joke "Keming. 1. The result of improper kerning.", perhaps we can define "atlassian-public-porn. 1. Perhaps by Java 6 people will stop asking us where this is.".
It was interesting to know how you guys use Maven, thanks for the post.
By Tom Clift at March 14, 2008 8:21 PM
Sherali,
It sounds very much that the release process you described would be handled nicely by most continous integration tools.
We use continuum and from my perspective it solves the same problem you describe in 1a-e and it also has access control etc.
By Kent Narling at September 30, 2008 11:36 AM
Kent, I am not sure what you mean exactly. Here is what I think though.
Support for the build in release process in continuous integration servers is great. We can not afford, however, every team member to be running a CI server on their box. Sometimes it is counterproductive. We can not also dictate our customers to use a particular flavor of a CI server if they want to build our products from the source. That would be unfair.
Therefore we need a common tool that all of the people above can use to make their builds.
Besides, CI servers normally delegate the task of running the build to tools like Maven, Ant, some home grown scripts etc.
By Sherali Karimov, X-Team Lead at September 30, 2008 3:17 PM