mcpField
E
enonic-content-migration

enonic-content-migration

github.com/webmaxru数据与数据库0143 次安装22 周前更新
代码仓库

关于 enonic-content-migration

用于 Enonic XP 批量内容操作与迁移的技能,帮助开发者选择 API 和分支上下文、分批处理内容,并跟踪长时任务及结果。

主要功能

  1. 01检测 Enonic XP 项目与版本
  2. 02指导选择 API 和上下文
  3. 03构建 NoQL 查询与聚合
  4. 04分批处理内容
  5. 05报告长时任务进度
  6. 06验证迁移与发布结果

适用场景

  1. 01从外部数据批量创建内容
  2. 02按条件更新或删除内容
  3. 03在路径或环境间迁移和转换内容
  4. 04查询内容并通过聚合汇总

安装

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

$npx skills add https://github.com/webmaxru/enonic-agent-skills --skill enonic-content-migration

安装后在 Claude Code 中输入/enonic-content-migration确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

assets/
bulk-update.template.ts
task-migration.template.ts
references/
compatibility.md
examples.md
migration-reference.md
troubleshooting.md
scripts/
find-enonic-targets.mjs

详细介绍

Enonic 内容迁移

流程

步骤 1:识别 Enonic XP 项目和操作范围

  1. 检查工作区中的 Enonic XP 项目标记:包含 com.enonic.xp 依赖的 build.gradle、src/main/resources/ 目录结构,或包含 xpVersion 的 gradle.properties。
  2. 如果有 Node 运行时,请执行 node scripts/find-enonic-targets.mjs .,扫描 Enonic XP 项目标记和现有内容操作文件。
  3. 如果未检测到 Enonic XP 项目,请停止并说明此技能仅针对 Enonic XP 内容操作。
  4. 从 gradle.properties 或 build.gradle 中确定目标 XP 版本,以选择正确的 API。
  5. 对所请求的操作进行分类:
    • 批量创建:从外部来源(JSON、CSV、API)导入内容。
    • 批量更新:修改符合查询条件的现有内容。
    • 批量删除:移除符合查询条件的内容。
    • 迁移:在路径、站点或环境之间移动或转换内容。
    • 查询/聚合:使用 NoQL 和聚合检索并分析内容。
    • 长时间运行的任务:任何处理超过约 100 个项目且需要进度报告的操作。

步骤 2:选择 API 层和上下文

  1. 阅读 references/migration-reference.md,了解查询 DSL 模式、批处理策略和分支处理规则。
  2. 如果操作涉及 CMS 内容,并且需要发布/取消发布、内容类型验证和内容域抽象,请选择 lib-content。
  3. 如果操作需要低级节点操作、自定义存储库,或需要在原始数据迁移时绕过内容类型验证,请选择 lib-node。
  4. 确定所需的上下文:
    • 修改时使用 lib-context 在 draft 分支中运行操作;读取已发布内容时使用 master 分支。
    • 如果操作需要更高权限,请将 lib-context 与 role:system.admin 主体一起使用。
  5. 如果操作处理超过约 100 个项目,请使用 lib-task 将其封装在任务控制器中。阅读 references/migration-reference.md 中关于任务控制器的部分,了解相应模式。

步骤 3:构建查询

  1. 构造 NoQL 查询字符串或 DSL 表达式,以匹配目标内容。
  2. 对于内容类型筛选,请在 contentLib.query() 中使用 contentTypes 参数,或在节点查询中比较 type 属性。
  3. 对于日期范围查询,请使用 instant() 或 dateTime() 函数以及 range() 查询函数。
  4. 对于全文搜索,请使用 fulltext(),并指定适当的字段路径和运算符(AND/OR)。
  5. 对于限定路径范围的操作,请使用 _path LIKE '/content/site-path/*' 匹配后代。注意:NoQL 查询中的 _path 属性包含内部 /content/ 前缀,但结果中的 hit._path 返回不带此前缀的内容域路径。根据结果路径构建查询时,务必添加 /content/ 前缀。
  6. 添加 filters,使用 exists、notExists、hasValue 或 boolean 组合来高效缩小查询结果范围。
  7. 如果操作需要分组统计(术语计数、日期直方图、数值范围、统计数据),请添加 aggregations。
  8. 阅读 references/examples.md,了解完整的查询和聚合模式。 第 4 步:实现批处理
  9. 使用带 start 和 count 参数的分页检索,避免将所有结果加载到内存中。
  10. 根据每个项目的处理复杂度,将 count 设为 50 到 200 之间的批量大小。
  11. 循环执行,直到 result.hits.length === 0 或 start >= result.total;每次迭代将 start 增加一个批量大小。
  12. 批量使用 contentLib.create() 时,设置 refresh: false,避免逐项刷新索引;批处理完成后手动刷新。
  13. 对于 contentLib.modify(),使用编辑器回调模式,以安全地转换每个内容项。
  14. 对于 contentLib.publish(),将键分成每组 50–100 个的批次,避免大量发布时超时。
  15. 跟踪成功和失败数量,以便生成报告。
  16. 阅读 assets/bulk-update.template.ts,了解可复用的批量更新控制器模板。注意:模板使用 TypeScript/ESM 语法(import、const、箭头函数);部署为 XP 运行时 .js 文件时,需改用 CommonJS JavaScript 语法(require()、var、function())。

第 5 步:处理分支操作和发布

  1. 在 draft 分支上下文中执行内容修改。
  2. 修改完成后,使用 contentLib.publish() 将已更改项目发布到 master。在 XP < 7.12 时,传入 sourceBranch: 'draft' 和 targetBranch: 'master'。在 XP 7.12+ 时,这些参数会被忽略(发布始终从 draft 到 master)。
  3. 发布批量更新的项目时,设置 includeDependencies: false,以避免意外发布依赖项。
  4. 对比 draft 和 master 状态的操作,使用 lib-node 中的 repo.diff(),并设置 target: 'master' 和 includeChildren: true。

第 6 步:使用任务控制器包装长时间运行的操作

  1. 内联任务函数使用 taskLib.executeFunction(),命名任务描述符使用 taskLib.submitTask()。
  2. 批处理期间定期使用 taskLib.progress({ info, current, total }) 报告进度。
  3. 阅读 assets/task-migration.template.ts,了解带进度报告的可复用任务控制器模板。
  4. 启动重复操作前,使用 taskLib.isRunning() 检查是否已有运行中的实例。
  5. 如果操作产生过高负载,使用 taskLib.sleep() 在批次之间进行限流。
  6. 对于 XP 7.13+ 上的命名任务,run 函数的第二个参数为 taskId:exports.run = function(params, taskId) { ... }。

第 7 步:验证并报告结果

  1. 操作完成后,记录摘要:已处理的项目数、已创建/更新/删除的项目数、失败的项目数、总耗时。
  2. 对于迁移操作,通过查询目标路径验证目标内容是否存在。
  3. 对于发布操作,通过查询 master 分支验证发布状态。
  4. 如果发生错误,将错误详情(内容路径、错误消息)整理成结构化报告。

错误处理

  • 如果 scripts/find-enonic-targets.mjs 未找到 Enonic XP 项目,请说明工作区不包含 Enonic XP 应用。
  • 如果内容操作因 contentAlreadyExists 失败,请检查目标是否存在,并决定更新还是跳过。阅读 references/troubleshooting.md,了解重复项处理模式。
  • 如果查询返回零条结果,请检查查询语法、分支上下文和属性路径。NoQL 字符串格式不匹配(例如日期比较缺少 instant() 包装)是常见原因。
  • 如果任务失败或超时,请检查 taskLib.get(taskId) 中的状态和进度详情。阅读 references/troubleshooting.md,了解超时和权限问题。
  • 如果发布或修改时发生 AccessDeniedException,请确保上下文通过 lib-context 包含 role:system.admin 主体。

评论

支持 Markdown