Salesforceの本番組織からApexクラスを削除する

# Apexコードは本番環境から直接削除できない

もうこの処理は使わなくなったから削除したいな〜ということがあっても、ApexクラスやApexトリガーは本番環境から直接削除ができないため、別途WorkbenchやSalesforce CLIを使う必要があります。
Salesforce CLIのsfdxコマンドを使うものはよく見るのですが、
sfコマンドを使って削除処理をする記事をあまり見つけられなかったので、備忘録として残すことにしました。

## Salesforce CLIのバージョン確認

Salesforce CLIのv2でないと動かないそうなので、以下のコマンドでバージョンを確認します。

```
sf version
@salesforce/cli/2.35.6 darwin-x64 node-v20.11.1
```

`@salesforce/cli/2.xx.x`が2から始まっていればOK。


## 本番組織に接続する

コンソールから以下のコマンドを入力するとブラウザが開くのでログインします。

```
sf org login web --set-default-dev-hub --alias dev
```

![apex-del1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075648/596a4f70-f3f5-d389-4bc1-89f32d700274.png)

ログイン後にこの画面が開けばOK。

![apex-del2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075648/87255f84-1745-5edd-3b7e-8d35eb2ac729.png)

---

`org login web`がうまくいかない場合は`org login device`を使う。書き方はwebと一緒。

```
sf org login device --set-default-dev-hub --alias dev
```

```
% sf org login device --set-default-dev-hub --alias dev
=== Action Required!

Enter XXXXXXXX device code in this verification URL: https://login.salesforce.com/setup/connect
```
実行するとこんな感じで8桁の文字列とログインURLが返されるので、ブラウザで開いて`XXXXXXXX`の部分を入力する。

**参考**
* [Salesforce CLI Command Reference - org login web](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_org_commands_unified.htm#cli_reference_org_login_web_unified)
* [Salesforce CLI Command Reference - org login device](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_org_commands_unified.htm#cli_reference_org_login_device_unified)

## destructiveChanges.xmlの作成

VS Codeで作ります。

![apex-del3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075648/fbc555de-0fd5-3467-3960-fabb7c047e03.png)

プロジェクトを右クリックして`SFDX: Generate Manifest File`をクリック。

![apex-del4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075648/f9750c91-3a1a-1fde-6940-8d9bf0a5d4ac.png)

ファイル名を`destructiveChanges.xml`と入力します。

:::note info
マニフェストファイルの名前にはルールがあり、削除のみを行う場合は`destructiveChanges.xml`とするらしい。
:::

![apex-del5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3075648/d8ca056b-4157-d1ff-aef6-47dd285c7fff.png)

プロジェクト内のmanifestフォルダにファイルが作成されました:bulb:

```xml:destructiveChanges.xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <fullName>destructive</fullName>
    <types>
        <members>HogeController</members> <!-- 削除したいApexクラスの名前 -->
        <members>HogeControllerTest</members>
        <name>ApexClass</name> <!-- 削除したいコンポーネントの名前 -->
    </types>
    <types>
        <members>HogeTrigger</members>
        <name>ApexTrigger</name>
    </types>
    <version>60.0</version> <!-- APIバージョン -->
</Package>
```

ある程度の枠組みは最初から入力されているので、こんな感じで中身を書き足します。

* fullName
    * 変更セットの名前にあたるもの
* members
    * 削除するファイルの名前
* name
    * 削除するコンポーネントの名前
* version
    * 削除対象を探す際、ここで指定されたバージョン以前のものを対象とする

---

上記の内容をコマンドから作る場合は`project generate manifest`を使います。

```
sf project generate manifest --metadata ApexClass:HogeController --metadata ApexClass:HogeControllerTest --metadata ApexTrigger:HogeTrigger -t destroy -d manifest
```

* `-m(--metadata)`で削除するコンポーネントを指定
    * コンポーネント名とファイル名を`:`で繋ぐことでファイル指定ができる
* 削除するためのファイルなので`-t(-type)`で`destroy`を指定
    * ファイル名が`destructiveChanges.xml`になる
* `-d(-output-dir)`で出力先をmanifestフォルダに指定
    * すでに同名のファイルがある場合は上書き

**参考**

* [メタデータ API 開発者ガイド - package.xml マニフェストファイルのサンプル](https://developer.salesforce.com/docs/atlas.ja-jp.api_meta.meta/api_meta/manifest_samples.htm)
* [Salesforce CLI Command Reference - project generate manifest](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_project_commands_unified.htm#cli_reference_project_generate_manifest_unified)

## package.xmlの作成

[destructiveChanges.xmlの作成](#destructiveChanges.xmlの作成)と同じ手順で作成します。
中身は空でOK！

```xml:package.xml
<?xml version="1.0" encoding="UTF-8"?>
<Package xmlns="http://soap.sforce.com/2006/04/metadata">
    <version>60.0</version> <!-- APIバージョン -->
</Package>
```

## 本番環境にデプロイする

以下のコマンドを実行します。
SFDXプロジェクト内でないと動かないので、VS Codeのターミナルタブからやると楽。

```
sf project deploy start --manifest manifest/package.xml --post-destructive-changes manifest/destructiveChanges.xml --target-org dev
```

* `-x(--manifest)`でマニフェストファイルのパスを指定
    * SFDXプロジェクトを基準にした絶対パス
* `--post-destructive-changes`で`-x(--manifest)`と同じパスを指定
    * `pre`と`post`があるが、デプロイ後にファイル削除するので`post`の方を使う
* `-o(--target-org)`でデプロイ先の組織を指定

```
Deploying v60.0 metadata to ixxxng@example.co.jp using the v60.0 SOAP API.
Deploy ID: XXXXXXXXXXXXXXXXXX
Status: Succeeded | ████████████████████████████████████████ | 2/2 Components | 6/6 Tests

Test Results Summary
Passing: 6
Failing: 0
Total: 6
Time: 11698
```

`Status: Succeeded`でこんな感じのログが返ってくれば成功です。
CLI、簡単だけど難しい。

**参考**
* [Salesforce CLI Command Reference - project deploy start](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference_project_commands_unified.htm#cli_reference_project_deploy_start_unified)