Continuous Integration with Jenkins, Part 1
Continuous integration is a software quality control technique that checks code integrity whenever small changes are made rather than waiting for all of the code to be finished before testing and debugging it.
CI asks for version control and for automated unit testing and constant package building. In principle, the automated part of the cycle can be done with cron jobs that trigger programs like xunit (tester) and make (builder). However, more convenient and resourceful tools have emerged in the last few years, like Jenkins, which is combines automation and supervisory tasks into one single system.
What Jenkins does is not difficult to understand once you know why it does that. In this 2-part series I’ll present a big-picture overview of the sort of programming problems CI can solve, show how it can be achieved with the help of specialized software and explain how Jenkins can be minimally used to periodically trigger testing and building of PHP (web)applications, keeping a record of where integration succeeded or failed and maintaining an “output” folder up-to-date with the latest files that the application requires, ready to be uploaded to the server.
By the way, I do not have to be concerned with making the reader an expert in Jenkins because it is so easy to use that once its basic purpose is understood the sophisticate resources follow naturally.
The Big Picture
Implementing its early retirement program, The One Big Worldwide Corporation, Inc. offered its employees suggestions on how to use their new quality time. One was programming for the web whether for fun, community service, or as a small business of their own. Several people showed interest and the training department bought them a series of very nice books on all aspects of web design and development published by an Australian company who also maintains some of the world’s finest websites on the subject.
Among those who jumped into PHP programming for the web were three former foreign trade operators who, having worked often together in the past, decided to set up an on-line network of former employees: Bertha, who lives in Buenos Aires, Argentina, Alicia, who resides in Yokohama, Japan, and Miwa from Bonn, Germany. Also, Guido, the former HR man in Torino, Italy, decided to create his own web development and hosting business.
To get started with their networking application, Bertha offered to write the database searching script while Alicia volunteered to develop the HTML interface and Miwa decided to attack the code for adding/editing/deleting records. They agreed to meet on-line once a week to test out their results.
The first couple of weeks things went smooth but soon after problems arose as Bertha decided that naming variables in
$camelCaseNaming did not look good and changed everything to
$underscore_separated_names, Alicia renamed some of the interface form fields and Miwa changed the way the database dealt with dates. When they got together and tested the application, errors began to pop out as corn from the One Big Worldwide Corporation’s One and Only Famous Popcorn Machine.
Meanwhile in Italy, Guido was having a hard time keeping track of the development files scattered all over his hard drive, some newer and some older than the versions on his clients’ servers, so that fixing a problem on one website invariably broke another.
The ladies and Guido were in what is sometimes called “integration hell” out of which the way is lots of praying to St Isidore, taken by some as the patron saint of the Internet, or continuous integration.
Continuous integration (CI) is a development method where any change, no matter how small, to a file must be documented, tested, and sent to a central version-controlled repository and packages are built in a planned manner, leaving out everything that is not required to run the application.
Continuous integration helps make sure that everybody is working on the latest version of code, that no unannounced changes in file A compromises the development of file B, that at most a few corrections are at any time required to get B back into working with A and that packages are self-contained, neatly organized, and free of unnecessary intermediate files.
After reading Sean Hudgston’s excellent article Introduction to Git, which I recommend to those that still need to get acquainted with this terrific tool (I mean, now!), the ladies and Guido decided to use Linus Torvalds’ repository manager Git to try to get all their code organized in one place.
As he worked alone, Guido set up a repository on his desktop machine creating an umbrella directory (
/www) with a subfolder for each project, like
The ladies needed a remote repository that everyone could access, and they opted for a GitHub account creating a project they called “former_employee_net” and agreeing that everyone would
git add a file as soon as its creation or editing was finished.
The fundamental step in testing software is continuously checking whether new code works as it is supposed to before committing it to the Git repository. This is called unit testing, and it can be carried out in PHP with the help of Sebastian Bergmann’s PHPUnit framework.
Apparently it was Miwa who read my colleague Michelle Sanver’s Getting Started with PHPUnit and began to write tests for her part of the application. This proved a success and was soon imitated by the others.
Once code was shown to be functional and was committed to the repository, there was the matter of creating packages for easy deployment to the production server, by separating the files that were needed for the application to run from those used to support development.
Put in charge of that for the ladies’ team, Alicia wrote down a list of file types to be left out (like .xcf files for Gimp image projects) and a list of those (like .php and .png) to be included in the compressed file. That was easy, but error-prone.
Apache Ant runs a batch of tasks otherwise done one-by-one. It reads a user-created script with actions like “copy this to there” and “delete that from here”. Guido was already using it, and he referred Alicia to the Ant tutorial on Apache’s website. Very shortly she created her own script and began automating not only the builds but also the testing.
In theory it all works fine, but, Alas, poor Yorick!, in practice other problems soon arose. Miwa missed some unit tests causing the group to spend time on bad code that eventually had to be fixed. By his turn, just to be on the safe side, Guido was spending a lot of time repeating tests he wasn’t sure he did or not.
And both the group and the lone developer forgot more than once to build a package which resulted in older, broken versions of some files finding their way on the production servers. That’s where a supervisory tool came in.
Created at Sun Microsystems by Kohsuke Kawaguchi, who seemed to have had enough of manual integrations, Jenkins began life as Hudson, a CI automation supervisory environment written in Java. With Sun’s absorption by Oracle, the community changed the name from Hudson to Jenkins which amounted to a de facto forking.
Jenkins, and for that matter Hudson, looks after the running of various tasks required by CI while helping to improve coding style, looking for duplicate code and statements that seems needlessly complex. Jenkins was created for Java development but with the help of plugins now it can render services to many programming languages.
In the second part of this article we will install and set Jenkins up to control the periodical test and build of a simple PHP project, which also requires version control, unit testing and build automation programs. We’ll end this first part by installing those.
Git, PHPUnit AND Apache Ant
Before we can use Jenkins with our PHP demonstration project, we need to install Git (revision control system), PHPUnit (unit tester for PHP) and Apache Ant (package builder).
Git is available in Linux code reps and their website offers installers for Mac and Windows. Once installed, check it by typing:
jajeronymo@server:~$ git --version
PHPUnit should be installed with the help of PEAR, the PHP extension and application repository, no other way. In Linux make sure your PEAR is the latest stable version and run:
jajeronymo@server:~$ sudo pear config-set auto_discover 1 jajeronymo@server:~$ sudo pear install pear.phpunit.de/PHPUnit
After the usual installation progress output is over, check it works:
jajeronymo@server:~$ phpunit --version
Apache Ant is Java software too and do not need an installer. The binaries packages are available from their download page. Major Linux distributions may have packages in their repos. Once you have installed it, again, run a test from the command-line interface:
jajeronymo@server:~$ ant -version
Note that Ant requires only one dash before the option “version”!
At this point we have all we need except Jenkins itself which will be covered in the second part of this article. Until then, take care!