This last 6 months, I had the chance to use many new & cool tools for PHP:
Composer, the ultimate dependency manager for PHP projects. If you’re not already using it, I strongly encourage you to test it ASAP.
Symfony framework, I started to work with the first version 3 years ago and this new version is a master piece, even Drupal announced that the next version will rely on it.
Atoum, as mentioned in my previous post, I moved away from PHPUnit for this new unit tests framework.
phpDocumentor, if you missed the big news: DocBlox and phpDocumentor merged and the alpha preview of the next version is already awesome.
Previously, our Symfony projects used git submodule, PHPUnit and DocBlox, so I had to update our CI configuration (Jenkins and Sonar). In fact, it was pretty easy because all our builds are managed by a custom version of the excellent php jenkins template. Here’s a quick list of the updates for this new stack.
Add atoum dependency with composer
The standard edition of Symfony relies on composer, it’s trivial to add atoum. Yet William Durand suggested a nice practice: add this “dev” dependency in the suggested packages instead of the required packages. This way, your production stage avoid useless packages and you just need an argument to fetch the optional packages “php composer.phar install —install-suggest”.
Create an abstract test class
Atoum code convention is “full lower case” and the test framework expects your tests to live in a namespace “tests/units”. Since Symfony uses capitalized namespaces, we have to make some adjustments:
This abstract class will be extended by all our test classes, it redefines the “expected” namespace for atoum to “Tests\Units”. Since there is no Symfony AtoumBundle for the moment, this class should live in a bundle (to be autoloaded).
Create the atoum configuration file
As PHPUnit, atoum accepts a configuration file conventionally named “.atoum.php” at your project root. I only use this configuration file for the remote CI plateform, so I named this file “.atoum.ci.php” and I define some specific reports (xunit, clover, coverage).
Warning, at the moment xunit and clover reports are wip. It will be merged soon, yet to ease our processes, Plemi provides a fork with a branch “clover-xunit” including all of these features.
Add composer step to ant
Nothing magic here, we just need to download composer and run the dependencies installation. Yet don’t forget to update the “clean” task (to remove the composer files).
Add atoum step to ant
Again, as PHPUnit, atoum provides also a CLI. The -g/—glob options was added recently, and allows regex pattern and wildcard char. For the bootstrap file, be lazy, just use the app/bootstrap.php.cache generated by Symfony. Note: if you didn’t place the previous abstract tests class in a bundle, you should handle this file manually. Here’s the ant target in my build.xml file:
Add phpDocumentor step to ant
phpDocumentor is installed with PEAR, so the only thing we need is an Ant step to generate the code documentation. Good news: the CLI argument are exactly the same as DocBlox.
That’s it! if you already used the php-jenkins template before, you should be able to have all your previous metrics in your jenkins job. You may notice that the “clover HTML report” is a bit different, it’s not generated with PHP CodeCoverage anymore but with the native html report writer from atoum.
What about Sonar ? Since the version 2.14, I wasn’t able to import the clover xml reports generated by atoum, It’s because PHPUnit doesn’t generate a standard clover file and so the sonar plugin isn’t able to parse the standard file from atoum. Hopefully, Julien Bianchi is working hard on atoum integration in sonar with a plugin and will release it in “the next days”.
Bonus track #1: To run atoum test in your local environment, here’s the command:
Bonus track #2: here’s is a full template of an ant build.xml for a Symfony project using composer, atoum and phpDocumentor 2 (used by Plemi)
At my new position at Plemi, I want to optimize the continuous integration flow. Last week, I had a pretty interesting conversation with Mathieu Nebra, we discussed about our same quest: best ROI through the development flow. I also had an awesome experience with Antoine Guiral (the man behind twoolr), we shared a “lean startup" friday night around a very interesting project.
In my previous article, I introduced a pragmatic Git flow. A first step in the flow focused on the local environment of the developer. I like to start this post with a personal, yet simple consideration : “the trust in your development team is reflected by your CI flow”.
It’s very reductive but the github flow is a perfect example. It’s composed of only one master stable branch and several feature branches, the production flow is deadly simple. However Github uses Github (dog fooding for the win) and this flow strategically relies on it own awesome feature called pull request. Sadly, I can’t afford to use github everywhere for many -good and bad- reasons. So I tried to set up a flow with a self-hosted git repository coupled to our continuous integration server
Overview of the development flow
- A Developer works on their local git repository in a dedicated feature branch
- He pushes often as he can (min 2 in a day) to the remote feature branch
- The CI builds on every push, merging the trunk and his feature branch
- When a feature is over, the developer merge it back to the trunk
The context and the tools
For the new comer, a quick summary of the tools used in this flow
- Source code management with git
- Branch management is based on the git flow template
- Continuous integration rely on Jenkins
- Code quality rely on Sonar
- I work with PHP, yet the flow can be used in other langage
The flow starts on the developer side
I already wrote on that topic in my previous article. In short, the developer works into a feature branch named against this pattern: "feature.ticketNumber_description". He writes code without worrying about the SCM. Then, he dedicates some time to nicely split his work into several independent commits. If it’s needed, he can rebase his local branch. Finally he pushes the commit pack.
On the continuous integration plateform side
We have two jobs for each repository: one for the develop branch and another one for all feature branches. The feature job is configured to build every branch with the pattern “feature.*”. Jenkins is notified after each push by a git post-receive hook.
Tip: this hook doesn’t start a build, it trigger Jenkins for a SCM polling. In this way Jenkins will start to build only if there is relevant change(s) in the repository. Read the official documentation: “Build by source changes"
I configured Jenkins to merge locally the lastest pushed branch with the develop branch. This allow an early and cheap detection about merge conflicts.
If Jenkins can’t merge automatically, it fails the build and the developer is already aware that he needs to manually merge back the develop branch into his feature branch. He can’t delay this conflict resolution because it blocks the CI process: checkstyle, unit tests and coverage won’t be available to him until he resolves the merge.
This continuous merge process has the huge advantage to avoid the nightmare of a messy merge while your developer responsible of a shitty conflict is unreachable for an undefined period.”
Don’t trust Jenkins too much
I don’t use "push after a successful build" option provided by Jenkins. Basically, This allows you to automate the integration process: if a build is stable it will push the new modification to a remote branch. Yet, it don’t fit our needs since I ask the developer to push everyday. Many features need more than one day to be achieve and I won’t let Jenkins push some kind of work in progress.
Don’t trust a single developer
I don’t rely too much on Jenkins and this is also related to my first quote: I work with a pretty nice team but “I don’t trust a single developer” (and even myself!) about building the perfect git log (i.e. the perfect code) in a one shot. We are all new in the company and we need to practice a little bit more with the processes or the new coding standards for example.
Trust your team
Moreover, when I say: “I don’t trust a single developer”, it’s a way to highlight the code review phase. When a feature is closed, it must be fully reviewed and discussed by a technical leader before being merged into the develop branch. This has 2 majors consequences: First I can’t let Jenkins automatically merge into the develop branch; second, the technical leader is free to make a final rebase of the feature branch before the merge. This ensures a stable and clean develop branch.
Finally, we have to distinct the 2 usages of develop. Jenkins use this branch locally as an integration branch for each feature while the remote branch reflects the lastest stable version ready to be checked by Q&A and then deployed.
What’s next ?Depends on your need, you’re free:
- Everything go to the production.
- You launch some stress test on a staging server and then deploy to prod
- You notify your Q&A and expect a final feedback
At our office Q&A check is “asynchronous”, it can be delayed from 1 to 3 days. That’s why I’m still using the release branch from the git flow template. I freeze develop into release and wait for a Q&A feedback. If it’s a green light, I’ll deploy the release branch.
I customized the git flow for my need, we don’t use the “release” concept because we deploy ASAP each feature. This flow fits perfectly to the AGILE methods. You collect technical metrics sooner and it’s simpler to detect and to fix potential problems on a small iteration. Your project manager/product owner collects user feedbacks sooner, easing the business decisions for the next sprints/features
I mentioned 2 jobs for each repository, one job is limited to the develop branch and serves the code quality purpose, metrics from this job are exported to Sonar
Continuous integration is not a new concept in software development, yet it’s a trending topic in the PHP community. Actually, the PHP development is evolving to a professional step. AGILE processes are spreading the web development world and so the continuous integration becomes a real business need.
This is a short and condensed introduction to the continuous integration in PHP. My next posts will cover deeply some parts. The main purpose of this blog is to provide keywords and concepts to ease your research.
I discovered the test-driven development more than 3 years ago in the symfony 1 documentation. This framework embeds a rudimentary, but efficient, test suite called lime. Frankly the tools don’t matter without the real will to improve your code quality.
The first question for many companies is: how much will it cost?
The long version : how much time/money will I have to spend to get a more reliable product or service? For this wrong paradigm, my answer is a reversed approach: could you estimate precisely the time/money lost without a continuous integration process?
To be honest, for lightweight projects, it’s still possible to evaluate the maintenance cost. But for huge projects using legacy-hard-coupled code, it’s a nightmare.
The customer, the boss or the developers love a bug tracker when it’s empty. The idea behind Test Driven Development (TDD) is to test your application before the release instead of fixing it after. Yes, it’s an extra cost on development estimated to 20% by Hugo Hamon from Sensio.But try to estimate the cost of your maintenance time and compare it. With the classic Blind Development you can’t predict it, since you have no reliable metrics on your application.
Test-driven development and continuous integration come to the rescue and don’t only allow a correct planning, it also reduces the number of “friday’s night emergency fix of the magic bug”. In short, everybody is happy : the customer, the boss, the wife and thus you too.
Unit test, functional test, acceptance test… These are answers which could and must be combined to match your need. Below is a quick summary and a tool kit for each purpose.
If you’re new to TDD or if you have short deadline : focus on unit tests. It’s the first mandatory step for the backend development which will reward you greatly. For php, consider phpUnit which is the actual standard, but keep also an eye on atoum. I believe that Behavior Driven Development should be use for acceptance, yet phpspec, mentioned by @andhos on twitter, offers a different approach : it’s a BDD framework focused on unit testing.
Sometimes you will need to test your whole application and probably by the presentation layer (i.e. almost like an user). Two solutions are available, first “Headless browser emulators” which are fast and reductive test focused on raw http output (See Goutte or Zombie.js). A second option are “Browser controllers” which simulate navigation with advanced js for example; you can use Sahi which replaced the famous Selenium.
To go further, look at Mink. It’s a web acceptance test framework based on the behavior test framework Behat (a port from cucumber in php). Mink provides an abstract layer for the web acceptance test which could be then executed by any tools mentioned above.
Beyond the test, lot of metrics can be collected about your code like cyclomatic complexity, duplicated code, coupled code… Furthermore, code standards should be controlled by a tool rather than an human eye. See Pdepend, phpmd (Mess Detector), phpCPD (duplicated code)…
Testing is one purpose, automating test is another one.
Let me introduce the gentleman called Jenkins (previously called Hudson), an open source java CI server. It’s the standard in this business. Sonar is another CI server, also in java, providing a nicer web GUI than Jenkins and maybe the nicest web GUI on the market for this concern. Finally, 2 new comers, first Travis CI a PaaS solution perfectly plugged with github, it’s a very sexy beta software. Second, mentioned in the comment by Pedro Mata-Mouros, an interesting solution called Cintient. It’s a beta but it seems to provide a cool UI with a minimal setup flow. I have to try it, yet expect a feedback on this blog soon.
For the deployment, only one answer : Capistrano. An unvaluable ruby tool for automated deployment processes.
Last thing, PHP is open-source like all the tools mentioned in this post. Most are hosted on github and provide a pear package. So now, you have no excuse to don’t start right now to improve your developments.
EDIT : thanks to the comments, I’ll added Cintient CI server.