October 26, 2009

Creating a Continuous Integration Server for Java Projects Using Hudson

Article Source Wazi
October 23, 2009, 10:56 am

In a previous article we demonstrated how to setup a Linux server to use Maven, the primary Java build tool. Now we’ll look at how to use Hudson to provide continuous integration to your build environment. Just what is continuous integration? Think of it this way: you have a team of developers who are all busily committing code to your source code repository. Each developer is focused on his or her role, or area of functionality, for the system being developed. A continuous integration (CI) engine is an automated build system that checks out the most current code from the source code repository, builds it, and makes the resulting artifacts available for download and/or review. It’s also a great way to see if the entire system is, in fact, compilable. More often than we’d like to admit, developers check in their code without checking for compile errors – creating a problem for others in the team who update their local sources to the trunk, only to find the system no longer compiles! The Continuous Integration Engine can be linked to a mailing list to notify developers that the build has failed. Additionally, it can show a “diff” of what has changed since the previous build, so users can see exactly who the culprit is – and follow up with merciless ridicule.

So why use Hudson to create a continuous integration server? There are certainly other CI engines out there, such as the primary open source rivals to Hudson: Apache Continuum and CruiseControl.  Some good commercial CI engines are also available, but those are beyond the scope of this article.

We’ve worked with both Continuum and CruiseControl in the past, and consider them to be functional – in an adequate sort of way. Continuum’s web-based front-end isn’t bad, and for the most part it does what it’s designed to do. We’ve found CruiseControl to be more competent than Continuum when it comes to stability, although we must admit that we have not tried any of Continuum’s newer builds. But when it comes to ease of configuration Hudson wins, hands down. If, like us, you’re visually-oriented, and if you find it painful to edit an XML file to configure CI (as is the case with CruiseControl), Hudson’s graphical user interface just makes perfect sense.

Interested readers should be able to find more detailed comparisons of CI engines (like this one) with a quick search, but our conclusion – based on a combination of first-hand experience and other people’s opinions – is that Hudson is the current front-runner among open source CI engines.

Before You Start

You’ll need to be proficient in  Maven and Subversion before you continue. The principle here is to have a mock application hosted in a Subversion repository. We’ll then download and configure Hudson to access the Subversion repository, and perform continuous integration builds from there. We’ll assume you already have Maven configured. If not, have a look at the tutorial titled Creating a Maven-Based Development Environment on Linux. You’ll also need to have an accessible Subversion server set up somewhere.  If you don’t, a good place to get started is at http://subversion.tigris.org/faq.html#repository.

Meat & Potatoes

Creating a Test Project

Let’s start with a software project for illustration purposes. For this, we’ll use Maven to generate a project with one simple command:

mvn archetype:generate

You’ll be asked to select an application type to generate. Let’s go with a simple web application. Choose option 18. Then enter the following information into the prompts:

Define value for groupId: : com.example
Define value for artifactId: : testWebApp
Define value for version:  1.0-SNAPSHOT: : [Press Enter]
Define value for package:  com.example: : [Press Enter]
Define value for package:  com.example: :
Confirm properties configuration:
groupId: com.example
artifactId: testWebApp
version: 1.0-SNAPSHOT
package: com.example
Y: : [Press Enter]

Good job. You now have a fully functional web application that does very, very little indeed. You can compile and execute it for test purposes like this:

cd testWebApp/
mvn -Djetty.port=9999 org.mortbay.jetty:maven-jetty-plugin:6.1.18:run

The reason we use port 9999 is because we have other web applications already running on our machine. Point your favorite web browser to http://localhost:9999/testWebApp and you’ll be greeted by the now famous “Hello World!” greeting. Excited yet?

Importing the Test Project into Subversion

Next we need to import our new project into Subversion. We don’t want to import any generated artifacts so we first perform an mvn clean operation.

mvn clean
cd ..
# svnadmin create /var/lib/svn/repositories/testWebApp
# cd ..
# svn import testWebApp file:///var/lib/svn/repositories/testWebApp -m "initial import"

Now remove your existing webapp directory, and check it out from Subversion.

rm -rf testWebApp
svn checkout svn://armor.osdcorp.com/testWebApp

Your Subversion repository will obviously be different. Substitute the svn://armor.osdcorp.com part with your configuration.

In a normal team development environment, your team would now joyfully check out the source from Subversion, make changes, and check them back in. Let’s shift our focus to the role of Hudson, our continuous integration engine of choice.

Downloading and Installing Hudson

To download Hudson:

wget http://hudson-ci.org/latest/hudson.war

Simple as that. Now, to execute it you have two options. You can either drop it into a Servlet container like Tomcat, or you can simply start it up like this:

java -jar hudson.war --httpPort=8075

Again, due to our system already running certain web applications, we can specify an alternate port. Point your browser to http://localhost:8075 and you should be rewarded with Figure 1.

We’ll need to do some basic configuration first. Essentially, we need to tell Hudson where the JDK and Maven reside. Click on “Manage Hudson”, then “Configure System”. In the resulting screen, configure the locations respectively. Figure 2 shows what it looks like on our server.

Next, make sure you have configured the “Hudson URL” at the bottom of this configuration screen. You need to change it from “localhost” to the actual hostname of your server. Something like what's shown in Figure 3.

Excellent. Now click “Save”, and then click on the “New Job” link in top left corner of the page and fill out the resulting form as we have demonstrated in Figure 4.

Continuing from here, a more detailed page of your project is available, as shown in Figures 5 and 6.

Some explanation is required here. Hudson has various methods of deciding when to perform a build. These are called build triggers. The method we have chosen here is to poll Subversion every minute. If anything has changed, we perform a build. Other trigger mechanisms exist internally to Hudson. We say internally because there is one other important method to trigger a build. An HTTP GET on http://localhost:8075/job/testWebApp/build will trigger a build from an external source. How is that useful? You could use the Wget utility to trigger that URL from the command line or a shell. It’s particularly handy if you use the Wget command on the URL from within a Subversion post-commit hook. So: every time someone commits a change to your source code repository, a build will be performed automatically. In this way we eliminate the wasteful polling of the Subversion repository by Hudson itself.

Let’s go ahead and set up the post-commit hook now. But first, go back into the testWebapp Hudson job configuration and uncheck the “Poll SCM” checkbox. Then click “Save”. Now we’re ready to configure the post commit hook. Our repository resides in /var/lib/svn/repositories/testWebApp (see above):

cd /var/lib/svn/repositories/testWebApp/hooks
cp post-commit.tmpl post-commit
chmod 755 post-commit

Now edit post-commit and ensure that the last three lines look like this:


wget http://localhost:8075/job/testWebApp/build

That’s it! From now on, every time someone commits code, the build is triggered.

Finishing Up

There’s a lot more you can do with Hudson. It supports multiple other source code control repositories, build triggers, build notifiers… even Twitter and IRC interfaces! It uses plugins to perform much of this functionality. Take a look here for the current list of plugins available. We hope this has been a useful introduction to Hudson. If you’re keen for more, there’s detailed information at the Hudson Website.

Grant Smith
Grant started writing software at the age of 12 when his father assembled a Sinclair ZX-81 in kit form, and he's been hooked on technology ever since. His experience with software development is as deep as it is unique -- he's been a programmer in the South African Army, IT manager at a merchant bank, VP of IT at a construction and property administration company, and he's an active committer to the Apache community of open source software projects. Grant currently resides in Oregon where he enjoys cycling, racquetball, geocaching, coaching and playing soccer, and spending time with his lovely wife and children.

Click Here!