Buildman - dead simple Continuous Integration tool

If you have ever tried to setup the Continuous Integration process using one of the well known ‘classic’ tools like CruiseControl you might have been wondering if there’s a simpler and quicker way. I have been wondering too, thus meet Buildman ;)

Buildman is a simple PHP based tool which helps to easily establish a Continuous Integration process for your applications(of any kind, not limited to PHP). There’s a screenshot of Buildman in action:

Buildman is based on Limb3 framework(as well as Syncman) and you can see its “real world” usage at snaps.limb-project.com where it’s used to make nightly builds of all Limb packages.

Some features of Buildman:

  • Simple text files based configuration for projects(no XML)
  • Nice WEB interface
  • Requires only PHP5 CLI for shell based build process invocation(no JVM)
  • Build errors e-mail notifications
  • Subversion repository support
  • Customizable HTML layout templates

If you need more than that you should definitely have a look at the mentioned above CruiseControl, otherwise read on! :)

Try it!

Here’s a quick howto on setting up some imaginary project under Buildman’s control.

  1. Grab Buildman from Subversion repository(there are no official releases yet) into ~/buildman directory:
    svn checkout https://svn.limb-project.com/buildman/trunk/ ~/buildman
    
  2. Create ~/buildman/projects directory, this is where all projects’ settings will reside
  3. Create some project directory ~/buildman/projects/foo, foo in this case is considered to be a unique name of the project
  4. Create project’s settings file ~/buildman/projects/foo/settings.ini with the following contents:
    #path to Subversion project's repository
    repository=svn://myhost/foo
    
    #shell command which should be executed for starting the build process
    #some macro tags(like %project_dir%) are supported, see below for explanation
    build_cmd=php %project_dir%/build_cmd.php
    
    #rotate builds once this number is reached
    max_builds=3
    
    #folks subscribed to get build errors via email
    subscribers[]=bob@dot.com
    subscribers[]=daisy@dot.com
    
  5. Create Buildman VirtualHost in Apache config file(most probably, /etc/apache/httpd.conf), something like this:
    <VirtualHost *>
        DocumentRoot ~/buildman/www/
        ServerName buildman
        ErrorLog logs/buildman-error_log
        CustomLog logs/buildman-access_log common
    </VirtualHost>
    

    In this case you will also need to put “buildman” host name into /etc/hosts:

    127.0.0.1  buildman
    

    Restart your Apache and point your browser to http://buildman. You should see a nice page with foo project on it.

  6. Start the build process by running the following command:
    $ php ~/buildman/bin/build.php
    

But wait a bit! Before you have already started building your project you might be interested to know how it all works. It’s pretty simple.

How it actually works

  1. When the build process is started via build.php script Buildman scans its projects directory and loads each project’s settings
  2. Each project is checked out from its repository into Buildman’s var directory(on later invocations projects are updated not checked out again)
  3. build_cmd script is executed for each project and its exit status is used to decide whether the build was success or failure. That’s why it’s important that your build script returns the proper exit code and also that’s why Buildman can be used for any kind of application, just provide the build script command.
  4. As shown above there are some macro tags which you can use in project’s settings.ini file. One of them is %project_dir%, it’s converted into project’s working copy path stored under Buildman’s var directory(remember, project is checked out from repository?). Without this macro you would have used the hardcoded path which is quite inconvenient.
  5. All builds are put into unique folders which have the following format: ~/buildman/www/builds/PROJECT/rX-YYYY_MM_DD-HH_MM_SS-PROJECT/. In our case PROJECT == foo. max_builds controls how many latest builds should be stored. Each build automatically has zip and gzip archives, BUILD.LOG and CHANGE.LOG.
  6. Folks listed in subscribers[] array will get emails if any errors happen during the build process.

Simple project build script

Now you might be wondering what the build script can be like. In the simplest case it may look as follows:

build_cmd.php

<?php
require_once('simpletest/unit_tester.php');
require_once('simpletest/reporter.php');

$test = new GroupTest('All tests');
$test->addTestFile('log_test.php');
...
exit($test->run(new TextReporter()) ? 0 : 1);

Again, please pay attention to the last line: it’s the exit status which defines if the build is successful or not.

Running Buildman

Well, that’s actually it. Now try starting the build process:

$ php ~/buldman/bin/build.php
============================= Building 'foo' =============================
Starting fresh build of 'foo' project...

Updating working copy

Executing 'svn up --non-interactive ~/buildman/var/wc/foo'...
At revision 12.
finished.

Syncing working copy with temp build directory...
finished.

New build is 'r12-2007_11_04-02_45_26-foo'

Executing 'php  ~/buildman/var/projects/foo/build_cmd.php'...
TestSuite
1 of 17 done(log_test.php)
...
17 of 17 done(event_test.php)
OK
Test cases run: 17/17, Passes: 719, Failures: 0, Exceptions: 0
14.018 sec.

finished.

Build is successful!

Copying build directory to web builds..

Zipping new build..

Gzipping new build..

Removing junk..

All done!

Once finished visit the Buildman’s virtual host we installed above - there should some changes indicating the new build of the foo project.

You can have as many projects under Buildman’s control as you need: just add the new project’s directory and settings.ini file.

The final question is what is the best way to trigger the build process. Well…it depends. If you’d like to start the Continuous Integration process on each commit just add something like this into your Subversion repository post-commit hook(read more on hooks here in “Hook Scripts” section):

...
php /path/to/buildman/bin/build.php projectname
...

As you can see, it’s possible to pass the concrete project name to build.php thus starting the build process only for this project.

Alternatively, you can start the build process by cron, say, every night.

I hope to release the official version of Buildman quite soon, once some pending TODO items are resolved(most notably, builds RSS support and tests code coverage integration). If you find Buildman any useful or have some questions and ideas on how to improve it, please post your feedback ;)

Leave a Reply