{"id":13852373,"url":"https://github.com/previousnext/drush_cmi_tools","last_synced_at":"2025-08-01T01:03:56.683Z","repository":{"id":51762939,"uuid":"66407689","full_name":"previousnext/drush_cmi_tools","owner":"previousnext","description":"Provides advanced CMI import and export functionality","archived":false,"fork":false,"pushed_at":"2021-05-10T05:29:19.000Z","size":38,"stargazers_count":89,"open_issues_count":12,"forks_count":14,"subscribers_count":15,"default_branch":"8.x-2.x","last_synced_at":"2025-07-29T16:34:01.569Z","etag":null,"topics":["drupal-module"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/previousnext.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-23T22:19:39.000Z","updated_at":"2024-11-11T01:42:43.000Z","dependencies_parsed_at":"2022-08-22T17:50:50.190Z","dependency_job_id":null,"html_url":"https://github.com/previousnext/drush_cmi_tools","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/previousnext/drush_cmi_tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/previousnext%2Fdrush_cmi_tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/previousnext%2Fdrush_cmi_tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/previousnext%2Fdrush_cmi_tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/previousnext%2Fdrush_cmi_tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/previousnext","download_url":"https://codeload.github.com/previousnext/drush_cmi_tools/tar.gz/refs/heads/8.x-2.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/previousnext%2Fdrush_cmi_tools/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268151818,"owners_count":24204034,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-31T02:00:08.723Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["drupal-module"],"created_at":"2024-08-04T22:01:17.514Z","updated_at":"2025-08-01T01:03:56.571Z","avatar_url":"https://github.com/previousnext.png","language":"PHP","funding_links":[],"categories":["PHP"],"sub_categories":[],"readme":"# Drush CMI tools\nProvides advanced CMI import and export functionality for CMI workflows.\n\n## ☠️ Deprecated ☠️ ##\n\n\u003cstrong\u003ePlease note that this module is deprecated and will not receive a Drupal 9 release. Please see [instructions for migrating to Config Ignore](https://www.previousnext.com.au/blog/migrate-from-drush-cmi-tools-drupal-9) module instead.\u003c/strong\u003e\n\n## Use case\nSay you're working on a local development environment for a project where the client is adding and editing configuration.\nFor example, the project might be using [Contact Storage](https://drupal.org/project/contact_storage) or [YAML Form](https://drupal.org/project/yamlform) for user interaction. Each of these and their associated fields, form and view displays are a config object. As the client is editing these, you don't want that configuration tracked in your source control.\n\nSo you start working on a new feature, the first thing you do is sync down a QA or production database and then you run your config import so that your local environment is in a clean state. \n\nYou work on some features and the time has come to export those changes to your config export folder, in order to check in the new work into git ready for deployment.\n\nEnter `drush cexy`\n\n# drush cexy\nIts like `drush cex` but with 74% more shiny\u003csup\u003e[1](#ref1)\u003c/sup\u003e.\n\nSo the normal `drush cex` command comes with a `--skip-modules` option that prevents configuration from say devel module from being exported. But let's go back to our original use case.\n\nWe want to export all configuration, but we want to exclude certain patterns.\n\nThis is where the `--ignore-list` option of `drush cexy` comes in.\n\nIn our project we have a `./drush` folder, so we stick a file in their called `config-ignore.yml` with contents as follows.\n\n```yml\nignore:\n  - field.field.contact_message.*\n  - field.storage.contact_message.*\n  - contact.form.*\n  - core.entity_form_display.contact_message*\n  - core.entity_form_display.contact_form*\n  - core.entity_view_display.contact_message*\n  - core.entity_view_display.contact_form*\n  - system.site\n  - workbench_email.workbench_email_template.*\n```\n\nYou'll note there are some wildcards there. We're ignoring all contact message fields and forms as well as any form or view display configuration. Additionally we're ignoring [Workbench Email](https://drupal.org/project/workbench_email) templates and the system site settings.\n\nSo now we run `drush cexy` like so\n\n```\ndrush cexy --destination=/path/to/config-export --ignore-list=/path/to/drush/config-ignore.yml\n```\n\nSo what this does is export the active configuration, and then apply the ignore list to remove unwanted configuration.\n\nSo now when you run `git status` you should only see changes you want to commit.\n\n# Single install configuration\n  \nSo lets assume you're working on a feature branch that requires installation of the [Google Analytics](https://drupal.org/project/google_analytics) module.\n\nYou download and enable the module\n\n```bash\ndrush dl google_analytics\ndrush en -y google_analytics\n```\n\nAnd then you export your configuration with `drush cexy` using your build tool of choice (`make` in this case - cause remembering all the flags is bound to go wrong)\n\n```\nmake export\n```\n\nAfter running that you find you have a new file in your exported configuration folder:\n\n```\ngoogle_analytics.settings\n```\n\nNow you know that you want this configuration to be editable by the client, as they'll have different GA urchin codes on different environments.\n\nSo you don't want to check this into git. But, you do need it to be deployed at least once. And that's where `drush cexy`'s sibling comes in `drush cimy`.\n\n# drush cimy\n\n`drush cimy` is the import equivalent of `drush cexy`. Experts estimate it increases your productivity by 94%\u003csup\u003e[2](#ref2)\u003c/sup\u003e.\n\nSo returning to our single install of the google analytics settings. You'd just exported your config using `drush cexy` and found yourself with a new `google_analytics.settings.yml` file that you needed to deploy, but only once.\n\n`drush cimy` combines the following features\n\n* The power of `drush cim --partial`\n* The ability to perform config deletes\n* The ability to perform one-time installs\n\nThe format is as follows\n\n```\ndrush cimy --source=/path/to/config-export --install=/path/to/config-install --delete-list=/path/to/config-delete.yml\n```\n\nSo we move the google_analytics.settings.yml out of our `config-export` folder and into our `config-install` folder. And then we add it to our `drush/config-ignore.yml` file, so it doesn't get exported in the future.\n\n## Partial imports\n\nSo as alluded above, `drush cimy` is similar to `drush cim --partial` in that it does partial imports. \n\nThe way `drush cim --partial` works is equivalent to the following\n\n* firstly it creates a temporary folder\n* then it exports all active configuration\n* then it copies your nominated config-export folder (the one under source control) over the top (in the temporary folder)\n* then it imports from the temporary folder\n\nSo what you get imported is all active config plus and new config from the config export, with changes in the exported config taking precedence over the active config.\n\nThe main pain point with using `--partial` is you don't get config deletes.\n\ne.g. if you delete a config file from git (it is no longer in your config-export folder) because it is still present in the active configuration, it still remains after import.\n\nSo why is this a problem. So let's consider a scenario where someone enabled `dblog` module on QA, and saved the settings so that `dblog.settings.yml` is in the active configuration.\n \nYour `core.extensions.yml` that is tracked in git does not contain `dblog` module. But `dblog.settings.yml` depends on `dblog` module.\n\nSo you work away on your feature and go to deploy to QA. But the import step of your deployment automation fails, because `--partial` places a copy of `dblog.settings.yml` in the temporary folder and tries to import it, but because `dblog` module is going to be disabled by the import, you have an unmet config dependency.\n\nThis is where the `--delete-list` flag kicks in. Let's look at a sample delete list file\n\n```yml\ndelete:\n  - dblog.settings\n```\n\nSo this is where `drush cimy` varies from `drush cim`, its (equivalent) logic is as follows\n\n* As with `drush cim --partial`, first it creates a temporary folder\n* Move one-time install configuration into the folder first - so that active configuration takes precendence over initial state\n* export all active configuration\n* delete any configuration found in active configuration that is listed in the delete list\n* copy the nominated config-export (tracked in source control) over the top, taking final precendence\n* import the result\n\nSo this means you get the good bits of partial imports, without the dependency dramas that can result. It also allows you to perform valid deletes, something that isn't possible with `drush cim --partial` - for example you might want to delete a field from active configuration. Previously you'd have to write an update hook to do that before you performed your config import. Now you just list it in the config-delete.yml file \n\n# Installation\n\n```bash\ncd ~/.drush\nwget https://raw.githubusercontent.com/previousnext/drush_cmi_tools/8.x-1.x/drush_cmi_tools.drush.inc\ndrush cc drush\n```\n\n### As Composer dependency\n\nFirst, update composer.json manually. Then call `require` command.\n```\n\"repositories\": [\n    {\n        \"url\": \"https://github.com/previousnext/drush_cmi_tools.git\",\n        \"type\": \"git\"\n    }\n],\n\"require\": {\n    \"drupal/drush-cmi-tools\": \"dev-8.x-1.x\"\n},\n```\n`$ composer require drupal/drush-cmi-tools:dev-8.x-1.x`\n\n# References\n\n* \u003ca name=\"ref1\"\u003e\u003c/a\u003e1. According to a random survey of this one guy I met on the train.\n* \u003ca name=\"ref2\"\u003e\u003c/a\u003e2. Granted they were experts in rocket science and had never heard of Drupal.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpreviousnext%2Fdrush_cmi_tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpreviousnext%2Fdrush_cmi_tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpreviousnext%2Fdrush_cmi_tools/lists"}