Preparing and Building a PHP Project in Jenkins

Share this article

In a previous article, we went through the installation of Jenkins and prepared everything to get started. We will continue in this article by actually preparing our project. If you have a Jenkins setup ready from before, no need to go through the previous part – you can follow along with this one quite nicely.

Prepare composer

We are going to prepare our project first. We could use the project supplied by Sebastian Bergmann, but it’s rather a basic project and will run without problems in Jenkins. In this article, we will be using a different repository in which we will have to overcome some hurdles. We will be using a fork of Jumph as our basis.

First and foremost, we have to make sure that we have tools like PHPUnit and PHP-CodeSniffer available. We can do this in two different ways. Either we install the packages on our Jenkins server through Pear or Composer globally, or we define the dependencies in our composer.json file. I decided to go with the latter method, so we can easily control the version of these tools on our own local machine as well as on Jenkins. So we start by adding the following lines to the composer.json file and run composer update.

"require-dev": {
    "squizlabs/php_codesniffer": "~1.5.*",
    "phpmd/phpmd": "~2.1.*",
    "sebastian/phpcpd": "~2.0.*",
    "pdepend/pdepend": "~2.0.*",
    "phploc/phploc": "~2.0.*",
    "phpunit/phpunit": "~4.3.*",
    "theseer/phpdox": "~0.7.*",
},

If you want to know more about what each package does, have a look at Bruno’s article about PHP QA tools.

Prepare Ant

On our Jenkins server, we will be using Ant. So in case Ant is not yet installed on your server, make sure it is by running the following command.

sudo apt-get install ant

Ant helps you automate the software build process. You define tasks, called targets, in the configuration file. Ant will read this file and perform the appropriate action. You can define dependencies to indicate in which order Ant should perform these tasks. The configuration file is the so called build.xml file. We are going to add this to our project, so Ant can perform these tasks on our Jenkins server. We are going to use the template provided by Sebastian Bergmann which can be found here. We add this to the root of our project.

To run Ant, you can kick off ant build on the command line. This means that Ant will run the build target. If no parameter is given, Ant will run the target as indicated in the configuration as default, which in this case is also build.

Let’s take a closer look at the build target.

<target name="build" depends="prepare,lint,phploc-ci,pdepend,phpmd-ci,phpcs-ci,phpcpd-ci,phpunit,phpdox" description=""/>

The target is empty, however, it depends on a lot of other targets. It will first run the prepare target and then continue with the lint target until every target has been run. Let’s have a look at the phploc-ci target for example.

<target name="phploc-ci" depends="prepare" description="Measure project size using PHPLOC and log result in CSV and XML format. Intended for usage within a continuous integration environment.">
    <exec executable="${toolsdir}phploc">
        <arg value="--count-tests"/>
        <arg value="--log-csv"/>
        <arg path="${basedir}/build/logs/phploc.csv"/>
        <arg value="--log-xml"/>
        <arg path="${basedir}/build/logs/phploc.xml"/>
        <arg path="${basedir}/src"/>
        <arg path="${basedir}/tests"/>
    </exec>
</target>

This target is fairly easy to understand. You will notice it depends on the prepare target. Since that was already run by the build target, it won’t run again. Then we get the executable, which is phploc, which will be executed by Ant. You installed this earlier with Composer. Lastly, we will see the PHPLOC specific arguments. Ant will run the following command line input based on this target configuration.

phploc --count-tests --log-csv /build/logs/phploc.csv --log-xml /build/logs/phploc.xml /src /tests

The ${toolsdir} and ${basedir} are 2 variables. Depending on how they are configured, they might have an effect on the overall command line output

As indicated above, if you only wanted to trigger this target, you should run ant phploc-ci on the command line.

Notice that this PHPLOC command will output a phploc.csv file and a phploc.xml file. The plugins installed in Jenkins earlier will read these files and convert them to graphs, for example. In the next article we will dive deeper into this topic.

If you look through the whole build.xml file, you will notice that it’s depending on 3 other separate config files for certain tools; build/phpmd.xml, build/phpdox.xml and build/phpunit.xml. These configuration files are requested by the actual tools. To find out more, look at their respective docs.

Note that phpunit.xml is heavily inspired by the original phpunit.xml.dist file from Symfony2 since we are dealing with a Symfony2 project.

Changing the build.xml file

So, are we done? Unfortunately, not yet. The build.xml file is very generic and not completely suited for our project. First we need to define where tools like PHPUnit can be found. Our composer installed these automatically in the bin directory in the root of our project. We need to change the toolsdir property to the correct value.

<property name="toolsdir" value="bin/" />

We can also clean up several commands. The current build.xml file defines that we on one hand have a src directory and on the other hand a tests directory. Since Symfony2 includes tests in the src directory, we can remove all paths to the tests directory like this example.

<arg path="${basedir}/tests"/>

Although it’s not required, I prefer to keep everything as clean as possible so it matches our project correctly.

Lastly, the current configuration for PHPDox as indicated in the build.xml file while writing this article does not work with the latest version in my case. I changed the target like below, so it correctly reads our configuration file.

<target name="phpdox" depends="phploc-ci,phpcs-ci,phpmd-ci" description="Generate project documentation using phpDox">
  <exec executable="${toolsdir}phpdox">
   <arg value="--file" />
   <arg value="${basedir}/build/phpdox.xml" />
  </exec>
 </target>

Creating new targets

Everything has been set up to make sure all our QA tools will run as expected. However, our project is just a bit more complicated. If you analyzed the repository, you will notice that dependencies are regulated by Composer and Bower. Since it’s a Symfony project, we will also need a default parameters.yml file. We need to deal with these requirements to be able to set up the project correctly on Jenkins.

Let’s start off with the parameters.yml file. We can work with the default content of parameters.yml.dist, so we are just going to copy that file. We start by creating a new target named copy-parameters which executes the cp command.

<target name="copy-parameters" description="Copy parameters.yml file">
  <exec executable="cp" failonerror="true">
   <arg path="app/config/parameters.yml.dist" />
   <arg path="app/config/parameters.yml" />
  </exec>
 </target>

Next up are Composer and Bower. I decided to install these globally on the Jenkins server by executing the following commands.

curl -sS https://getcomposer.org/installer | php
sudo mv composer.phar /usr/bin/composer

sudo apt-get install nodejs
sudo apt-get install npm
sudo npm install -g bower
sudo ln -s /usr/bin/nodejs /usr/bin/node #This is needed on certain linux distro's.

[Ed: Note that if you’re running all this in a VM hosted on Windows, BowerPHP will be a much better option than Bower.]

Now lets create a target for Composer.

<target name="composer" description="Installing composer dependencies">
 <exec executable="composer" failonerror="true">
  <arg value="install" />
  <arg value="--dev" />
  <arg value="--prefer-dist" />
  <arg value="--no-progress" />

  <env key="SYMFONY_ENV" value="test"/>
 </exec>
</target>

It’s important to set SYMFONY_ENV to test so symfony knows it has to clear its test cache directory.

Let’s continue with Bower.

<target name="bower" description="Installing bower dependencies">
 <exec executable="bower" failonerror="true">
  <arg value="install" />
 </exec>
</target>

The final thing we need to do, is to make sure these targets are executed. So we change the build target and add the 3 newly created targets in the order we want to execute them.

<target name="build" depends="prepare,copy-parameters,bower,composer,lint,phploc-ci,pdepend,phpmd-ci,phpcs-ci,phpcpd-ci,phpunit,phpdox" description=""/>

Git

The last thing we need to do is to prepare our .gitignore file. If you ever want to run an Ant target on your local machine, your build directory will be filled with log files which you don’t want to commit to your repository. So we add the following lines to the .gitignore file.

# build
!build/phpmd.xml
!build/phpunit.xml
!build/phpdox.xml
build/*

Perhaps you got a little confused by all the changes we made. For your convenience, here is a direct link to the commit with all the changes we described above.

Create the project in Jenkins

Our project is ready. Let’s head back to Jenkins and configure it. This will be the easiest part in this article.

Since our project is located on Github, I suggest you install the Github plugin within Jenkins. If you are using your own git server, you can just install the regular Git plugin. If you are uncertain how to install a plugin, check the previous article.

When you return to the overview, you have to click new item in the left menu. As item name, we fill in Jumph. Next, we choose the option copy existing item and fill in php-template as the project to copy from.

Jenkins

We will immediately be taken to the configuration page of this project. First we uncheck Disable build so our build will be enabled on save. Within the Github project input field, we fill in the URL to the Github project.

The last thing we have to do is choose the source management. In our case, this is git. Next, you have to fill in the repository link. If you use the HTTPS link, you don’t have to provide any additional credentials. We can decide which branches should be build, but since we only have a master branch, we will leave it as it is.

The configuration is done – it’s so easy because we used a predefined template. If you scroll down, you will exactly see what the template configured for us. Don’t forget to save your configuration before continuing.

Start a build

If you followed all the steps so far, you should now be able to start a build. You can start a build by clicking build now in the left side menu of a project. You will notice at the bottom left table that a build appears.

Jenkins

If you click on the build itself, you will get a new side menu with options for this particular build. Click on console output to see exactly what’s going on. In my case, the first build failed due to missing some PHP extensions.

Jenkins

The console output comes in very handy for finding out why your project is failing. In my case, I just had to run sudo apt-get install php5-curl php5-xsl php5-sqlite php5-xdebug to install some needed packages. It took me a couple of builds to figure out what was missing, but with the console output, it’s easy to figure out what is going wrong. In the end, this is what my build history looks like.

Jenkins

Red means the build has failed, where blue means the build was successful. A failure can mean something went wrong with the configuration as we saw before, but it could also mean that unit tests have failed. If you open up your build.xml file again, you will notice that some targets got an attribute named failonerror which is set to true. If for some reason, that target fails, Ant will automatically stop and will report the build as broken.

Perhaps you expected a green ball instead of a blue ball when a build succeeds. There is a plugin available to show green balls instead of blue ones.

Conclusion

In this article, we worked our way to a successful build. We had to prepare our project and create a job within Jenkins. Finally we had to debug our first couple of builds since we forgot to install some libraries.

In the next part, we will take a look at all the results Jenkins gives back.

Frequently Asked Questions (FAQs) about Building PHP Project with Jenkins

How can I set up Jenkins for my PHP project?

Setting up Jenkins for your PHP project involves several steps. First, you need to install Jenkins on your server. You can download it from the official Jenkins website and follow the installation instructions. Once installed, you need to configure Jenkins to work with PHP. This involves installing necessary plugins like the PHP plugin, Git plugin, and others depending on your project requirements. After installing the plugins, you can create a new Jenkins job and configure it to build your PHP project. You will need to specify the location of your project’s source code, the build triggers, and the build steps.

What are the benefits of using Jenkins for PHP projects?

Jenkins offers several benefits for PHP projects. It automates the process of building, testing, and deploying your PHP applications, which can save you a lot of time and effort. It also helps to ensure that your code is always in a deployable state, which can improve the quality of your software. Furthermore, Jenkins supports continuous integration and continuous delivery, which can help you to deliver updates to your users more quickly and frequently.

How can I use Jenkins to automate testing for my PHP project?

Jenkins can be used to automate testing for your PHP project by integrating with various testing tools. For instance, you can use the PHPUnit plugin to run unit tests, or the Selenium plugin to run functional tests. You simply need to configure these plugins in your Jenkins job, and they will automatically run your tests every time you build your project. This can help to catch bugs early and ensure that your code is always in a good state.

Can I use Jenkins with other programming languages besides PHP?

Yes, Jenkins supports a wide range of programming languages besides PHP. This includes Java, Python, Ruby, C#, and many others. You can use Jenkins to build, test, and deploy applications written in these languages by installing the appropriate plugins and configuring your Jenkins job accordingly.

How can I use Jenkins to deploy my PHP application?

Jenkins can be used to deploy your PHP application by integrating with various deployment tools. For instance, you can use the SSH plugin to deploy your application to a remote server, or the Docker plugin to deploy your application as a Docker container. You simply need to configure these plugins in your Jenkins job, and they will automatically deploy your application every time you build your project.

What is continuous integration and how does Jenkins support it?

Continuous integration is a software development practice where developers integrate their code into a shared repository frequently, usually multiple times per day. This helps to catch integration issues early and reduce the time and effort required to deliver software updates. Jenkins supports continuous integration by automating the process of building, testing, and deploying your software every time you commit changes to your repository.

What is continuous delivery and how does Jenkins support it?

Continuous delivery is a software development practice where code changes are automatically built, tested, and prepared for a release to production. It aims to make releases less risky and more frequent. Jenkins supports continuous delivery by automating the entire software release process, from integration and testing to delivery and deployment.

Can I use Jenkins with Git?

Yes, Jenkins can be integrated with Git. This allows you to automatically build, test, and deploy your software every time you push changes to your Git repository. You can configure this by installing the Git plugin and setting up a webhook in your Git repository to trigger a Jenkins build whenever changes are pushed.

How can I troubleshoot issues with my Jenkins setup?

Jenkins provides several tools to help you troubleshoot issues. This includes build logs, which can provide detailed information about what happened during a build, and system logs, which can provide information about the overall operation of your Jenkins server. You can also use the Jenkins CLI or REST API to interact with your Jenkins server and diagnose issues.

How can I secure my Jenkins server?

Securing your Jenkins server involves several steps. First, you should ensure that your Jenkins server is running the latest version, as this will include the latest security patches. You should also configure Jenkins to use HTTPS, which will encrypt communications between your Jenkins server and your users. Additionally, you should restrict access to your Jenkins server by using authentication and authorization mechanisms, and limit the permissions of Jenkins users to only what they need to perform their tasks.

Peter NijssenPeter Nijssen
View Author

Peter is a software architect from the Netherlands. He freelanced for more then 6 years as a web developer, and meanwhile, he graduated as software engineer with honors. He decided to join CMNTY Corporation which specializes in creating community software and is now responsible for the ongoing development of multiple web applications as well as mobile applications. Peter believes a real developer is able to combine multiple techniques together to make sure the user receives the ultimate experience and enjoys using the application. In his free time, he loves to play board games with anyone who is interested. He especially has a passion for cooperative board games.

BrunoScontinuous integrationdeploymentjenkinsOOPHPPHPTesting
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week