Tag Archive for 'continuous integration'

Setting up phpUnderControl

On a regular basis, I get contacted by people who want to install phpUnderControl but don’t really know how to set up their projects and use the features provided by phpUnderControl completely. So, aside from providing a quick-and-easy setup guide for cruisecontrol and phpUnderControl, I’ll share the setup scripts I have here and hope it’s useful for someone. This guide is mostly focussed on getting phpUnderControl to work on a Debian system, but there’s not that much OS specific to it.

Getting it installed

You probably will need some tools that are related to the PHP project you want to deploy on the phpUnderControl installation and for the sake of briefness I’m not going to cover how to install them, but instead just list what might come in handy for the continuous integration system to set up:

$ apt-get install subversion subversion-tools sun-java6-jre sun-java6-jdk

Also, install php, phpdoc, phpcs, phpunit and xdebug, you’ll need it later on for unit testing, generating reports and analyzing your code. Next up, you can install cruisecontrol. Just get the cruisecontrol archive and unpack it somewhere. (I chose /opt):

$ cd /opt/
$ wget http://heanet.dl.sourceforge.net/sourceforge/cruisecontrol/cruisecontrol-bin-2.8.2.zip
$ unzip /opt/cruisecontrol-bin-2.8.2.zip
$ mv -f cruisecontrol-bin-2.8.2 cruisecontrol

By default, cruisecontrol doesn’t have a start-up script. That’s not very easy when you want to start, stop or restart the server, so let’s make it (in /etc/init.d/cruisecontrol):

. /lib/lsb/init-functions
test -x $DAEMON || exit 5
UGID=$(getent passwd $RUNASUSER | cut -f 3,4 -d:) || true
case $1 in
log_daemon_msg "Starting Cruisecontrol server" "cc"
if [ -z "$UGID" ]; then
log_failure_msg "user \"$RUNASUSER\" does not exist"
exit 1
cd /opt/cruisecontrol/
./cruisecontrol.sh > /dev/null 2>&1
log_end_msg $?
log_daemon_msg "Stopping Cruisecontrol server" "cc"
start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
log_end_msg $?
rm -f $PIDFILE
$0 stop && sleep 2 && $0 start
pidofproc -p $PIDFILE $DAEMON >/dev/null
if [ $status -eq 0 ]; then
log_success_msg "Cruisecontrol server is running."
log_failure_msg "Cruisecontrol server is not running."
exit $status
echo "Usage: $0 {start|stop|restart|force-reload|status}"
exit 2

Set the file to have executable rights, and start the cruisecontrol server:

$ chmod +x /etc/init.d/cruisecontrol
$ /etc/init.d/cruisecontrol start

Right now, if you go to http://yourhost:8080/dashboard/, you should see a working cruisecontrol server page. If you don’t, please have a look at the previous steps and try again. A quick look at the cruisecontrol logs in /opt/cruisecontrol/cruisecontrol.log to find out what might be the problem.
For now, you can stop the cruisecontrol server:

$ /etc/init.d/cruisecontrol stop


This is even easier to install. We’ll just take the bleeding edge SVN sources so we can enjoy the latest goodies that phpUnderControl has to offer :) :

$ cd /opt/
$ svn co svn://svn.phpunit.de/phpunit/phpUnderControl/trunk phpuc
$ /opt/phpuc/bin/phpuc.php install /opt/cruisecontrol
$ /etc/init.d/cruisecontrol start

That’s it! phpUnderControl should be installed by now, which you can verify by going to http://:8080/cruisecontrol/ and see the new phpUnderControl interface. Of course, there’s not much information available at this time, let alone a useful project. But we’ll get to that in a minute :)


All phpUnderControl projects are configured in a single config.xml file, located in the cruisecontrol install directory, in our case /opt/cruisecontrol/config.xml. To give you an idea on how this looks for most of my PHP projects, here’s an example:

<project name="phpfoo" buildafterfailed="false">
<plugin name="svnbootstrapper" classname="net.sourceforge.cruisecontrol.bootstrappers.SVNBootstrapper"/>
<plugin name="svn" classname="net.sourceforge.cruisecontrol.sourcecontrols.SVN"/>
<currentbuildstatuslistener file="logs/${project.name}/status.txt"/>
<svnbootstrapper localWorkingCopy="projects/${project.name}/source/"/>
<modificationset quietperiod="0">
<svn localWorkingCopy="projects/${project.name}/source/"/>
<schedule interval="60">
<ant anthome="apache-ant-1.7.0" buildfile="projects/${project.name}/source/build.xml"
target="build" uselogger="true" usedebug="false" />
<log dir="logs/${project.name}">
<merge dir="projects/${project.name}/build/logs/"/>
<currentbuildstatuspublisher file="logs/${project.name}/buildstatus.txt"/>
<artifactspublisher dir="projects/${project.name}/build/coverage" dest="logs/${project.name}" subdirectory="coverage" />
<artifactspublisher dir="projects/${project.name}/build/api" dest="logs/${project.name}" subdirectory="api" />
<execute command="/opt/phpuc/bin/phpuc.php graph logs/${project.name}"/>
<htmlemail mailhost="xx.xx.xx.xx" returnaddress="foo@example.com"
returnname="phpUnderControl server" logdir="logs/${project.name}">
<failure address="fail@example.com" reportWhenFixed="true" />

As you can see, this file actually just looks out for changed subversion modificationsets, updates the source and then fires off the build.xml inside the project source directory. That one is actually the most interesting one, so I’ll list it here too:

<?xml version="1.0"?>
<project name="phpfoo" default="build" basedir="../">
<target name="php-documentor">
<exec executable="phpdoc" dir="${basedir}/source" logerror="on">
<arg line="-o HTML:frames:DOM/earthli -ti '${ant.project.name} documentation' -dn default -i tests/
-s on -ue on -t ${basedir}/build/api -d ." />
<target name="phpcs">
<exec executable="phpcs"
output="${basedir}/build/logs/checkstyle.xml" dir="${basedir}">
line="--ignore=*/tests/* --report=checkstyle
--standard=PEAR source" />
<target name="phpunit">
<exec executable="phpunit" dir="${basedir}/source/tests" failonerror="true">
line="--log-xml ${basedir}/build/logs/phpunit.xml
--log-pmd ${basedir}/build/logs/phpunit.pmd.xml
--log-metrics ${basedir}/build/logs/phpunit.metrics.xml
--coverage-xml  ${basedir}/build/logs/phpunit.coverage.xml
--coverage-html ${basedir}/build/coverage
AllTests" />
<target name="build" depends="php-documentor,phpcs,phpunit" />

This builds API documentation, runs the PHP Codesniffer and runs the unit tests, which in turn provides the code coverage, metrics, PMD and other statistics. That’s all there is to it!