November 26th, 2009

Build and Release with Maven

Recently I gave a short presentation to the local Perl Mongers Group. The topic of the evening was build and deploy systems. I had chosen to present Maven.

Maven is a tool written in Java and only useful when managing Java project (but it implements some common and best practices that a valid in any software project).

The slides are available here:

The main part of the presentation was a practical demonstration of a few concepts: Subversion integration and release management. I've converted my demonstration notes into a simple tutorial, which you're find below.


You'll need
  • A Java JDK - I'm using version 1.6.0 update 17
  • Maven (obviously) - I'm using version 2.2.1
  • The Subversion command line tools - I'm at version 1.6.5

I will not go into details on how to install the tools (it should be pretty easy).

The rest of this tutorial is done in a terminal (or DOS-Prompt if you're on Windows).

Creating a Subversion Repository

To demonstrate the integration with Subversion, you'll need a repository. A repository can be created with following:
mkdir /tmp/svn	
svnadmin create /tmp/svn/maven
svn mkdir file:///tmp/svn/maven/branches file:///tmp/svn/maven/tags file:///tmp/svn/maven/trunk -m "Initial repository layout"
If you're you on Windows you should replace /tmp with /C:/TEMP or similar (and remember to do that for the rest of this tutorial).

Creating a New Project

To start a new project (or archetype) issue the following:
mvn archetype:generate
Don't panic! Maven will download a lot of plugins before presenting you with a menu of project types to chose from. It look something like this:
[INFO] Scanning for projects...
[INFO] Searching repository for plugin with prefix: 'archetype'.
[INFO] ------------------------------------------------------------------------
[INFO] Building Maven Default Project
[INFO]    task-segment: [archetype:generate] (aggregator-style)
[INFO] ------------------------------------------------------------------------
[INFO] Preparing archetype:generate
[INFO] No goals needed for project - skipping
[INFO] Setting property: classpath.resource.loader.class => 'org.codehaus.plexus.velocity.ContextClassLoaderResourceLoader'.
[INFO] Setting property: velocimacro.messages.on => 'false'.
[INFO] Setting property: resource.loader => 'classpath'.
[INFO] Setting property: resource.manager.logwhenfound => 'false'.
[INFO] [archetype:generate {execution: default-cli}]
[INFO] Generating project in Interactive mode
[INFO] No archetype defined. Using maven-archetype-quickstart (org.apache.maven.archetypes:maven-archetype-quickstart:1.0)
Choose archetype:
1: internal -> appfuse-basic-jsf (AppFuse archetype for creating a web application with Hibernate, Spring and JSF)
2: internal -> appfuse-basic-spring (AppFuse archetype for creating a web application with Hibernate, Spring and Spring MVC)
3: internal -> appfuse-basic-struts (AppFuse archetype for creating a web application with Hibernate, Spring and Struts 2)
4: internal -> appfuse-basic-tapestry (AppFuse archetype for creating a web application with Hibernate, Spring and Tapestry 4)
5: internal -> appfuse-core (AppFuse archetype for creating a jar application with Hibernate and Spring and XFire)
6: internal -> appfuse-modular-jsf (AppFuse archetype for creating a modular application with Hibernate, Spring and JSF)
7: internal -> appfuse-modular-spring (AppFuse archetype for creating a modular application with Hibernate, Spring and Spring MVC)
8: internal -> appfuse-modular-struts (AppFuse archetype for creating a modular application with Hibernate, Spring and Struts 2)
9: internal -> appfuse-modular-tapestry (AppFuse archetype for creating a modular application with Hibernate, Spring and Tapestry 4)
10: internal -> maven-archetype-j2ee-simple (A simple J2EE Java application)
11: internal -> maven-archetype-marmalade-mojo (A Maven plugin development project using marmalade)
12: internal -> maven-archetype-mojo (A Maven Java plugin development project)
13: internal -> maven-archetype-portlet (A simple portlet application)
14: internal -> maven-archetype-profiles ()
15: internal -> maven-archetype-quickstart ()
16: internal -> maven-archetype-site-simple (A simple site generation project)
17: internal -> maven-archetype-site (A more complex site project)
18: internal -> maven-archetype-webapp (A simple Java web application)
19: internal -> jini-service-archetype (Archetype for Jini service project creation)
20: internal -> softeu-archetype-seam (JSF+Facelets+Seam Archetype)
21: internal -> softeu-archetype-seam-simple (JSF+Facelets+Seam (no persistence) Archetype)
22: internal -> softeu-archetype-jsf (JSF+Facelets Archetype)
23: internal -> jpa-maven-archetype (JPA application)
24: internal -> spring-osgi-bundle-archetype (Spring-OSGi archetype)
25: internal -> confluence-plugin-archetype (Atlassian Confluence plugin archetype)
26: internal -> jira-plugin-archetype (Atlassian JIRA plugin archetype)
27: internal -> maven-archetype-har (Hibernate Archive)
28: internal -> maven-archetype-sar (JBoss Service Archive)
29: internal -> wicket-archetype-quickstart (A simple Apache Wicket project)
30: internal -> scala-archetype-simple (A simple scala project)
31: internal -> lift-archetype-blank (A blank/empty liftweb project)
32: internal -> lift-archetype-basic (The basic (liftweb) project)
33: internal -> cocoon-22-archetype-block-plain ([])
34: internal -> cocoon-22-archetype-block ([])
35: internal -> cocoon-22-archetype-webapp ([])
36: internal -> myfaces-archetype-helloworld (A simple archetype using MyFaces)
37: internal -> myfaces-archetype-helloworld-facelets (A simple archetype using MyFaces and facelets)
38: internal -> myfaces-archetype-trinidad (A simple archetype using Myfaces and Trinidad)
39: internal -> myfaces-archetype-jsfcomponents (A simple archetype for create custom JSF components using MyFaces)
40: internal -> gmaven-archetype-basic (Groovy basic archetype)
41: internal -> gmaven-archetype-mojo (Groovy mojo archetype)
Choose a number:  (1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20/21/22/23/24/25/26/27/28/29/30/31/32/33/34/35/36/37/38/39/40/41) 15: : 
We just want the default (quickstart) archetype, so just press enter.

Now you'll be asked to enter a groupId, artifactId, version and package.

The groupId is like a Java package name, usually a domain name in reverse.

For example I could use com.livejournal.slu as a groupId. The artifactId is the name of the project, you should enter maven-demo. The version default 1.0-SNAPSHOT which is ok, the package default is the same as the groupId, also ok.

You will be presented with the selected values and if you're satisfied (pressing enter) a new project will be created for you in the directory maven-demo.

Now you can build you project using
cd maven-demo
mvn compile
Also try mvn package which will create a JAR of your project (after running any unit tests).

Importing to and Integrating with Subversion

To play with the Subversion integration we need to import the project into the repository we created earlier:
cd ..
svn import maven-demo file:///tmp/svn/maven/trunk
Check out you project:
svn co file:///tmp/svn/maven/trunk maven-demo-svn
Now edit the pom.xml file. Add the following lines just after the line that reads <url></url>:

Setting up a Distribution Repository

When doing releases we need a place to store our released artefacts (in essence JAR files). Add the following lines right after the scm-section you added above:
    <name>My TEMP directory</name>
Check in your modified pom.xml:
svn ci pom.xml -m "Added SCM and repository"

Preparing and Performing a Release

Now we're ready to release our project. This is a two step process: first the release is prepared and if all goes well we can perform the actual release.

Start the the prepare:
mvn release:prepare

You will be asked to enter a release version, SCM tag and the next development version. Maven will present you with sensible default values, so just press enter three times.

Now Maven will update the version number in the pom.xml, will verify that the project builds, tags the release in Subversion and finally commits a pom.xml for the next development cycle to Subversion.

If everything went well, you can now perform the release:
mvn release:perform
This will check out a fresh copy of the project for the tag you defined when preparing the release. Next the project is built and released (i.e. copied to the /tmp directory.

The End

That's it. Play with the above commands, read the documentation, and play some more...

Welcome to the world of Maven!