Most of the Symfony based applications use Capifony for creating a continuous delivery pipeline but sometimes it’s not flexible enough. Because of this reason I’ve decided to create a different approach (which can be seem a bit old-looking but it’s easy, trust me).
First, let’s take a look at the process:
Okay, we want to make sure that no bug can get through our pipeline. For this reason we try to set up as many traps as we can for bad code. Here is my pipeline for this job (for web applications):
- Creating code
Developers commit code on feature branches. After the Code Review, the code can be merged back to the develop branch.
- Starting the pipeline
At a fixed time (somewhere in the morning) the pipeline starts and pulls the latest code from develop branch.
- Static analysis
First step is to make a static analysis on the code to detect possible defects and bad design, typos, etc.
- Unit testing
This step should be no longer than a few minutes. It’ll test our business logic without any dependencies (database, message queues, caching servers, etc.).
- Functional testing
The code is tested in this step completely. It is the longest step as it uses all of the other services, like: database, message queues, etc.
- Manual testing
Simultaneously with the previous steps a manual testing server can be set up for manual testing. As we’re in Continuous Delivery this server should be used for usability testing and not functional testing!
- Pushing changes to master
If everything is fine, we can push our tested code into master branch. This branch represents the stable code and will be released onto the production servers.
This is the easy part. You have a fully tested code, you just have to make sure that everything goes into production without any issues. The following steps are needed:
- Getting out the server from production
This step can be done by either putting out a “Maintenance in progress” page or by reconfiguring HAProxy/Nginx proxy/etc. to redirect traffic elsewhere.
- Backing up database
We want to make sure that if anything happens during the upgrade process, we won’t lose any data. Our worst scenario is to roll back everything to the previous state.
- Upgrading the codebase/database
- Putting back the server into production
If everything went fine, we can redirect back the traffic.
Implementation with Symfony
For creating a completely trustable CI/CD environment, I use PHPUnit for unit testing and Behat for functional testing. Feel free to replace them with your favorite frameworks.
For this solution I use the following tools:
- Symfony, obviously
- Phing, to create extendable commands with a single commit and to group the commands
- Jenkins, as the backbone of my Continuous Delivery system
And for Symfony, you’ll probably need the following bundles/libraries:
- doctrine/doctrine-migrations-bundle, for database migrations
- lexik/maintenance-bundle, for displaying a nice looking message during the update
- phpunit/phpunit (dev), for unit testing
- doctrine/doctrine-fixtures-bundle (dev), for functional testing
- behat/symfony2-extension (dev), for functional testing (framework)
- behat/mink-extension (dev), pre-defined BDD elements for functional testing
- behat/mink-browserkit-driver (dev), for running the tests in headless mode
In case you would like to dive deep into Continuous Delivery with Symfony, go ahead and clone a pre-prepared skeleton project. You can find additional information in the
Readme.md file in the repository.