mcpField
D
drupal-config-reconcile

drupal-config-reconcile

github.com/grasmash云与 DevOps8291 次安装4 周前更新
代码仓库

关于 drupal-config-reconcile

drupal-config-reconcile 是用于协调 Drupal 跟踪配置与部署环境配置差异的引导式工作流。它逐项审查差异,帮助团队选择导入、导出或跳过,并将写入限制在本地文件。

主要功能

  1. 01比较跟踪配置与参考环境
  2. 02将差异归为导入、导出或跳过
  3. 03使用 config:get 获取单项配置
  4. 04仅将导出内容写入本地文件
  5. 05通过导入转换器验证结果

适用场景

  1. 01部署前协调配置漂移
  2. 02将环境中创建的配置纳入版本控制
  3. 03导入前审查配置 UUID 差异
  4. 04确认导出的配置能否在部署中保留

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/grasmash/drupal-claude-skills --skill drupal-config-reconcile

安装后在 Claude Code 中输入/drupal-config-reconcile确认已加载。

详细介绍

Drupal 配置协调

一个引导式工作流,用于解决已跟踪配置(config/default 以及任何拆分目录)与已部署环境中的活动配置之间的差异。大多数团队都掌握了相关操作(config:status、cim、cex),但没有一套严谨的方法逐项检查差异并决定哪一方为准。本工作流就是这套方法。

核心决策:导入、导出或跳过

对于每个存在差异的配置项,以下三种情况恰有一种成立,你需要选择一个方向:

  • 导入 = 磁盘 → 数据库。 已跟踪文件是唯一事实来源;它会在下次代码部署并导入配置时部署到环境中。不更改文件——保留 Git 中的内容。
  • 导出 = 数据库 → 磁盘。 以环境中的值为准;将环境中的配置写入已跟踪文件(如果环境中没有该配置,则执行 git rm 删除文件)。
  • 跳过。 保留未解决的差异并继续(对于仅涉及 _core 的差异,这是正确的选择)。

切勿对生产环境执行配置写入操作。 此工作流只会从参考环境中读取,只会向本地文件写入。它绝不会写入任何远程数据库。

远程 CLI——不依赖主机平台

以下示例使用 Pantheon 的 Terminus。任何主机平台上的工作流都相同——只需替换为你所用平台的远程 Drush 命令。如果平台提供 Drush 站点别名,通用的 drush @<alias> <cmd> 形式在任何平台上都适用,也是最简单的基准方案。

任务Acquia(acli)Pantheon(Terminus)Platform.sh / UpsunLagoon(amazee.io)通用(Drush 别名)
远程 Drushacli remote:drush -- <cmd>terminus drush <site>.<env> -- <cmd>platform drush -e <env> -- <cmd>(Upsun:upsun drush …)lagoon ssh -p <project> -e <env> -C "drush <cmd>"drush @<alias> <cmd>
从生产环境刷新非生产数据库云端 UI 复制数据库 / acli api:environments:database-copyterminus env:clone-content <site>.live <env> --db-onlyplatform sync data(Upsun:upsun sync data)drush sql:sync 或 Lagoon 发布后的任务drush sql:sync @<prod> @<env>
将数据库拉取到本地acli pull:db(drush sql:sync)platform db:dumplagoon ssh … -C "drush sql:dump"drush sql:sync @<env> @self
获取 Drush 别名acli remote:aliases:downloadterminus aliasesPlatform.sh 提供的 @platform.<env>drush sa(Lagoon 提供)drush/sites/ 中的别名

每个平台只需认证/关联一次: Acquia acli auth:login + acli link;Pantheon terminus auth:login;Platform.sh/Upsun platform login / upsun login;Lagoon lagoon login。切勿对任何平台执行面向生产环境的写入/克隆操作。

工作流

1. 选择参考环境(切勿使用 live/prod)

使用非生产环境作为生产环境的替代参考(例如 Pantheon dev/test,或 CI/预发布别名)。拒绝将实时生产环境作为目标——对生产环境执行配置写入会导致团队破坏生产配置。

2. 确保参考数据库为最新

只有当参考环境反映了当前生产环境的状态时,差异才有意义。如果环境数据库已过时(通常超过 24 小时),请先从生产环境刷新。在 Pantheon 上:

terminus env:clone-content <site>.live <env> --db-only -y   # Pantheon; see the table above for acli / platform / upsun / lagoon

克隆会修改共享环境,而且需要几分钟——请先征得用户确认;切勿静默执行。(注意:大多数平台无法可靠判断环境上次刷新的时间——terminus backup:list 报告的是备份的时间,而不是从生产环境克隆的时间。只能将其视为参考信息,并向用户确认。)

3. 在参考环境上获取差异(而非本地)

在参考环境上运行 config:status,以便 Drupal 正确应用配置拆分和 config_exclude_modules —— 在本地运行会因仅供开发环境使用的模块(devel、views_ui、生产环境拆分等)而产生误报:

terminus drush <site>.<env> -- config:status --format=json   # or your platform's remote-drush form (see table)

你会看到以下状态:

  • Only in DB —— 存在于环境的数据库中,但不在受跟踪的配置中。
  • Only in sync —— 存在于受跟踪的配置中,但不在环境的数据库中。
  • Different —— 两边都存在,但内容不同。

列表为空 → “已同步,无需协调” → 停止。

4. 使用 config:get 获取环境中每个项目的值(而非完整导出)

不要使用 config:export --destination + scp —— config_split 通常会因尝试在临时目标目录下创建相对拆分目录而失败,而且不同 Terminus 版本对 SSH 命令的发现方式也不稳定。按需逐项获取:

terminus drush <site>.<env> -- config:get <name> --format=yaml > /tmp/ref-<name>.yml   # or your platform's remote-drush form

config:get --format=yaml 输出 Drupal 导出的确切文件格式(没有 _core 键)—— 与受跟踪的同类文件逐字节一致。

注意: config:get 会额外追加一个尾随换行符。Drupal 的 phpcs(Drupal.Files.EndFileNewline.TooMany)不允许文件末尾有两个换行符,且提交前钩子会阻止提交。写入文件时,请规范化为恰好一个尾随换行符:

printf '%s\n' "$(cat /tmp/ref-<name>.yml)" > config/default/<name>.yml
5. 逐项处理

创建一个待办列表(每个配置名称一项),以便查看进度。按以下顺序处理:先 Only in DB,再 Different,最后 Only in sync;每项按以下步骤处理:

  1. 定位本地文件。 通常位于 config/default/<name>.yml。如果该文件不存在,请先检查拆分目录(config/prod/、config/local/、config/envs/…),再判断文件是否缺失——由拆分管理的项目位于 config/default 之外,必须写回同一个拆分目录。
  2. 显示内容差异(左侧标记为本地/磁盘,右侧标记为环境/数据库):
    • Different:diff -u config/default/<name>.yml /tmp/ref-<name>.yml
    • Only in DB:本地文件不存在 → 显示环境中的完整内容。
    • Only in sync:环境中不存在 → 显示本地文件的完整内容。
  3. 建议处理方向并说明原因:
    • Only in DB → 导出。 在环境中通过界面或更新钩子创建、应纳入 git 的配置(消息模板、视图显示等)。
    • Only in sync → 导入。 代码中新增的配置尚未部署;保留它并让它随部署生效。
    • Different:
      • 只有 _core 不同 → 跳过(无害的环境产物;不要无谓改动文件)。
      • uuid 不同 → 导出。 这不是无害差异:当同步文件的 uuid 与当前生效的 UUID 不同时,下一次导入时 StorageComparer::addChangelistUpdate() 会将该配置实体标记为重新创建(先删除,再创建)。对于字段存储,这会删除该字段的数据。必须以环境中的 UUID 为准。
      • 环境中有明显属于有意更改的值 → 导出。
      • 本地文件中有明显属于有意的代码更改 → 导入。
      • 确实无法判断 → 清楚呈现双方内容,默认跳过,让用户决定。
  4. 询问导入 / 导出 / 跳过。
  5. 执行操作——仅限本地文件:
    • 导出(Different / Only in DB):写入环境中的文件,并规范化尾随换行符(由拆分管理的项目写入拆分目录)。Only in sync + 导出表示环境中没有该配置 → 确认后,使用 git rm 删除本地文件。
    • 导入:保留本地文件;不做更改。⚠️ Only in DB + 导入具有破坏性——环境中的配置不在 git 中,因此部署时执行完整的 drush cim 会从环境中删除该配置。明确警告,并要求再次确认。
    • 跳过:不做任何操作。
6. 使用导入转换器验证——不要使用 config:status

写入导出的文件后,不要重新运行 config:status 来确认——即使文件已存在且有效,它仍可能将刚写入的项目报告为 Only in DB(这是显示信息过期导致的假象)。请使用 cim 实际采用的存储层——导入转换器来验证(它会像部署时一样应用 config_split):

drush ev '
$t = \Drupal::service("config.import_transformer")->transform(\Drupal::service("config.storage.sync"));
foreach (["<name1>","<name2>"] as $n) {
  print "$n => " . ($t->exists($n) && in_array($n, $t->listAll(), true) ? "RECONCILED (deploy-safe)" : "MISSING — would be deleted on cim") . "\n";
}'

exists() && in listAll() = YES 表示实际部署会保留该配置。请以此为准,而不是 config:status 表,来判断“我的导出是否生效”。

7. 总结并交接
  • 已导出(环境 → git): 创建、覆盖或移除的文件。
  • 部署时保留(导入): 下次部署时,本地版本会应用到环境中的项目。
  • 已跳过: 尚未解决的差异及其原因。

然后展示 git status 和 git diff --stat config/,不要自动提交或推送——先征求同意。请记住,Import 项目只有在代码部署完成且环境上运行配置导入后才会生效(完整的部署后续步骤及其验证见 drupal-deploy-safety 技能)。

注意事项

  • 在参考环境上运行 config:status,比较的是该环境的同步目录和数据库——它看不到你尚未提交的本地编辑。请先提交并部署编辑内容,再协调剩余差异。
  • 配置拆分:prod/local 拆分项目位于 config/prod / config/local,而不是 config/default。请始终将导出结果写回文件的实际位置。
  • 仅涉及 _core 的差异无害——不要因此反复修改文件。uuid 差异则不同:导入会删除并重新创建配置实体,因此请导出环境中的值。

评论

支持 Markdown