Two web artists. One amazing company.

Using per-project Drush commands to simplify your development

from Michael Prasuhn on February 19, 2013 08:45am


Developing a large Drupal site is no easy task and managing all the latest tools isn't getting any easier. Between SASS, Compass, Simpletest, Guard, Behat, Capistrano, Git, and sometimes even Drush itself, you've got alot of commands to master. Trying to remember all the right flags and syntax can be a nightmare that ends up requiring it's own documentation page just to get all of your team on the same page. If you've ever caught yourself or another developer asking someone to paste a command into a chat window, or sharing their shell history via email, it's time to simplify things by writing your own Drush commands.

While you could always write shell scripts or even use tools such as make and Rake, Drush has plenty of features to handle all of the above use cases and more. Even better, Drush's tight integration with your Drupal site make scripting and automating things easier than ever.

Getting started: Drush shell-aliases

The easiest and simplest way to get started with per-project Drush commands is to wrap them with what Drush calls shell-aliases, which are a concept borrowed from Git. The basic idea is that you can give your Drush commands (with specific arguments and options) an alias, and you can even specify an alias for any command line you would execute. There are plenty of examples in the Drush documentation but I'll include a few examples here to get you started.

To start, make sure you have a drushrc.php file saved in your site directory, either sites/default/ or sites/ Once you have that setup, you can replace a command such as drush rsync @prod:%files/ sites/default/files/ with a short alias like this:

$options['shell-aliases']['dl-files'] = 'rsync @prod:%files/ sites/default/files/';

Now, typing drush dl-files will allow perform the same action with alot less typing. (Assuming you have your Drush site aliases setup correctly, which I won't be covering here.) While that's a semi complex example, imagine more complex command such as drush sql-sync @prod default --no-cache --dump-dir=/tmp --structure-tables-key=common --sanitize. Drush shell-aliases make running commands like this much easier and provide consistency among team members.

It may seem that the above examples are fairly simple, or that they aren't necessarily project specific either. These could probably be put into a per-user Drush config, but then you'd have to worry about any changes being properly updated for each team member. If they are stored with the project you can be assured that any team member is guaranteed to have the latest versions if they are in version control along with your site's code.

More advanced: Custom commands

There are times when you're going to need a little bit more interaction with your site than a simple shell-alias can provide. For example here at Shomeya we do almost all of our theming with SASS and Compass which allow us more features in our stylesheets at the expense of requiring them to be compiled before they can be previewed in a browser, or committed to version control. These steps require specific options passed to the compass command, which needs to be run against a specific directory. The easiest way to implement this, is to write a simple project specific Drush command.

To get started with custom commands, you'll need to add a command file to sites/all/drush/. I suggest using the name or your site or project to avoid conflicts with other Drush commands, for example In this file you'll need to define a few hooks, the first is COMMANDFILENAME_drush_command() which uses the first part of the file name as the 'hook' name. In our case it might look something like this:

* Implements COMMANDFILE_drush_command().
function PROJECTNAME_drush_command() {
  $items = array();

  $items['compile'] = array(
    'description' => "Compile bundled assets such as SASS or SCSS files.",

  $items['watch'] = array(
    'description' => "Watch SASS and SCSS files for changes.",

  return $items;

This hook describes the commands that are contained in this command file. Here we've just described two commands, and specified the required bootstrap level along with a description to be displayed along with drush help. This only implements the basic options that are required, but there are many more keys described in the Drush commands documentation.

To actually implement those commands, we'll need to define one function for each command that follows the pattern of drush_COMMANDFILENAME_COMMANDNAME. For example, here's the compile command defined above:

* Command callback for compile command.
function drush_PROJECTNAME_compile() {
  $path = drupal_get_path('theme', 'theme name goes here');
  $command = 'compass compile ' . $path . ' --force -e production -s compressed';
  if (!drush_shell_exec_interactive($command)) {
    return drush_set_error('COMPASS_ERROR', dt('There was an error compiling the CSS with Compass.'));

This command is pretty self explanatory, but provides alot of power by being able to hook into Drupal APIs such as drupal_get_path() to get the correct path to the theme. By using this in conjunction with the bootstrap level specified above, DRUSH_BOOTSTRAP_DRUPAL_FULL, it's now possible to run this command in any directory or sub directory of your Drupal site and Drush will always find the correct directory by running the exec command from the document root. Now you can run drush compile and you can be sure that your SASS will be compiled with the same settings by each developer on your team.

In conclusion

Project specific Drush commands are easy to write and provide a great way to automate and simplify all the tasks that you need to execute as part of building a Drupal site. Writing custom Drush commands allows you to unify your workflow around the one tool that every Drupal developer must know and use. As a final bonus commands are easily indexed and scanned by running drush help and they are easy to version with your Drupal project's repo enabling your code and tasks to be documented for the next person to work on the site.

blog comments powered by Disqus