Skip to main content

Migrate from drush_cmi_tools for Drupal 9

Drush CMI Tools was the standard approach for config management at PreviousNext prior to Drupal 9. For Drupal 9, Drush CMI tools has been deprecated and replaced by a community-supported project which provides the same functionality — Config Ignore 3.

by adam.bramley /

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.

Posted by adam.bramley
Senior Drupal Developer

Dated

Comments

Comment by Matthieu Riffault

Dated

Hi,
Thanks for the update. I'm the person who submit a PR to migrate drush CMI Tools to D9 https://github.com/previousnext/drush_cmi_tools/issues/33
No problem to migrate to the new system as soon as possible. As obviously we encounter the "non-existent config entity name..." issue.

But, how to deal with the config-delete.yml ? We use it quite often.
Sure we could deploy a hook_update, but this yml file was much easier to use.

Thanks

Comment by adam.bramley

Dated

Hey Matthieu! Thanks for your contributions :)

You no longer need config-delete as anything that does not exist in your sync directory that is not ignored via config_ignore.settings is automatically deleted.

Comment by regilero

Dated

This deletes feature is fine, but there's still one problem, if you deliver a code to a production platform, with some new 'deletes-to-ignore' in the config_ignore.settings yaml file, a drush cim would still delete everything and update the config_ignore setting in a single operation, only the next drush cim would know that some new records should be protected from delete.

To fix this we added a first step with a drush cim --partial before, to be sure that the delete list is ignored BEFORE the delete operation are performed.

Pagination