Jenkins for PHP from scratch – II

In the previous post, we explained how to set up jenkins for php applications. It was the basic setup, installing Jenkins and creating a test job.

Now we want to go on step further and take advantage of all the previously installed plugins. They require some php extensions and phpunit extensions in order to start working.

Summarizing, I had to run the following command (you might have already installed some of the packages, that’s okey):

sudo apt-get install php5-xsl  #Required by phpdox
sudo pear config-set auto_discover 1
sudo pear install -a pear.phpunit.de/phploc
sudo pear install -a PHP_CodeSniffer
sudo pear install pear.phpunit.de/phpcpd
sudo pear channel-discover pear.pdepend.org
sudo pear install pdepend/PHP_Depend
sudo pear channel-discover pear.phpmd.org
sudo pear install --alldeps phpmd/PHP_PMD
sudo pear install -a channel://nikic.github.com/pear/PHPParser-0.9.3
sudo pear install -a channel://pear.netpirates.net/phpDox-0.5.0
sudo pear channel-discover pear.phpqatools.org
sudo pear install --alldeps phpqatools/PHP_CodeBrowser

Now you should have installed all the tools required by the jenkins plugins.

Then, we just need to create a script to execute all this tools, save the outputs, and configure the jenkins plugins to parse all this data. Yo can do it all manually in a bash script, but I’d suggest you to install ant and create an easy customizable build.

In order to get ant just type:

sudo apt-get install ant1.7

Note: You might need to install java JRE in order to get ant working.

Now, you have to create your own build.xml file on the root directory of your proyect. This is how mine looks like:

<?xml version="1.0" encoding="UTF-8"?>

<project name="The Developer World Is Yours" default="build" basedir="workspace/">
 <target name="build"
   depends="prepare,lint,phploc,pdepend,phpmd-ci,phpcs-ci,phpcpd,phpdox,phpunit,phpcb"/>

 <target name="clean" description="Cleanup build artifacts">
  <delete dir="${basedir}/build/api"/>
  <delete dir="${basedir}/build/code-browser"/>
  <delete dir="${basedir}/build/coverage"/>
  <delete dir="${basedir}/build/logs"/>
  <delete dir="${basedir}/build/pdepend"/>
 </target>

 <target name="prepare" depends="clean" description="Prepare for build">
  <mkdir dir="${basedir}/build/api"/>
  <mkdir dir="${basedir}/build/code-browser"/>
  <mkdir dir="${basedir}/build/coverage"/>
  <mkdir dir="${basedir}/build/logs"/>
  <mkdir dir="${basedir}/build/pdepend"/>
  <mkdir dir="${basedir}/build/phpdox"/>
 </target>

 <target name="lint" description="Perform syntax check of sourcecode files">
  <apply executable="php" failonerror="true">
   <arg value="-l" />

   <fileset dir="${basedir}/">
    <include name="**/*.php" />
    <modified />
   </fileset>

   <fileset dir="${basedir}/tests">
    <include name="**/*.php" />
    <modified />
   </fileset>
  </apply>
 </target>

 <target name="phploc" description="Measure project size using PHPLOC">
  <exec executable="phploc">
   <arg value="--log-csv" />
   <arg value="${basedir}/build/logs/phploc.csv" />
   <arg path="${basedir}/" />
  </exec>
 </target>

 <target name="pdepend" description="Calculate software metrics using PHP_Depend">
  <exec executable="pdepend">
   <arg value="--jdepend-xml=${basedir}/build/logs/jdepend.xml" />
   <arg value="--jdepend-chart=${basedir}/build/pdepend/dependencies.svg" />
   <arg value="--overview-pyramid=${basedir}/build/pdepend/overview-pyramid.svg" />
   <arg path="${basedir}/" />
  </exec>
 </target>

 <target name="phpmd-ci" description="Perform project mess detection using PHPMD creating a log file for the continuous integration server">
  <exec executable="phpmd">
   <arg path="${basedir}/" />
   <arg value="xml" />
   <arg value="${basedir}/../phpmd.xml" />
   <arg value="--reportfile" />
   <arg value="${basedir}/build/logs/pmd.xml" />
  </exec>
 </target>

 <target name="phpcs-ci" description="Find coding standard violations using PHP_CodeSniffer creating a log file for the continuous integration server">
  <exec executable="phpcs" output="/dev/null">
   <arg value="--report=checkstyle" />
   <arg value="--report-file=${basedir}/build/logs/checkstyle.xml" />
   <arg value="--standard=PSR2" />
   <arg path="${basedir}/analyzer/" />
  </exec>
 </target>

 <target name="phpcpd" description="Find duplicate code using PHPCPD">
  <exec executable="phpcpd">
   <arg value="--log-pmd" />
   <arg value="${basedir}/build/logs/pmd-cpd.xml" />
   <arg path="${basedir}/" />
  </exec>
 </target>

 <target name="phpdox" description="Generate API documentation using phpDox">
     <exec executable="phpdox">
         <arg value="-f" />
         <arg value="../phpdox.xml.dist" />
     </exec>
 </target>

 <target name="phpunit" description="Run unit tests with PHPUnit">
     <exec executable="phpunit" failonerror="true">
         <arg value="--log-junit" />
         <arg path="${basedir}/build/logs/junit.xml" />
         <arg value="--coverage-clover" />
         <arg path="${basedir}/build/logs/clover.xml" />
         <arg value="--configuration" />
         <arg path="${basedir}/tests/phpunit.xml" />
         <arg value="${basedir}" />
     </exec>
 </target>

 <target name="phpcb" description="Aggregate tool output with PHP_CodeBrowser">
  <exec executable="phpcb">
   <arg value="--log" />
   <arg path="${basedir}/build/logs" />
   <arg value="--source" />
   <arg path="${basedir}/" />
   <arg value="--output" />
   <arg path="${basedir}/build/code-browser" />
   <arg value="${basedir}" />
  </exec>
 </target>
</project>

You must to keep in mind the output paths that you have set, as you will need to put the same data on jenkins.

In order to ensure that everything is fine, just type ant on the commandline and it will automatically execute all the other targets (dependencies). You shouldn’t see any errors.

This is the process that it should follow:

  • Delete all the build folders (clean up any existing data).
  • Create all the folders where the build results will be stored.
  • Ensure that there aren’t any syntax errors in the code.
  • Generate a full report of the project, including metrics like:
    • Number of lines of code, comments and no-comments
    • Number of directories, files, namespaces, interfaces, classes and so on.
    • Number of testing classes, methods and functions
    • Number of abstract and concrete classes
    • Number of static, non-static, public and private methods
    • Number of global and class constants
    • Average length of the classes and methods
    • Cyclomatic complexity regarding lines of code and number of methods
  • Generate a full report of project dependencies, which includes metrics such as:
    • Complexity
    • Coupling
    • Hierarchy
    • Inheritance
    • and so on.
  • Analyze the source code looking for the following problems:
    • Possible bugs
    • Suboptimal code
    • Overcomplicated expressions
    • Unused parameters, methods, properties
  • Find coding standard violations, note that you can provide a predefined set of rules (such as PSR2) or just create your own custom rules/standard.
  • Perform an analysis of duplicated code (copy paste detector).
  • Generate documentation based on the phpdoc comments found on the source code.
  • Run all PHPUnit tests.
  • Generates a browsable representation of PHP code where sections with violations found by the previous tools are highlighted.
Once you have the ant build working, it’s time to create a new job on Jenkins.
In order to speed up this, you can use  Sebastian Bergmann’s template, whose page has been the inspiration of this guide, by the way. Or you can download my template, which is basically the same but with some customizations.

Either way, all you need is create a new folder under jenkins’ jobs directory, which in Ubuntu is located at /var/lib:

cd /var/lib/jenkins/jobs/
sudo mkdir thedeveloperworldisyours
cd thedeveloperworldisyours
#put here the template (config.xml) file.
cd ..
#change the owner and group of the files, you can get the proper name and group by making an ls -l under jenkins directory (jenkins:nogroup by default)
sudo chown -R jenkins:nogroup thedeveloperworldisyours/

Now, restart Jenkins, go to the web interface, select “New Job” and select the option “copy existing job”:
jenkins-new-job-thedeveloperworldisyours

Have a look at the configuration and make the required changes (if you chosen my template you only need to change the source of your git files and the notification email).

Finally, run the job and hopefully you will get the venerated blue ball at the end:
jenkins-blue-ball

And that’s about it. If you have any doubts, questions or problems, feel free to ask.

In my next post I’ll show you how to integrate jenkins with git, authenticating using ssh keys, adding precommit and postcommit hooks, and much more!

3 thoughts on “Jenkins for PHP from scratch – II

  1. Hello! This post couldn’t be written any better! Reading through this post reminds me of my good old room mate! He always kept talking about this. I will forward this article to him. Fairly certain he will have a good read. Thank you for sharing!

Leave a Reply

Your email address will not be published. Required fields are marked *