Continuous integration with Symfony2

There are many great articles that tells you why you should use continuous integration i.e. the one by Martin Fowler and the book This is Lean by Niklas Modig and Pär Ahlström. This article describes our workflow and what tools we use to achieve continuous integration and extreme programming. We are doing most of our developing in Symfony2 and we are using tools like Jenkins, Sonar, Ant and a bunch of homemade services and scripts. 

We use Jenkins as a continuous integration server. Jenkins is a great platform where you can add on other services that may run analysis, tests, generate reports etc. Whenever we do a push to our Git server, Jenkins will start to “build” the project. We have defined an Ant target to specify what to do when the project is being built. The instruction file for Ant is called build.xml and it is basically a list of tasks. (You will find a reference to our build.xml at the bottom of this page.) At each build we tell Ant to:

  1. Purge the cache
  2. Create some folders, like app/build/logs
  3. Run composer update
  4. Run PHPUnit

We have instructed PHPUnit to generate both test reports and code cover reports. After all the above Ant tasks have succeeded, Jenkins will send the code to quality analysis.

Code analysis with Sonar

Sonar is a great peace of software from Sonarsource. It is a platform for code analysis. Sonar supports a lot of common programming languages. I’ve installed the PHP package which contains HP Depend, PHP Mess Detector, PHP CodeSniffer. Together with the Sonar core and a some nice quality profiles it will help us find bugs and make the code uniform. We’ve made some strict rules that will fire alarms if the code contains more than 5 major violations or if the minor violations has increased with more than 15 since last week. When a alarm is fired Jenkins will mark the build as failed.

Except from code style Sonar will also measure complexity and find logical bugs. Sonar once told me I had to rewrite a function because it was over 100 possible execution ways through that function…

The first couple of weeks with Sonar was pain. Each commit we did had a lot of violations and we thought it was just slowing us down. But soon we learned how to write code with no violations and it really made our code more uniform and easy to read and maintain.

Another great code analysis software for PHP is the SensioLabs insight. Sonar and SensioLabs insight should both be used as they complement each other. SensioLabs insight detects much more sophisticated errors and security vulnerabilities.

Download our Symfony2 Sonar quality profile.

When build fails

When a build fails (i.e. when the PHPUnit or the analysis fails) Jenkins will stop the execution flow and send an email to whoever broke the build. The code must not proceed to the development or production servers.

I’ve read some examples of companies who have implemented some sort of monitoring of the builds. You may see build status in Jenkins but it would be a lot cooler to have a red lava lamp that gets turned on when the code in the master branch does not pass the tests or quality profile. If the build is broken for 15 minutes or more the lava lamp bubbles are starting to move. =)

Distribution to test and production

If the build passes both the test suite and the quality profile it is time to deploy the project to a development server. This is done at each successful build. You may run more manual tests and/or QA tests on this server. It is also a good place to let you manager try the new features.

Jenkins should also be in charge of deployment to the QA server and production server. I prefer to start those deployment myself by clicking on a button in Jenkins but I know of developers that would like to deploy to production when pushing to the “production” git branch.

Our deployment is a Ant target. Ant will:

  1. Do a git pull
  2. Put the site in maintenance mode
  3. Run composer install
  4. Migrate the database and clear APC cache
  5. Install new bower dependencies
  6. Run Assetic dump
  7. Clear and warm up the cache
  8. Remove the maintenance mode

Since Jenkins is running on a different server than many of our application I tell Jenkins that a deployment is to start a shell script. The shell script uses ssh to get to the production server and then start the Ant task from there. It is possible to set up Jenkins to communicate with other servers but I prefer to keep things simple.

Download our Ant build.xml.

Choose your tools

Which tools and services I use is not too important. What you should learn form this article is the workflow, the concept and that automation is key. If you are a .NET developer you might file that TeamCity is a much better choice over Jenkins or if you feel like using Capistrano instead of Ant that is fine. The concept is the same and you will achieve the same results no matter the name of the tool.

8 Comments

  1. Thanks for the great article!

    Reply
  2. Great article, do you also consider to backup your database when you need to update your schema?

    Reply
  3. ” At each build we tell Ant to: run composer update” …
    IMO it should never happen. Composer updates should be made on Your dev env and then composer.lock should be commited and pushed to repository. Running composer update when building prod/stage is asking for troubles if You don’t have strict declared versions in composer – not every bundle provider is providing compatibility even on minor version bump.

    Reply
    • Agreed. Learned this the hard way. Run composer install on production environments.

    • Couldn’t agree more. Always use composer.lock and composer install for keeping consistency and stability between instances.

  4. Thanks so much for putting this article together. It’s giving me a good jump start into CI with Symfony2.

    One question: How are you handling database schema migrations?

    Reply
    • Database migrations are hard. I use DoctrineMigrationBundle and I make sure that only use migrations that do not break BC.

      Example: I do not rename a column, instead I add a new column and removed the old one some weeks/deploys later.

Submit a Comment

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

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>