Some time ago I tried having a separate build machine performing continuous builds every time I checked my project sources into Subversion and I was quickly hooked. It’s a very simple idea but I always found it a little hard to fully appreciate the benefits before I tried it in a real project.
While having a build machine really shines with unit tests, it has a place even when you don’t have any unit testing at all in place. Firstly, you catch those time-consuming errors not having added all files to the version control system. Breaking a build wastes time for the entire team. Secondly, you have an incentive to keep the build process sane since the system gets built all the time. Building a system really should be as simple as checking the sources out and running a single command. Performing automated builds can help simply because setting up the builds becomes troublesome otherwise!
So here’s a suggestion for you existing project that does not have any unit tests: setup a build machine that builds the project every time someone checks something in. Then create a single unit test and have it run as part of the continuous build process. That’s it. You will now know that your project can be built and that it at least passes some simple test. Moving forward, you can for example make a point of creating a unit test for all new bug reports from customers. You decide, but knowing that your project builds alone can be worth quite a lot.
There are several applications for continuous integration to choose from. Most of them seem to have been developed within the Java community, but they are capable of running much more than Java builds and JUnit tests. The first build system I tried was CruiseControl because it seemed an obvious choice at the time. It has performed very well, though I remember it was a little cumbersome to set up. Since I recently needed to set up CruiseControl from scratch I figured I might just as well try Hudson out.
For me, the major advantage of Hudson, besides the much neater interface, is the packaging and running behavior. Hudson is delivered as a WAR file that you can deploy on any Java servlet container, but it also contains Winstone, a lightweight servlet container so that you can actually run Hudson “self-hosted” by simply going:
$ java -jar hudson.war
Starting a self-hosted Hudson on a Linux box as a daemon, typically requires an System V init.d script. I can post a little information on how to write such a script and have Hudson start each time your System V machine boots if you wish; It’s not hard since Hudson will run as a single process, but a better solution might be to deploy Hudson to a servlet container, like Tomcat, JBoss or Glassfish.
A reasonable choice of servlet container for an Ubuntu box is Tomcat, simply because it is available as an Ubuntu package. Installation requires you to enable the universe and multiverse repositories. Details on how to do that can be found here. Once those repositories are enabled, you can install Tomcat and Hudson on an Ubuntu box by following these steps:
We start by installing Java and Tomcat.
# apt-get install sun-java6-jdk
# apt-get install tomcat5.5
Sun’s Java should be the default but if it is not, you can select the default Java by:
# update-alternatives --config java
Tomcat on Ubuntu comes with the security manager enabled by default and this will cause Hudson not to run. You can disable the security manager by editing the /etc/default/tomcat5.5 file.
Next we need to set the home directory for hudson. Add the following line to /etc/tomcat5.5/context.xml
<Environment name="HUDSON_HOME" value="/srv/hudson"
type="java.lang.String" override="false"/>
As you can see, I choose /srv/hudson as the home directory. See the FHS for details on that choice. Whichever directory you choose, create the directory and set the ownership so that the tomcat55 user can use it and restart Tomcat:
# mkdir /srv/hudson
# chown tomcat55.nogroup /srv/hudson/
# /etc/init.d/tomcat restart
Now, simply deploy Hudson by copying the hudson.war file into the /var/lib/tomcat5.5/webapps/ directory. Tomcat will notice the new file and deploy it automatically. Verify that it all works by pointing your browser to http://hostname:8180/hudson/ To update Hudson simply copy the new hudson.war file to the same location, overwriting the old.
If you wish to restrict access to Hudson, add the following two lines to /etc/tomcat5.5/tomcat-users.xml:
<role rolename="admin"/>
<user username="hudson-admin" password="secret" roles="admin"/>
Restart Tomcat and enable security in the Hudson System Configuration panel. Users not logged in will still be able to access builds but cannot adjust the settings or force new builds.
Update 2008-12-28:
I just verified that the installation instructions are still valid on Ubuntu 8.10 using Tomcat 6. All you have to do is replace tomcat55 with tomcat6 above; also, the port seem to have changed from 8180 to 8080. Here’s an updated installation summary:
Install Java and Tomcat.
# apt-get install sun-java6-jdk
# apt-get install tomcat6
Configure or disable the security manager:
# vi /etc/default/tomcat6
Set the home directory for Hudson by adding the follwowing line to /etc/tomcat6/context.xml
<Environment name="HUDSON_HOME" value="/srv/hudson"
type="java.lang.String" override="false"/>
Create the home directory, set the permissions and restart Tomcat
# mkdir /srv/hudson
# chown tomcat6.nogroup /srv/hudson/
# /etc/init.d/tomcat6 restart
Deploy Hudson by copying the hudson.war file into the /var/lib/tomcat6/webapps/ directory. Verify that it works by pointing your browser to http://hostname:8080/hudson/