platform-destructive-deploy

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Handling Destructive Changes

处理破坏性变更

Coordinate metadata deletion against a Salesforce org via the destructiveChanges manifest. Runs in three phases: scope → validate → execute, with stricter guardrails for production.
通过destructiveChanges清单协调针对Salesforce组织的元数据删除操作。分为三个阶段:范围确定→验证→执行,针对生产环境有更严格的防护措施。

Phase 1 — Scope the deletion

阶段1 — 确定删除范围

Step 1a — Gather the components to remove

步骤1a — 收集要移除的组件

Ask the user (or infer from context) which components to delete. For each, capture:
  • Metadata type (e.g.
    CustomObject
    ,
    CustomField
    ,
    ApexClass
    ,
    Flow
    ,
    PermissionSet
    )
  • API name (e.g.
    Project__c
    ,
    Account.Status__c
    ,
    MyController
    )
询问用户(或从上下文推断)要删除哪些组件。对于每个组件,需记录:
  • 元数据类型(例如
    CustomObject
    CustomField
    ApexClass
    Flow
    PermissionSet
  • API名称(例如
    Project__c
    Account.Status__c
    MyController

Step 1b — Local dependency scan (best-effort)

步骤1b — 本地依赖扫描(尽力而为)

Before generating the manifest, scan the local project for references to each component. Use Grep over
force-app/
:
bash
grep -rn "<componentApiName>" force-app/ --include='*.cls' --include='*.trigger' --include='*.xml' --include='*.js' --include='*.html'
If references are found:
  • List them to the user
  • Recommend either updating those references first OR removing them in the same destructive deploy
  • Do NOT proceed silently — surface the dependency risk
生成清单前,扫描本地项目中对每个组件的引用。使用Grep遍历
force-app/
目录:
bash
grep -rn "<componentApiName>" force-app/ --include='*.cls' --include='*.trigger' --include='*.xml' --include='*.js' --include='*.html'
如果发现引用:
  • 向用户列出这些引用
  • 建议先更新这些引用,或者在同一次破坏性部署中一并移除
  • 切勿静默继续——必须告知用户依赖风险

Step 1c — Generate
destructiveChanges.xml

步骤1c — 生成
destructiveChanges.xml

Write to
manifest/destructiveChangesPre.xml
(for pre-deploy deletion) or
manifest/destructiveChangesPost.xml
(for post-deploy deletion). Use the standard Salesforce metadata format:
xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Project__c</members>
        <members>OldThing__c</members>
        <name>CustomObject</name>
    </types>
    <types>
        <members>Account.Status__c</members>
        <name>CustomField</name>
    </types>
    <version>62.0</version>
</Package>
Use the API version from
sfdx-project.json
's
sourceApiVersion
.
Group components by metadata type (one
<types>
block per type). For namespaced fields, use
Object.Field
notation.
写入
manifest/destructiveChangesPre.xml
(用于部署前删除)或
manifest/destructiveChangesPost.xml
(用于部署后删除)。采用Salesforce标准元数据格式:
xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <types>
        <members>Project__c</members>
        <members>OldThing__c</members>
        <name>CustomObject</name>
    </types>
    <types>
        <members>Account.Status__c</members>
        <name>CustomField</name>
    </types>
    <version>62.0</version>
</Package>
使用
sfdx-project.json
sourceApiVersion
指定的API版本。
按元数据类型对组件进行分组(每种类型对应一个
<types>
块)。对于带命名空间的字段,使用
Object.Field
格式。

Phase 2 — Validate

阶段2 — 验证

ALWAYS validate before executing a destructive deploy:
bash
sf project deploy validate \
  --pre-destructive-changes manifest/destructiveChangesPre.xml \
  --manifest manifest/package.xml \
  --target-org <alias> \
  --test-level RunLocalTests \
  --json
(For post-destructive: use
--post-destructive-changes
.)
If
package.xml
doesn't exist, create an empty one alongside (deletion-only deploy needs a package descriptor):
xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <version>62.0</version>
</Package>
If validation fails, surface errors and STOP. Common failure modes:
  • "Cannot delete: referenced by Apex/Flow/Layout" → component still has references
  • "Cannot delete: required for license" → managed-package or license dependency
  • "Insufficient access" → user lacks delete permission
执行破坏性部署前必须先验证:
bash
sf project deploy validate \
  --pre-destructive-changes manifest/destructiveChangesPre.xml \
  --manifest manifest/package.xml \
  --target-org <alias> \
  --test-level RunLocalTests \
  --json
(针对部署后删除:使用
--post-destructive-changes
参数。)
如果
package.xml
不存在,需在旁边创建一个空文件(仅删除的部署需要包描述符):
xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <version>62.0</version>
</Package>
如果验证失败,需显示错误并终止操作。常见失败原因:
  • "无法删除:被Apex/Flow/Layout引用" → 组件仍存在引用
  • "无法删除:许可证必需" → 托管包或许可证依赖
  • "权限不足" → 用户缺少删除权限

Phase 3 — Execute

阶段3 — 执行

Production path

生产环境流程

Confirm whether the target is production before executing. The reliable check is the gate's classifier (returns
production|sandbox|scratch|trial|devhub|unknown
):
bash
sf org display --target-org <alias> --json | "${CLAUDE_PLUGIN_ROOT}/scripts/sf-deploy-gate" classify
If the classifier returns
production
:
  1. Display destructive confirmation banner (mirroring
    platform-quick-deploy
    )
  2. List EVERY component that will be deleted
  3. Require explicit "yes, delete from PRODUCTION" confirmation
  4. Reject
    --purge-on-delete
    unless the user types it explicitly
The PreToolUse hook (
sf-deploy-gate destructive
) will already block bare destructive commands against prod — surface that denial to the user, do not work around it.
执行前确认目标是否为生产环境。可靠的检查方式是使用gate分类器(返回
production|sandbox|scratch|trial|devhub|unknown
):
bash
sf org display --target-org <alias> --json | "${CLAUDE_PLUGIN_ROOT}/scripts/sf-deploy-gate" classify
如果分类器返回
production
  1. 显示破坏性确认横幅(与
    platform-quick-deploy
    一致)
  2. 列出所有将被删除的组件
  3. 要求用户明确确认“yes, delete from PRODUCTION”
  4. 除非用户明确输入,否则拒绝使用
    --purge-on-delete
    参数
PreToolUse钩子(
sf-deploy-gate destructive
)已会阻止针对生产环境的裸破坏性命令——需向用户说明该限制,切勿绕过。

Sandbox / Scratch path

沙盒/临时组织流程

bash
sf project deploy start \
  --pre-destructive-changes manifest/destructiveChangesPre.xml \
  --manifest manifest/package.xml \
  --target-org <alias> \
  --json \
  --wait 30
Add
--purge-on-delete
only if the user explicitly asked to permanently delete (skip the recycle bin).
bash
sf project deploy start \
  --pre-destructive-changes manifest/destructiveChangesPre.xml \
  --manifest manifest/package.xml \
  --target-org <alias> \
  --json \
  --wait 30
仅当用户明确要求永久删除(跳过回收站)时,才添加
--purge-on-delete
参数。

Phase 4 — Post-delete cleanup

阶段4 — 删除后清理

After a successful destructive deploy:
  • Recommend a
    sf project retrieve start --metadata <Type>:<Name>
    is NOT useful (component is gone) — instead suggest cleaning up the local source:
    bash
    # Remove the now-deleted local files to keep source tracking accurate
    rm -rf force-app/main/default/<path-to-component>
  • If deleting a custom field with data, remind the user that data is gone (or in the recycle bin until purged)
  • Recommend running tests to confirm no runtime regressions
破坏性部署成功后:
  • 建议无需执行
    sf project retrieve start --metadata <Type>:<Name>
    (组件已不存在)——而是建议清理本地源代码:
    bash
    # 删除已删除的本地文件,保持源代码跟踪准确
    rm -rf force-app/main/default/<path-to-component>
  • 如果删除的是带有数据的自定义字段,提醒用户数据已丢失(或在回收站中,直到被彻底清除)
  • 建议运行测试以确认无运行时回归问题

Rules

规则

  • ALWAYS validate first; NEVER skip Phase 2
  • ALWAYS scan for local references; NEVER delete blindly
  • ALWAYS gate production with explicit user confirmation
  • NEVER add
    --purge-on-delete
    without explicit user request
  • NEVER use
    --ignore-errors
    on a destructive deploy
  • ALWAYS use the API version from
    sfdx-project.json
    , not a hardcoded value
  • If the user is deleting a field with
    required="true"
    or that's used in
    RecordType
    picklist values, surface the cascade impact before proceeding
  • 必须先验证;切勿跳过阶段2
  • 必须扫描本地引用;切勿盲目删除
  • 必须通过用户明确确认来保护生产环境
  • 除非用户明确要求,否则切勿添加
    --purge-on-delete
    参数
  • 切勿在破坏性部署中使用
    --ignore-errors
    参数
  • 必须使用
    sfdx-project.json
    中的API版本,而非硬编码值
  • 如果用户要删除
    required="true"
    的字段或用于
    RecordType
    选择列表值的字段,需在继续前告知用户连锁影响