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:
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:
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:
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.
# 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:
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):
cp post-commit.tmpl post-commit
chmod 755 post-commit
Now edit post-commit and ensure that the last three lines look like this:
That‚Äôs it! From now on, every time someone commits code, the build is triggered.
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 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.