Sunday, June 10, 2012

Easy start with Jenkins for PHP developer

Lets look into the quick and minimal Jenkins setup for middle sized fast growing PHP project.
In order to easy follow this article you should at least:
  • have PEAR installed on server
  • use phpUnit for unit tests
  • build your app with Phing
Install Jenkins according to the operation system you have.

On my Ubuntu 12.04 LTS its only four CLI commands:
# wget -q -O - | sudo apt-key add -
# sudo sh -c 'echo deb binary/ > /etc/apt/sources.list.d/jenkins.list'
# sudo apt-get update
# sudo apt-get install jenkins

Jenkins will be available under http://localhost:8080/ by default.

Go to "Manage Jenkins" > "Manage Plugins" in order to install plugins required for PHP project:

  • Phing - run Phing targets
  • xUnit - parse phpUnit log files

For more information look into Jenkins for PHP website OR really awesome book Integrating PHP Projects with Jenkins.

Now when all plugins are installed we can configure our project.

Click "New Job", input job name, select "Build a free-style software project" and click "OK"

New Job is created and you will be redirected to Job configuration page.
First of all you should configure project working directory. In order to do that you should find "Advanced Project Options" section and expand it by clicking "Advanced..." button.

Check the "Use custom workspace" checkbox and input the path to your project root directory.

Its good to configure your build process to checkout the code from SVN, but in order to simplify our current setup we will describe that in next article, so lets just leave "None" in "Source Code Management" section.

Also in "Build Triggers" section we will check "Build periodically" checkbox and set the nightly build with the cron-like syntax: "0 0 * * *". 
NOTE: The whole point of Continuous Integration is to perform tests and build on any change (commit to version control system) but not on some periodical basis. So in the future its good to configure the VCS and use "Poll SCM" instead that will for example once per 5 minutes check it there were any new commits and only then will start the build process.

PERMISSIONS DISCLAIMER: Jenkins operates from under its own user, so make sure you've applied your permissions configuration accordingly.

From this point you can save the configuration and click "Build Now" in order to execute empty build.
In build log you will see something like:

Started by user anonymous
Building in workspace /home/joseph/www/aaaaa.localhost
Finished: SUCCESS

Click "Configure" link and lets fill our build with "Build" and "Post Build Actions".
Lets assume that our Phing file looks as simple as this build.xml:

<project name="name-of-project" default="build">
  <property name="basedir" value="." override="true" />
<target name="build" depends="alltests">
    <!--  deploy your project here -->

<target name="alltests" depends="prepare">
 <phpunit haltonfailure="true" haltonerror="true" printsummary="true">
 <formatter todir="${basedir}/build/tests" type="xml"/>
 <batchtest classpath="${basedir}/tests/">
    <fileset dir="${basedir}/tests">
              <include name="*.php"/>

 <target name="clean" description="Cleanup build artifacts">
  <delete dir="${basedir}/build/tests"/>

 <target name="prepare" depends="clean" description="Prepare for build">
  <mkdir dir="${basedir}/build/tests"/>


So we have a very simple set of tasks to build, test and deploy our web application.

Click "Add Build Step" in "Build" section and select "Invoke Phing targets".
Input the name of the target you want to execute, i. e. "build" (you can even specify couple of them  separated by space)

Click "Add post-build action" in "Post-build Actions" section and select "Publish JUnit test result report". Input for example "build/tests/*.xml" as we've configured in build.xml file to store logs in such location.

Click "Save" and start build.
Yahoo! We are all set!

Next time we will talk about integration with version control systems and try a lot of interesting things like codding standard compliance checkcode complexity measurement, copy-paste detection, code dependency analysis and API documentation generation. See ya!