Skip to main content
Start of main content.

Migrate from drush_cmi_tools for Drupal 9

by adam.bramley /

Share this post on social media

Prior to Drupal 9, Drush CMI Tools was our standard approach for config management. Drush CMI tools have been deprecated for Drupal 9 and replaced by the Config Ignore 3 community-supported project that provides the same functionality.

Config Ignore version 3 removed the dependency on config_filter in favour of using core's new APIs available for Drupal 8.8 and above. Using this module, we are now able to achieve everything Drush CMI Tools did, with better integration with core's APIs and event subscribers. This is a huge improvement over the completely custom commands shipped with Drush CMI Tools, and ironed out some annoying bugs with it... No more pesky leftover field maps!

How to upgrade

The upgrade path is quite straightforward. You'll first need to require the 3.x version of Config Ignore and, at the time of writing this post, you'll need to apply a patch from this issue. Add the following to your composer.json patches section:

"drupal/config_ignore": {
  "fixes import (3117694)": "https://www.drupal.org/files/issues/2020-05-28/3117694-active-config-25.patch"
},

And then run:

composer require drupal/config_ignore:^3

You can now enable config_ignore, and disable drush_cmi_tools

drush en config_ignore -y
drush pmu drush_cmi_tools -y

Note: Config Ignore requires Drush 10, you'll be prompted to upgrade via Composer if on an earlier version.

composer require drush/drush:^10

The final step is to migrate your ignored config settings into config_ignore settings. This requires a manual upgrade path due to the fact that enabling the module and importing the module's config happen at the same time, if you do not use an update hook to import the settings your ignored config will be deleted.

First, move the yml file that listed your ignored config for drush_cmi_tools into config_ignore.settings.yml. For us this was in drush/config-ignore.yml

mv drush/config-ignore.yml YOUR_CONFIG_SYNC_DIRECTORY/config_ignore.settings.yml

Next, change the key in the file from ignore to ignored_config_entities

It should look something like this:

ignored_config_entities:
  - devel.settings
  - devel.toolbar.settings

Finally, add the following update hook to a module or profile:

/**
 * Migrate to config_ignore.
 *
 * For this to work, updb needs to be before config-import in your deployment.
 * Alternatively, use `drush deploy`.
 */
function MY_MODULE_update_N() {
  /** @var \Drupal\Core\Extension\ModuleInstallerInterface $moduleInstaller */
  $moduleInstaller = \Drupal::service('module_installer');
  $moduleInstaller->install([
    'config_ignore',
  ], FALSE);
// Populate config_ignore initial values so we don't delete configs we need
  // in the first config import step after this.
  $syncDirectory = Settings::get('config_sync_directory');
  $data = Yaml::decode(file_get_contents(sprintf('%s/config_ignore.settings.yml', $syncDirectory)));
  \Drupal::configFactory()->getEditable('config_ignore.settings')->setData($data)->save();
}

Update your deployment scripts

Now that you're migrated, you need to change the commands you run in your deployment scripts. At PNX we generally use Makefile commands to run a deployment, e.g make deploy this runs update-db, config-import, cache-clear in that order.

Now that we are not using a custom drush command, we can simply change the config-import/config-import commands to:

# Old import
drush config-import-plus -y --source=$(CONFIG_DIR) --install=$(CONFIG_INSTALL) --delete-list=$(CONFIG_DELETE)

# New import
drush config-import -y

# Old export
drush config-export-plus -y --destination=$(CONFIG_DIR) --ignore-list=$(CONFIG_IGNORE)

# New export
drush config-export -y

In fact, I would highly recommend you migrate your whole deployment workflow to using the new Drush Deploy command. This gives you the added bonus of being able to run post deployment hooks. These are really handy if, for example, you're deploying a new taxonomy vocabulary and need to create some default terms when deploying. Instead of having to manually import the vocabulary config in an update hook, you can simply add the following to my_module.deploy.php

/**
 * Add some terms.
 */
function MY_MODULE_deploy_add_terms() {
  $terms = ['Foo', 'Bar', 'Baz'];
  foreach ($terms as $term) {
    $term = Term::create(['name' => $term, 'vid' => 'new_vocab']);
    $term->save();
  }
}

And with that we can simply run drush deploy -y to run all of our deployment steps in the appropriate order.