Run Drupal updates directly after enabling a deployment module

Drupal Deployment Module

When rolling out changes to a Drupal website I often use a deployment module to handle all of the updates. The module is made up of implementations of hook_update_N() in an .install file. Quite often the updates just consist of enabling or reverting features, but much more complex updates can also be included. Here's a sample deployment module .install file:

<?php
/**
 * @file
 * Update hooks for deploying changes to the Delicious Creative website.
 */

/**
 * Enable some features.
 */

function delicious_deploy_update_7101() {
 
$module_list = array(
   
'my_feature',
   
'my_other_feature',
  );
 
module_enable($module_list);
}

/**
 * Revert some features.
 */
function delicious_deploy_update_7102() {
 
// Revert features
 
$revert = array(
   
'my_content_type' => array('node', 'field_instance', 'field_group', 'variable'),
   
'my_variables' => array('variable'),
  );
 
features_revert($revert);
}

/**
 * More updates...
 */
function delicious_deploy_update_7103() {
 
// More updates go here.
}
?>

Now to roll out those changes on the live site just update the code and run drush updb, or visit /update.php. I've found deployment modules invaluable for complex deployments, testing deployments, keeping track of changes, and letting clients or other non-technical users run the updates when I'm not the one doing the deployment.

But what if the site you need to deploy to doesn't already have a deployment module installed? If you create a new deployment module with all of your updates and enable it, Drupal won't recognise that the updates need to run since it's the first time the module was enabled. So how do we get Drupal to recognise that we want to run those updates?

One way to is to leave all of your updates out of the .install file and install the module on the site you're deploying to. Then add in your updates and when you next update the code on the site you're deploying to Drupal will recognise that those updates need to run. But that sucks and we can do much better.

Usually Drupal will set the schema version of a module to the last update hook number during the module install. This is what determines if updates will need to be run when updating a module. In the example from above the schema version would be set to 7103. So if the schema version in the system table is set to 7100, anything after that will be flagged as necessary to run. If we manually set the schema version to a smaller number with a drupal_set_installed_schema_version() during install we can instantly run updates after enabling our deployment module.

<?php
/**
* Implements hook_install().
*/
function delicious_deploy_install() {
 
// Set an initial value for the schema version so we can run updates after install.
 
drupal_set_installed_schema_version('delicious_deploy', 7100);
}
?>

With that in place the schema version of our deployment module is set to 7100 during install and Drupal will recognise that our updates, which start at 7101, still need to be run. Using Drush to run the deployment means that all you have to do is:

drush en delicious_deploy -y
drush updb -y

And that's pretty darn cool.

Here's the final .install file of the module all put together:

<?php
/**
 * @file
 * Update hooks for deploying changes to the Delicious Creative website.
 */

/**
* Implements hook_install().
*/

function delicious_deploy_install() {
 
// Set an initial value for the schema version so we can run updates after install.
 
drupal_set_installed_schema_version('delicious_deploy', 7100);
}

/**
 * Enable some features.
 */
function delicious_deploy_update_7101() {
 
$module_list = array(
   
'my_feature',
   
'my_other_feature',
  );
 
module_enable($module_list);
}

/**
 * Revert some features.
 */
function delicious_deploy_update_7102() {
 
// Revert features
 
$revert = array(
   
'my_content_type' => array('node', 'field_instance', 'field_group', 'variable'),
   
'my_variables' => array('variable'),
  );
 
features_revert($revert);
}

/**
 * More updates...
 */
function delicious_deploy_update_7103() {
 
// More updates go here.
}
?>

UPDATE: 19 September 2014

Thanks to the comment from Doug below I've updated the code examples to use drupal_set_installed_schema_version() instead of db_update().

I've also created an example deployment module that's available on GitHub.

Comments

Thanks for bringing that up, Doug! I wasn't aware of drupal_set_installed_schema_version() and I think it's a better way of doing it. I've updated the blog post to use that instead of db_update().

There's also now an example module on GitHub.

In drupal 6 use hook_enable() as hook_install() is too early, and your schema version will be overwritten later. (hope this saves someone else a headache!)

Add new comment