GitHub Actionsでsandboxを自動更新

この記事は[Ateam LifeDesign Advent Calendar 2023](https://qiita.com/advent-calendar/2023/ateam-life-design)の19日目の記事です。

# はじめに

今回は、[sfpowerkit](https://github.com/dxatscale/sfpowerkit)というSalesforce CLIのプラグインを使ってsandoxを自動更新しようと思います。

:::note warn
sfpowerkitは現在非推奨で[sfpowerscripts](https://github.com/dxatscale/sfpowerscripts)に移行中ですが、
2023/12現在 sandbox refreshはsfpowerkitでしか対応していません。
なので今回はsfpowerkitを使用しています。
:::

# 完成したもの

以下のようなスケジュールでSalesforceのsandboxを自動更新する
GitHub Actionsができました。

常に最新のsandboxが一つ存在するように、2つのsandboxの更新をローテーションしています。

|月曜|火曜|水曜|木曜|金曜|
|---|---|---|---|---|
|latest|latest2|latest|latest2|latest|

```yml:refresh-sandbox.yml
name: SNDBOX 自動更新 0時（latest（月・水・金）, latest2（火・木））

on:
  schedule:
    - cron: "0 15 * * 1,3,5" # 月・水・金 JST 00:00 に latest sandbox更新
    - cron: "0 15 * * 2,4" # 火・木 JST 00:00 に latest2 sandbox更新

jobs:
  refresh_sandbox:
    runs-on: ubuntu-latest
    environment:
      name: schedule_production
    steps:
      - name: Make temporary directory
        run: |
          mkdir ./tmp
      - name: Install Salesforce CLI
        run: |
          wget https://developer.salesforce.com/media/salesforce-cli/sfdx/channels/stable/sfdx-linux-x64.tar.xz
          mkdir ./tmp/sfdx-cli
          tar xJf sfdx-linux-x64.tar.xz -C ./tmp/sfdx-cli --strip-components 1
          echo "./tmp/sfdx-cli/bin" >> $GITHUB_PATH
      - name: sfdx version
        run: sfdx version
      - name: set name latest
        if: github.event.schedule == '0 15 * * 1,3,5'
        run: echo "SANDBOX_NAME=latest" >> $GITHUB_ENV
      - name: set name latest2
        if: github.event.schedule == '0 15 * * 2,4'
        run: echo "SANDBOX_NAME=latest2" >> $GITHUB_ENV
      - name: echo sandbox name
        run: echo ${{ env.SANDBOX_NAME }}
      - name: install sfpowerkit
        run: echo y | sfdx plugins:install sfpowerkit
      - name: save into private-key
        run: echo -n "${{ secrets.SF_JWT_KEY_FILE }}" | base64 -d > ./tmp/server.key
      - name: auth
        run: sfdx auth:jwt:grant --instance-url ${{ vars.SF_INSTANCE_URL }} --client-id ${{ secrets.SF_CONSUMER_KEY }} --jwt-key-file ./tmp/server.key --username ${{ vars.SF_DEPLOY_USER }} --alias production
      - name: refresh sandbox
        run: echo y | sfdx sfpowerkit:org:sandbox:refresh -n ${{ env.SANDBOX_NAME }} -v production -l DEVELOPER
```

# なぜ毎日最新のsandboxが必要なのか？

Salesforceのsandboxには、本番から作成更新ではなく
**既存のsandboxをコピーして作成する方が早い**という特徴があります。

sandboxを利用して開発するメンバーの開発体験を上げるためにも
最新のsandboxを用意して、コピーする運用は非常に大事です。
（じゃないとsandbox作成に1日かかるのはよくある）

※今自分が利用している本番組織は、Hyperforceに移行済み組織ではないです。

>本番組織を送信元として使用するのではなく、既存の Sandbox をコピーして Sandbox を作成できます。一連のデータとメタデータで Sandbox をカスタマイズして、それを複製することで時間を節約できます。

https://help.salesforce.com/s/articleView?id=sf.data_sandbox_cloning_overview.htm&type=5

# この記事で詳しく説明しないこと

- GitHub Actions自体の詳細な説明
- Salesforce CLIについてや、セットアップ
- 接続アプリケーションの詳細な設定

# セットアップ

## 1. 接続アプリケーションの作成

今回はJWTを使った認証を使用します。

以下の記事がとてもわかりやすいです。

https://qiita.com/stomita/items/4542ce1b48e5fa849ef1

## 2. GitHub 環境変数のセット

### Variables

|Key|Value|
|---|---|
|SF_INSTANCE_URL| sandboxを作成する 本番組織のURL |
|SF_DEPLOY_USER|Salesforce CLIを実行する Salesforceユーザー名|

### Secrets

|Key|Value|
|---|---|
|SF_CONSUMER_KEY| 接続アプリケーションのコンシューマーキー |
|SF_JWT_KEY_FILE| 接続アプリケーションに登録したJWTの秘密鍵（.pem）をBase64でエンコードしたもの |

# 作成したGitHub Actionsについて

## 1. スケジュール実行

平日に２パターンでsandboxを更新する必要があるので、スケジュールは2つ登録しています

- 月曜・水曜・金曜 00:00
- 火曜・木曜 00:00


```yml
on:
  schedule:
    - cron: "0 15 * * 1,3,5" # 月・水・金 JST 00:00 に latest sandbox更新
    - cron: "0 15 * * 2,4" # 火・木 JST 00:00 に latest2 sandbox更新
```

## 2. 起動したスケジュールによって更新するsandboxを変える

スケジュールで起動した際に、どのスケジュールで起動したかが`github.event.schedule`の値を見るとわかります。
スケジュールによって更新対象のsandbox名が入る`SANDBOX_NAME`を動的に変更します。

```yml
  - name: set name latest
        if: github.event.schedule == '0 15 * * 1,3,5'
        run: echo "SANDBOX_NAME=latest" >> $GITHUB_ENV
      - name: set name latest2
        if: github.event.schedule == '0 15 * * 2,4'
        run: echo "SANDBOX_NAME=latest2" >> $GITHUB_ENV
```

## 3. 認証

更新前に本番組織へJWT認証を行います。

```yml
      - name: save into private-key
        run: echo -n "${{ secrets.SF_JWT_KEY_FILE }}" | base64 -d > ./tmp/server.key
      - name: auth
        run: sfdx auth:jwt:grant --instance-url ${{ vars.SF_INSTANCE_URL }} --client-id ${{ secrets.SF_CONSUMER_KEY }} --jwt-key-file ./tmp/server.key --username ${{ vars.SF_DEPLOY_USER }} --alias production
```

## 4. sandboxを更新


```yml
      - name: refresh sandbox
        run: echo y | sfdx sfpowerkit:org:sandbox:refresh -n ${{ env.SANDBOX_NAME }} -v production -l DEVELOPER
```

|オプション|説明|
|---|---|
|-n|更新するsandbox名|
|-v| 認証した際のalias名 |
|-l|使用するsandboxのエディション（'DEVELOPER', 'DEVELOPER_PRO', 'PARTIAL', 'FULL） |


# 最後に

SalesforceのCLIプラグインは、開発者の作業効率を大幅に向上させるための便利なツールを数多く提供しています。今回の記事では、これらのツールの中から特に[sfpowerkit](https://github.com/dxatscale/sfpowerkit)を取り上げ、Salesforceのsandboxの自動更新について解説しました。sfpowerkitを活用することで、sandbox利用者は更新プロセスの時間短縮を実現し、全体の開発体験が格段に向上しました。また、常に最新のsandboxを維持することにより、小規模ながらも実質的なメタデータのバックアップとしての役割も果たしています。このような多面的な利点を考慮すると、sandboxの自動更新を検討している方々には、sfpowerkitの利用を強くお勧めします。

https://developer.salesforce.com/docs/atlas.ja-jp.sfdx_dev.meta/sfdx_dev/sfdx_dev_create_clone_sandboxes.htm

ただし、現在sfpowerkitは非推奨とされています。将来的には、Salesforce公式のSandbox操作コマンドやsfpowerscriptsにリフレッシュ機能が追加されることを期待しています。