I was watching a DjangoCon keynote by Cal Henderson from Flickr and he mention that they used Hudson for Continuous Integration (CI).

I know that there is phpUnderControl, but with Flickr endorsing Hudson that was enough for me to give Hudson a try over phpUnderControl. I will not be covering the installation of Hudson in this post. I would like to focus more on the integration of the PHP tools with Hudson.

I will be showing how to integrate the following tools:

Hudson Plugins

Once you have Hudson installed you will want the following plugins installed to get the PHP tools running on your code base:

Installing the Plugins

To install plugins you will want to click on Manage Hudson:

Manage Hudson

Then click on Manage Plugins:

Manage Plugins

Then go to the avaliable plugins tab and install the plugins that are described above.

Now that you have the plugins installed and you have restarted Hudson. Let's get started on creating and configuring the job.

Start a New Hudson Job

From the main Hudson page you will want to click on New Job. Give the job a name and select Build a free-style software project. Then click OK

Hudson New Job

Configure the Hudson Job

Okay, now that we have the job started let's go ahead and configure the job. After creating the job it should take you to the configure screen. Here I will go through each of the configuration options for each of the tools.

Subversion

Subversion should be pretty straight forward, choose the Subversion option. I ssh into my subversion repo so there are a few more steps to take.

Click on the question mark on the right side of the Repository URL. Click on the ****this link**** link that you see in the paragraph below see:

Specify the subversion repository URL to check out, such as "http://svn.apache.org/repos/asf/ant/". You can also add "@NNN" at the end of the URL to check out a specific revision number, if that's desirable.

When you enter URL, Hudson automatically checks if Hudson can connect to it. If access requires authentication, it will ask you the necessary credential. If you already have a working credential but would like to change it for other reasons, click ****this link**** and specify different credential.

During the build, revision number of the module that was checked out is available through the environment variable SVN_REVISION, provided that you are only checking out one module. If you have multiple modules checked out, use the svnversion command.

You should get the following screen:

Hudson Subversion Configuration

Type in your Repository URL and your authentication information. Then click OK.

When you return to the main configuration page you will need to fill out one more section.

Local module directory (optional): svn

Hudson SVN Checkout Directory

If you don't do this your repository check out will be in your main build folder (workspace directory). We do not want this so we put it into a svn folder.

Ant Build Targets

Hudson Ant Build Targets

Go ahead and type in what I have as targets. We will build the Ant file later and all of this will make sense.

If you have problems with the build completing at the end of this tutorial, I would recommend doing each of the build targets one by one until one completes. Then add another one and so on until all of them complete.

Post-build Actions

The following actions process the php tools that we will be using.

Javadoc (Works with PHP Doc)

Check the Publish Javadoc and type in the Javadoc directory: build/docs/

Hudson PHP Doc Configuration

Clover Coverage Report

Check the Publish Clover Coverage Report.

Clover report directory: build/logs

Clover report file name: clover.xml

Clover Coverage Report

Report JDepend (Works with PDepend)

Check the Report JDepend option and type in Pre-generated JDepend File: build/logs/jdepend.xml

Hudson PDepend Option

Checkstyle

Check the Publish Checkstyle analysis results and fill in the Checkstyle results: build/logs/checkstyle.xml

Hudson Checkstyle

DRY results

Check the Publish duplicate code analysis results option and fill in the Duplicate code results: build/logs/pmd.xml

Hudson Duplicate Code Results

Testing Tools (PHPUnit with junit.xml)

Check the Publish testing tools result report option and fill in the PHPUnit section: _build/logs/junit.xml

This is a little strange because you have to put it in _build. It is because this plugin can only put files in your repository check out folder, I chose to put it in _build because most likely you do not have a folder in your respository with that name. If you do you will also have to change the ant file to represent the new folder name.

Future versions will be based off of the workspace directory and you will be able to put it with the rest of your log files. For now this is how we have to do it.

Hudson Testing Tools - PHPUnit

Configuration Complete

Now we are done with the configuration so click the Save button.

Setup the Hudson Ant File for the Job

Open up a terminal and log into your server.

Okay now off to the Ant file. I am going to paste my Ant file for you to copy and paste. If you have done a normal Hudson installation you should be able to change directory to:

CODE:
  1. cd /srv/hudson/jobs/Test\ Job/workspace

Test\ Job can be replaced with whatever you called your job.

Create the build.xml file and paste in the Ant file:

CODE:
  1. sudo nano build.xml

The Ant File

CODE:
  1. <project name="Test Job" default="build">
  2.  <target name="clean">
  3.   <delete dir="${basedir}/svn/_build"/>
  4.   <delete dir="${basedir}/build"/>
  5.  </target>
  6.  
  7.  <target name="prepare">
  8.   <mkdir dir="${basedir}/svn/_build/logs"/>
  9.   <mkdir dir="${basedir}/build/logs"/>
  10.   <mkdir dir="${basedir}/build/docs"/>
  11.  </target>
  12.  
  13.  
  14.  <target name="phpdoc">
  15.   <exec dir="${basedir}"
  16.         executable="phpdoc"
  17.         failonerror="true">
  18.    <arg line="-t build/docs/
  19.               --directory svn
  20.               -ti 'Test Job Docs'
  21.               --parseprivate on
  22.               --undocumentedelements on
  23.               --output HTML:Smarty:PHP"/>
  24.   </exec>
  25.  </target>
  26.  
  27.  <target name="phpcpd">
  28.   <exec dir="${basedir}"
  29.         executable="phpcpd"
  30.         failonerror="true">
  31.    <arg line="--log-pmd=build/logs/pmd.xml svn"/>
  32.   </exec>
  33.  </target>
  34.  
  35.  <target name="pdepend">
  36.   <exec dir="${basedir}"
  37.         executable="pdepend"
  38.         failonerror="true">
  39.    <arg line="--jdepend-xml=build/logs/jdepend.xml svn"/>
  40.   </exec>
  41.  </target>
  42.  
  43.  <target name="phpcs">
  44.   <exec dir="${basedir}"
  45.         executable="phpcs"
  46.         output="${basedir}/build/logs/checkstyle.xml"
  47.         failonerror="false">
  48.    <arg line="--report=checkstyle svn"/>
  49.   </exec>
  50.  </target>
  51.  
  52.  <target name="phpunit">
  53.   <exec dir="${basedir}"
  54.         executable="phpunit"
  55.         failonerror="true">
  56.    <arg line="--log-junit       svn/_build/logs/junit.xml
  57.               --coverage-clover build/logs/clover.xml
  58.              svn/tests"/>
  59.   </exec>
  60.  </target>
  61.        
  62.  <target name="code-coverage">   
  63.   <exec dir="${basedir}"
  64.         executable="phpunit"
  65.         failonerror="true">
  66.    <arg line="--coverage-html /path/to/webserver/that/can/serve/the/coverage/pages"/>
  67.   </exec>
  68.  </target>
  69.              
  70.  
  71.  <target name="build"
  72.          depends="clean,prepare, phpcpd, pdepend, phpunit, code-coverage"/>
  73. </project>

Please pay attention to this section:

CODE:
  1. <target name="code-coverage">   
  2.   <exec dir="${basedir}"
  3.         executable="phpunit"
  4.         failonerror="true">
  5.    <arg line="--coverage-html /path/to/webserver/that/can/serve/the/coverage/pages"/>
  6.   </exec>
  7.  </target>

You will have to replace /path/to/webserver/that/can/serve/the/coverage/pages with a path that can serve the web pages from your server. Also, this path has to have tomcat6 in the group permissions so that PHPUnit can write to it.

To find out more about what Ant can do go and read!

Build the Hudson Job

Now click the Build Now link and let it work it's magic.

Hudson Build Now

Once set up I think that Hudson and PHP make a great team. Is this a better set up then phpUnderControl and PHP? Let me know your experiences.

ant clover code coverage continuous integration Development hudson Linux pdepend php php tools phpcpd phpcs phpdoc phpdocumentor phpunit