Features How-To's Tips & Tricks

Continuous Integration for PHP using TeamCity

TeamCity supports your Continuous Integration (CI) process in many technologies like Java and .NET. It’s not because we don’t provide other technologies out-of-the-box that you can not make use of them! In this post, we’ll put TeamCity to the test and setup a CI process for a PHP project.

We’ll be using the open-source PHP project PHPExcel as a sample project to set up Continuous Integration using TeamCity. This project features a large amount of code, PHPUnit tests and uses Phing to create build artifacts. We’ll use TeamCity to get this process completely automated and ready for immediate feedback once the source code on GitHub changes.

Before setting up our CI process, we’ll assume that you already have a PHP environment with PEAR, PHPUnit and Phing installed. If not, now is the time. You can find more info on installing TeamCity on Linux and on configuring your PHP environment through this blog post.

Setting up the project

We’ll start of creating a new project and build configuration in TeamCity. The build number for this new build configuration will be “1.7.6.{0}” since PHPExcel is currently in the 1.7.6.x range.

PHPExcel comes with a build script that creates build artifacts under the ”build/release/*” folder, which means we can already add that path as the artifact path TeamCity monitors.

The PHPExcel project has a GitHub repository at https://github.com/maartenba/PHPExcel.git, a URL which we can configure in the Version Control System (VCS) settings.

Now let’s add some build steps. Since PHP is an interpreted language, we’ll not be doing any compilation and instead start with…

Unit tests

As a first step in the build process we’re creating, we want to make sure all tests are green. Whenever there is a failing unit test, we want to fail the entire build and not provide any build artifacts. TeamCity comes with a number of predefined build steps for Java and .NET, but since we’re on PHP we’ll have to select the Command Line build runner.

Since we want to run unit tests, the custom script could read something like phpunit -c phpunit.xml to run the PHPUnit configuration that’s in PHPExcel’s source code. Since there are a lot of unit tests to be run, why not report test results to TeamCity real-time so that our team members can see what’s happening? I’ve created a wrapper around PHPUnit which uses service messages to report build results. You can download this wrapper here and locate it somewhere on the build agent or have the build agent download it from the above GitHub repository directly using a second VCS root.

The fun thing is: even without TeamCity knowing anything about PHP or PHPUnit, we can monitor tests in real-time!

Congratulations on your first build for a PHP project using TeamCity! Now let’s add some more build steps since just running unit tests is only the first step…

Build using Phing

Our next build step will be invoking Phing, a PHP project build system or build tool based on ​Apache Ant. PHPExcel comes with a Phing build script which we’ll invoke after all unit tests have passed. Let’s add a new Command Line build step which uses Phing’s command-line tool and pass some parameters to it:

phing -f buildbuild.xml -DpackageVersion=%system.build.number% -DreleaseDate=CIbuild -DdocumentFormat=doc release-standard

PHPExcel has four build targets defined (release-standard, release-documentation, release-pear and release-phar), all providing different build artifacts. The release-standard target which we’ve now specified at the command line is the default build for PHPExcel which generates a ZIP file containing all source code and phpDocumentor output.

We are also passing Phing the current build number from TeamCity using Phing’s -D command line switches. The build script can use these to create the correct file names.

If you haven’t configured the artifact paths while creating our build project, it’s best to do so now (see “Setting up the project”). We want to make sure that the ZIP file generated in this build script is available from TeamCity’s web interface.

Try running another build. You’ll now see that unit tests are being run and afterwards the Phing build script is being run. Once the entire build is completed, you will find the ZIP file generated by the Phing build script is now available for download.

Nice, isn’t it? Let’s see what else is possible. How about…

Code coverage

The first build step we created was running unit tests using PHPUnit. The nice thing about PHPUnit is that it can provide code coverage information as well, nicely formatted as an HTML report. What’s even nicer is that TeamCity can display HTML reports on a custom tab in the build results.

Let’s first make sure code coverage is enabled. Edit the first build step (running PHPUnit) and make sure it uses PHPExcel’s phpunit-cc.xml configuration file for configuring PHPUnit. This configuration file which is specific to PHPExcel outputs its code coverage report in the  unitTests/codeCoverage folder. While it is possible to add all generated files to TeamCity as a build artifact, it’s cleaner to ZIP that entire folder and make it available as one single file. We can have TeamCity create this ZIP file for us by using a special artifact path pattern! Edit the build artifacts again and make sure the following two artifact paths are specified:

build/release/*%system.build.number%*
unitTests/codeCoverage => coverage.zip

That’s right: we can make TeamCity create a ZIP archive from the unitTests/codeCoverage path by simply using => and specifying a target artifact name.

Run the build again. Once it completes, the Artifacts tab should contain the coverage.zip file we’ve just created. Next to that, there should now be an additional tab “Code Coverage” available which displays code coverage results. Since we’re using a TeamCity convention for reporting code coverage, namely creating a coverage.zip build artifact, TeamCity will automatically display the coverage results in a new report tab.

It’s very easy to add additional build reporting and display results from PHP mess detector, PHPLint or even have a tab available which displays phpDocumentor contents by creating custom report tabs based on information from build artifacts.

Of course, all features in TeamCity you know and love are still there. We can view build history, VCS history, commits and so on. We have general build statistics such as success rate, build duration and test count in a graphical format.

When working with an environment based on the IntelliJ Platform, like PhpStorm or WebStorm, it’s easy to link TeamCity with the IDE. After installing the TeamCity plugin into your IDE you’ll notice that there are some useful little things like opening a unit test in the IDE from within TeamCity:

As we’ve seen in this blog post, while TeamCity does not come with PHP support out-of-the-box it’s really easy to run builds for PHP!

Happy building!

image description