mcpField
A
automation-sandbox-post-copy-configure

automation-sandbox-post-copy-configure

github.com/forcedotcom云与 DevOps1.1k2.1k 次安装1 天前更新
代码仓库

关于 automation-sandbox-post-copy-configure

将 Salesforce 沙盒复制后自动化 JSON 配置应用到目标组织的技能。它会在变更前验证配置类型和记录,再按类型处理元数据、计划 Apex 或 Flow 激活状态。

主要功能

  1. 01验证配置项和目标组织
  2. 02变更前核验配置 API
  3. 03通过复合 PATCH 更新元数据
  4. 04单独处理计划 Apex
  5. 05检查状态后激活或停用 Flow

适用场景

  1. 01向 Salesforce 沙盒应用复制后设置
  2. 02更新出站消息或远程站点设置
  3. 03根据配置安排 Apex 作业
  4. 04设置目标组织中的 Flow 激活状态

安装

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

$npx skills add https://github.com/forcedotcom/sf-skills --skill automation-sandbox-post-copy-configure

安装后在 Claude Code 中输入/automation-sandbox-post-copy-configure确认已加载。

包含的文件

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

assets/
api_request_templates.json
scheduled_apex_template.apex
examples/
sample_config_input.json
sample_execution_summary.md
sample_scheduled_apex_config.json
references/
api_endpoints.md
authentication.md
execution_phasing.md
flow_activation_path.md
rules_gotchas.md
scheduled_apex_path.md
scripts/
build-scheduled-apex.mjs
classify-patch-result.mjs
map-metadata-key.mjs
plan-phases.mjs
resolve-target-org.mjs
soql-escape-job-name.mjs

详细介绍

自动化:沙盒复制后配置

将 Salesforce 沙盒复制后自动化 JSON 配置应用到目标组织。四个规范的 ConfigurationName 值已固定: OutboundMessages + RemoteSiteSettings → 复合 Metadata PATCH (步骤 A–E);ScheduledApex → 匿名 Apex(步骤 F),因为 CronTrigger 为只读;Flows → 流激活(步骤 G),使用与 A–E 相同的复合 Metadata 传输方式,固定变更键为 activeVersionNumber,并进行状态感知预检(ALREADY_ACTIVE / ALREADY_INACTIVE)。非规范名称通过推导并经 describe 验证。 每个 A–E 条目都必须通过步骤 B(describe 返回 200 + Metadata 复合 字段),之后才能规划任何 PATCH;ScheduledApex 跳过步骤 B。 未验证的条目会显示在摘要中并跳过——绝不猜测。

工具限制

只能使用 Bash 工具执行 sf CLI 命令(sf data query --use-tooling-api、sf api request rest、sf org display)。不要 使用 execute_soql 等 MCP 工具——此技能要求的复合 Metadata PATCH 模式无法通过 MCP 封装工具实现。 如果用户没有指定别名,调用 sf 时不要使用 --target-org(运行环境会设置 CLI 默认值);绝不要传入 --target-org default(会出现 NamedOrgNotFoundError)。SOQL-over-REST 使用相同的 OAuth—— 不可直接访问数据库或使用非 Salesforce SQL。

停止——在发起任何 API 调用前执行

绝不要凭记忆调用组织。在首次请求前:

  1. 从用户提供的确切路径(默认 ./post-copy-config.json) 读取完整配置 JSON。每个条目都必须包含全部五个键 (ConfigurationName、Label、Fields、IsActive、 ExecutionOrder)。如果任何条目格式错误,则中止,并指出 文件路径和条目索引——不要部分应用。**不要 虚构条目。**如果文件不存在,则停止并询问;绝不要根据虚构的标签 制定计划。
  2. 对配置中的每个不同 ConfigurationName,在规划任何 PATCH 之前 执行推导 + describe 验证步骤(见下文)。无法验证其 API 的条目 绝不能出现在计划的 PATCH 中——必须预先拒绝。
  3. 除非用户已明确提供目标组织别名,否则请向用户确认。此技能会修改 正在运行的组织——写入错误的组织(例如默认别名指向生产组织)是 代价最高的失败模式。

如果你在未读取配置文件并对每个不同的 ConfigurationName 执行 describe 验证之前,就宣布“我现在将应用……”, 请停止并先完成这些步骤。


每条目的操作流程(此技能的核心)

此技能为下列规范类型提供固定映射,并为其他类型提供先推导后验证的 路径。必须按顺序对每个条目执行以下步骤。无论映射来自固定表还是 推导路径,Step B(describe 验证)都是必需的——摘要中必须显示其 HTTP 状态。

步骤 A — 确定 Tooling API sobject 和查找过滤条件

固定规范项(权威来源 — 必须原样使用,不得替换为其他 sobject 名称):

ConfigurationNameTooling API sobjectRecord-lookup SOQL
OutboundMessagesWorkflowOutboundMessageSELECT Id, FullName FROM WorkflowOutboundMessage WHERE EntityDefinition.QualifiedApiName = '<Fields.Object>' — 然后在客户端选择 FullName == '<Fields.Object>.<Label>' 的行。对于此 sobject,SOQL 无法直接按 FullName 过滤。
RemoteSiteSettingsRemoteProxySELECT Id, SiteName FROM RemoteProxy WHERE SiteName = '<Label>'。
ScheduledApexCronTrigger(只读 — 使用匿名 Apex 路由,见步骤 F)见步骤 F — 预检门控:SELECT Id FROM CronTrigger WHERE CronJobDetail.Name = '<escaped>'。
FlowsFlowDefinition(通过复合 Metadata PATCH 修改固定的 activeVersionNumber — 见步骤 G)见步骤 G — 预检门控:SELECT Id, DeveloperName, ActiveVersion.VersionNumber FROM FlowDefinition WHERE DeveloperName = '<Fields.FlowApiName>'。

对于规范项,必须原样使用固定的 sobject 和 SOQL;跳过“推导”步骤。不得臆造 OutboundMessage、RemoteSiteSetting 或 MasterLabel 变体。字段名称解析(覆盖项 + 大小写规则 + 存在性检查)由 scripts/map-metadata-key.mjs 负责。

非规范项:推导一个候选项(通常是 Metadata API 类型名称的单数形式);步骤 B 会排除错误猜测。使用步骤 C 中的通用 SOQL 模式。

步骤 B — 验证候选项存在且支持 Metadata 写入

对每个候选项执行 GET describe:

sf api request rest \
  "/services/data/v<apiVersion>/tooling/sobjects/<Candidate>/describe/"

仅当以下两项均成立时,才接受该候选项:

  • HTTP 200(该 sobject 存在于此 org 的 Tooling API 中),并且
  • describe 响应的 fields 数组包含名为 Metadata 的字段(复合字段 — PATCH 通过此字段写入)。

如果没有候选项同时通过这两项门控,将条目标记为 API_NOT_IDENTIFIED 并跳过。不得猜测 REST 路径——最好的情况是错误路径返回 404,最坏的情况则会更新错误的记录。

步骤 C — 确定记录 Id(SOQL-over-REST)

对于固定规范项:原样运行步骤 A 表格中的 SOQL(替换 <Label> / <Fields.Object>)。不得替换为其他过滤列,例如 MasterLabel — 表中固定的 SOQL 是针对该 sobject 经过测试且正确的过滤条件。

对于非规范(推导的)sobject:查询已验证的 sobject,查找由条目的 Label 标识的记录(如存在 Fields.Object,也使用该字段):

# SOQL to a variable + separate jq call — avoids the most common
# shell-quoting failure in this skill.
SOQL='SELECT Id, FullName FROM <VerifiedSobject> WHERE <UniqueFilter>'
sf data query --use-tooling-api --json --query "$SOQL" \
  > /tmp/entry-<Slug>-lookup.json
ID=$(jq -r '.result.records[0].Id // empty' /tmp/entry-<Slug>-lookup.json)

根据步骤 B 的 describe 响应中显示的可查询字段,选择 <UniqueFilter>。如果行中包含 FullName 字段,SOQL 通常会拒绝直接使用 FullName = ... 进行过滤 — 应按 describe 显示的直接列进行过滤(例如 EntityDefinition.QualifiedApiName、DeveloperName、SiteName),并在客户端进行 FullName 匹配(jq -r '.result.records[] | select(.FullName == "<Object>.<Label>") | .Id')。

结果:

  • 零行 → NOT_FOUND(绝不回退到插入)。
  • 客户端过滤后有多行 → AMBIGUOUS(在摘要中列出所有 Id 并跳过;错误的 Id 比没有 Id 更糟)。
  • 恰好一行 → 继续步骤 D。
步骤 D — GET 当前 Metadata、执行变更并 PATCH 回去

Metadata 是全量替换——PATCH 中省略的键会被置空。保留步骤 D-1 GET 返回的所有现有键;仅覆盖需要变更的键。摘要中的“计划 PATCH 正文”(应用和试运行)是这个完整合并后的对象——试运行中,冗长或组织专属的值可以显示为 "<preserved-from-GET>",但必须包含所有键。

步骤 D 的每个文件名都必须包含步骤 C 中的记录 <Id>(例如 /tmp/entry-<Id>-meta.json)——并行阶段的条目共用工作目录,使用共用名称会相互覆盖。

  1. GET 当前 Metadata → /tmp/entry-<Id>-meta.json。
  2. 解析变更键(仅适用于通用路径;Flows 使用步骤 G 固定的 activeVersionNumber,ScheduledApex 使用步骤 F 的匿名 Apex——这两种情况都不得运行此脚本)——对于每个 Fields.<Xxx>,运行 node scripts/map-metadata-key.mjs "<ConfigurationName>" "<ConfigFieldName>" /tmp/entry-<Id>-meta.json。如果返回 {"status":"OK","key":...},则使用返回的键。如果返回 {"status":"FIELD_MAP_UNKNOWN",...},则标记该条目并跳过。不得跳过此脚本并通过首字母小写的简单规则推断:RemoteSiteSettings.Fields.RemoteSiteUrl 映射到 Metadata.url(而非 remoteSiteUrl);此类覆盖规则由脚本处理。
  3. PATCH——通过 heredoc 构建 /tmp/entry-<Id>-mutation.json,使用 jq --slurpfile m /tmp/entry-<Id>-mutation.json '. + $m[0] | {Metadata: .}' /tmp/entry-<Id>-meta.json > /tmp/entry-<Id>-patch.json 合并(保留 JSON 类型),使用 -b @/tmp/entry-<Id>-patch.json 发起 PATCH,并将响应正文保存到 /tmp/entry-<Id>-response.json。完整 bash 命令见 references/api_endpoints.md §步骤 D。绝不能使用 --arg(它会把布尔值和数字转成字符串,并且特殊字符会导致问题)。使用 for attempt in 1 2; do <cmd> && break; done 包装 PATCH——如果发生 shell/jq 引号错误(HTTP 请求尚未发出时退出码非零),则重试一次。
  4. 分类——运行 node scripts/classify-patch-result.mjs "<httpCode>" /tmp/entry-<Id>-response.json。退出码为 0 → SUCCESS;退出码为 2 → FAILED(解析后的错误会输出到标准输出)。204 响应正文非空时,结果为 FAILED。
步骤 E — 验证变更已生效

重新读取记录,确认 PATCH 已生效:

  • 如果变更的字段是该 sobject 上可直接通过 SOQL 查询的列(极少见——大多数可写入 Metadata 的字段都不满足此条件),按 Id 执行 SELECT 即可。
  • 否则,GET 记录并检查 .Metadata 中对应的键。

如果读回的值与请求值不匹配,记录 FAILED_VERIFY——PATCH 返回了 204,但效果不可见(通常是命名或权限问题)。

步骤 F — Scheduled Apex(匿名 Apex 路径)

阅读 references/scheduled_apex_path.md——步骤 A–E 不适用(CronTrigger 为只读)。该参考文档包含 F-1→F-4 的匿名 Apex 操作流程(预检 AMBIGUOUS 门控、代码片段构建、sf apex run、验证、试运行)以及步骤 F 的摘要格式。

步骤 G — Flow 激活/停用(Flows)

阅读 references/flow_activation_path.md——步骤 A 和 B 仍适用(FlowDefinition 是指定的 sobject;步骤 B 会确认复合字段 Metadata)。该参考文档包含 G-1→G-4 的复合 Metadata PATCH 操作流程,其中变更键固定为 activeVersionNumber(不适用步骤 D-2 的键推导)、决策规则(FlowApiName 验证、ALREADY_ACTIVE / ALREADY_INACTIVE 短路处理、禁止使用的同级键)、试运行约定以及 Flows 的摘要格式。


IsActive 语义

  • IsActive: true → 按照步骤 A–E 执行 PATCH(Flows 则执行步骤 G)。
  • IsActive: false → 不执行 PATCH。记录 SKIPPED_INACTIVE,并在 Follow-ups 中添加一个条目,包含该项的 ConfigurationName 和 Label,以便客户知道该项未被改动。

原因:IsActive: false 表示“在此沙盒中未启用”,而不是“停用现有记录”——默默停用正在运行的集成,其影响范围远大于保留原状。


标准输出格式(始终使用此格式)

生成一份 Markdown 摘要,写入 ./post-copy-<mode>-summary.md(mode 为 dry-run 或 apply),并打印给用户。不得生成 JSON 旁置文件(plan/phases.json、requests/*.request.json 等)——在 Markdown 中内联所有计划中和实际发出的请求。

Flows 和 ScheduledApex 使用特定步骤的摘要格式——采用带标签的叙述块,替代下方通用格式中的 Planned request: 块(阶段表格保持不变);请参阅各自参考文档的“Summary shape”部分。其他所有 ConfigurationName 均使用通用格式。

阶段枚举由脚本管理。 运行 node scripts/plan-phases.mjs <config.json>,并原样使用其 phases[]——每个条目都包含 ordinal(标题使用,从 1 开始计数)和 executionOrder(原始值,用于 (ExecutionOrder = <raw>));稀疏值会折叠;IsActive:false 条目会预先标记为 SKIP_INACTIVE。请参阅 references/execution_phasing.md 中的完整示例。

目标组织解析由脚本管理。 运行 node scripts/resolve-target-org.mjs;将返回的 .alias 填入标题。切勿原样输出 <env:SF_TARGET_ORG> 或 $SF_TARGET_ORG。

对于 dry-run 条目,HTTP 列为 —。摘要结尾使用: 未发出任何 PATCH 请求。要应用更改,请在不带 dry-run 标志的情况下重新运行。

# Post-Copy Configure Run — <N> entries <planned|applied> against `<alias>`

Config file: `<path>`
Target org: `<alias>`
Mode: <dry-run|apply>

## Phase <ExecutionOrder> — <count> entr(y|ies)

Planned request:
- Method: `PATCH`
- Path: `/services/data/v<apiVersion>/tooling/sobjects/<VerifiedSobject>/<Id>`
- Body: `<FULL merged Metadata: every key from the Step D-1 GET overlaid with the mutated keys. Verbose/org-specific values may render as "<preserved-from-GET>", but every key must be present. NEVER emit a minimal body.>`

| ConfigurationName | Label | Object | Sobject | Describe | Outcome | HTTP |
|-------------------|-------|--------|---------|----------|---------|------|
| <name>            | <lbl> | <obj>  | <VerifiedSobject> | <200 or 404> | <outcome> | <code> |

## Totals

| Outcome | Count |
|---------|-------|
| <state> | <n>   |

## Follow-ups

- <bullet per SKIPPED_INACTIVE / API_NOT_IDENTIFIED / AMBIGUOUS / FIELD_MAP_UNKNOWN / NOT_FOUND entry>

列语义:Object = 条目的 Fields.Object,或 —。Sobject = 步骤 A 解析出的 sobject。Describe = 步骤 B 的 HTTP 状态(200 表示已验证,404 → API_NOT_IDENTIFIED)——此列为必填,以便显示跳过的步骤 B。结果状态词汇:SUCCESS、NOT_FOUND、AMBIGUOUS、API_NOT_IDENTIFIED、FIELD_MAP_UNKNOWN、FAILED、FAILED_VERIFY、SKIPPED_INACTIVE、SKIPPED、DRY_RUN、DELETE_NOT_SUPPORTED、ALREADY_ACTIVE(Flows:请求的版本已激活——不执行 PATCH)、ALREADY_INACTIVE(Flows:请求停用,但已处于未激活状态——不执行 PATCH)、NOT_ATTEMPTED。

脚本仅供内部使用——切勿将原始 node scripts/… 标准输出或“我运行了 node …”之类的叙述内联到摘要中;应使用 JSON,采用返回的值,并按上述格式准确呈现。

范围

  • 范围内:将 post-copy 配置 JSON 应用于实时组织——按 ExecutionOrder 分阶段,推导并验证 sobject,通过 SOQL-over-REST 解析 Id,通过复合 Metadata 执行 PATCH,并报告结果。
  • 范围外:根据 SOP 生成配置 JSON(委托给 automation-sandbox-post-copy-config-generate);部署 metadata-XML;ATF Java 编排器;对 describe 探测失败的条目猜测 API 路径(API_NOT_IDENTIFIED → 停止)。

实时组织变更工具:优先先使用 --dry-run;切勿静默地通过不同端点重试失败的条目。

必需输入

应用前收集或推断:

  • 配置文件路径:来自 automation-sandbox-post-copy-config-generate 的 JSON(默认 ./post-copy-config.json)。缺失 → 停止并询问。
  • 目标组织别名 / 用户名:绝不假设默认值;如果未提供,使用 sf org list --json 列出并询问。
  • 试运行标志(默认 false):允许读取,禁止写入——这不代表“没有网络调用”。仍需运行步骤 B describe GET、步骤 C SOQL、步骤 D-1 GET;计划中预期的 PATCH 请求体只有针对真实 Metadata 块时才准确。跳过步骤 D-3(PATCH)和 E(验证)(Flows:参见步骤 G——G-3 GET + PATCH 均跳过,G-1 + G-2 仍会运行)。读取失败时(401、404、NamedOrgNotFoundError)应报告错误并停止——绝不回退到基于内存的计划。首次运行优先使用试运行。
  • 出错后继续(默认 true):true = 失败的条目不会中止当前阶段;false = 在当前阶段中途终止。

如果用户提供了明确的配置路径和目标别名,无需进一步询问即可继续。


工作流

每一步都通过 Bash 执行真实的 sf CLI 命令。绝不要只描述计划而不运行命令——此技能会修改目标组织。

  1. 读取 + 验证配置 JSON——使用 Read 工具加载。 每个条目都必须包含五个顶层键;格式错误 → 立即停止。

  2. 解析目标组织 + API 版本——sf org display --json。 解析结果以确认别名可用,并提取 result.apiVersion。 不要打印原始 JSON——其中包含访问令牌。

  3. 规划阶段——运行 node scripts/plan-phases.mjs <config.json> 并遍历其 phases[] 输出。有关并发上限,请参见 references/execution_phasing.md。

  4. 逐条目 describe 验证——对于每个不同的 ConfigurationName ≠ ScheduledApex,运行一次步骤 A + 步骤 B, 并缓存已验证的 sobject。步骤 B 失败 → 该名称对应的每个条目都标记为 API_NOT_IDENTIFIED。ScheduledApex 跳过 describe 验证(步骤 F 使用匿名 Apex,而非复合 Metadata)。Flows 会执行 describe 验证(PATCH 通过 FlowDefinition 上的复合 Metadata 传输);只跳过步骤 D 的变更键推导(步骤 G-3 使用固定键)。

  5. 逐条目应用——处理每个阶段中的每个条目:

    • plan-phases 返回 SKIP_INACTIVE → 标记为 SKIPPED_INACTIVE + 添加 Follow-ups 项,然后继续。
    • ScheduledApex → 步骤 F(F-1→F-4)。试运行:仅执行 F-1 + F-2; 记录为 DRY_RUN。
    • Flows → 步骤 G(G-1→G-4)。ALREADY_ACTIVE / ALREADY_INACTIVE 预检会跳过 PATCH。试运行: 仅执行 G-1 + G-2;记录为 DRY_RUN。
    • 其他所有条目 → 步骤 C(Id)、步骤 D(GET+修改+PATCH)、步骤 E (验证)。试运行:仅执行 C + D-1/D-2;记录为 DRY_RUN。
  6. 阶段之间——当前阶段的所有条目完成后,才能开始下一阶段。

  7. 写入摘要文件——按照“Canonical output shape”章节的要求,以 Markdown 格式写入 ./post-copy-<mode>-summary.md;同时打印给用户。绝不写入访问令牌或原始的 sf org display 输出。在摘要中遮蔽 URL 内嵌的凭据(https://user:***@host/...);实际 PATCH 请求体使用原样 URL。


规则与注意事项

关键不变量(绝不插入;对每个 ConfigurationName 执行 describe 门控;复合 Metadata PATCH 保留完整的现有块;IsActive: false → SKIPPED_INACTIVE;绝不打印原始访问令牌;阶段内并发上限为 5)以及每种运行时故障的规范响应(运行中遇到 401、429、包含凭据的 URL、Fields.Action = "Delete"、describe 404、SOQL 查询返回零条或多条记录)都记录在 references/rules_gotchas.md 中。偏离步骤 A–E 流程前,先阅读该文件。

跨技能集成

需求委托给
将客户 SOP 转换为此技能使用的 JSON 配置automation-sandbox-post-copy-config-generate
在复合式 Metadata Tooling 模式之外部署元数据 XML匹配的 generating-* 技能 + 元数据部署流程
在目标组织中创建尚不存在的新记录platform-metadata-deploy
分配 API 调用所需的权限集dx-org-permission-set-assign

参考文件索引

文件阅读时机
references/api_endpoints.md步骤 A–E — 完整通用流程 + OBM/RSS 操作示例
references/scheduled_apex_path.md步骤 F — ScheduledApex 的匿名 Apex 路径
references/flow_activation_path.md步骤 G — 流激活/停用(Flows)
references/execution_phasing.md步骤 3 — plan-phases.mjs 背后的阶段分组模型
references/authentication.md步骤 2 — 会话检查 + 运行中途的 401 处理
references/rules_gotchas.md偏离步骤 A–E 之前 — 不变量 + 失败响应
scripts/plan-phases.mjs步骤 3 — 阶段规划器
scripts/map-metadata-key.mjs步骤 D-2 — Metadata 键解析器
scripts/classify-patch-result.mjs步骤 D-4 — HTTP 结果分类器
scripts/resolve-target-org.mjs输出结构 — 目标组织别名解析器
scripts/build-scheduled-apex.mjs步骤 F-2 — 匿名 Apex 代码片段构建器
scripts/soql-escape-job-name.mjs步骤 F-1/F-4 — 对 JobName 进行 SOQL 转义
assets/api_request_templates.json步骤 A–E — describe/lookup/GET+PATCH 模板
assets/scheduled_apex_template.apex步骤 F-2 — 匿名 Apex 模板
examples/sample_config_input.json步骤 1 — 配置 JSON 结构
examples/sample_scheduled_apex_config.json步骤 1 — ScheduledApex 条目结构
examples/sample_execution_summary.md步骤 7 — 摘要报告结构

评论

支持 Markdown