At work, we have a Jenkins server. I love the butler. One thing we use it for is making nightly snapshots of our distribution, Demo Framework. One cool feature of Jenkins is that I can tell it to email me when the build fails. (Of course, this always seems to happen on a Friday night!) Sometimes the build fails due to network errors, so when I received an email on Friday that the build broke, I didn't worry.
"If it breaks again tomorrow, I'll check on it," I said to myself. Well, it broke again tonight and this time it wasn't because of code that I had committed or network problems. Now my curiosity was peaked - I had to login to Jenkins and see why the build was failing. I quickly saw an error was being thrown before the build could even get rolling.
PHP Warning: require(/home/jenkins/jobs/workspace/demoframework-tarball/drush/vendor/autoload.php): failed to open stream: No such file or directory in /home/jenkins/jobs/workspace/demoframework-tarball/drush/includes/bootstrap.inc on line 1007
One unique feature of this particular build is that we pull down the latest HEAD of Drush to run drush make for packaging the distro. Now, yes, this is kind of crazy. The maintainers of Drush might cringe at this, but I don't mind being a guinea pig. This particular job has been running for the better part of a year and Friday was the first time it failed because of Drush. So I trust drush-ops won't commit bad code - but it doesn't mean they won't commit new "features" that break the build.
In order to debug why drush was no longer working, it was fairly easy to visit the drush commit log on github and look for commits from the day that the build broke. There were only 10 commits on this day, and I noticed that one commit had the message, "Fix #127. Fetch external libs with composer, and use Composer autoloader..."
This explained everything I needed to know. Composer is great and the fact that Drush is now using code from other PHP projects is double great. This is a pattern for Drupal starting in D8, so it only makes sense that Drush would do this.
It was a quick fix to add downloading and configuring Composer as a part of the build. (Ok, so it took a few test runs, but I got things working...) Here's what our current build looks like:
#!/bin/bash echo "Building Demo Framework Nightly Snapshot" rm -rf df_checkout git clone --branch 7.x-1.x http://git.drupal.org/project/df.git df_checkout echo "Checkout Composer" rm -rf composer git clone firstname.lastname@example.org:composer/composer composer echo "Install Composer" rm -rf composer.phar wget http://getcomposer.org/composer.phar cd composer && php ../composer.phar install cd .. echo "Checkout Drush" rm -rf drush git clone email@example.com:drush-ops/drush.git drush echo "Install Drush dependencies" cd drush php ../composer/bin/composer install cd .. chmod +x drush/drush echo "Prepare output directory" rm -rf build_df mkdir build_df echo "Run the build" drush/drush make --no-cache df_checkout/build-df.make --tar build_df/df_nightly_dev_snapshot_`date +%s` -d --concurrency=1
Originally, we were just checking out Drush and using it straight away. The new build requires downloading and installing Composer first. We then have to move into the checked out drush directory and run composer install to get the required autoloader. Then voilà - the build is upright once again.
Until next time, that is.