ROBOT PAYMENT TECH-BLOG

株式会社ROBOT PAYMENTのテックブログです

Salesforce CLI × GitHub ActionsでCIパイプライン構築

 こんにちは!
 ROBOT PAYMENTで請求管理ロボ for Salesforce の開発をしている木村です。
 今回はGitHub Actions と Salesforce CLI を活用したCIパイプラインの構築してみましたのでご紹介します。

以前までの運用と課題

運用

 請求管理ロボ for App Exchange は第一世代管理パッケージであり、パッケージ作成環境としてはPBO(※1)から払い出したPDEを利用しています。
 運用としては以下のようになってます。

※1 AppExchangeパートナーが利用する組織で、アプリケーション開発やライセンス管理、顧客組織へのアプリ配布などを行うための環境

課題

メタデータの取り込み漏れ

 各開発者がPDEで開発を進める際、特にFlowやSalesforce内で設定・実装したカスタムオブジェクト、その他カスタム項目などのメタデータ(Apex以外のメタデータ)は、対象のSalesforce組織からローカル環境へ手動でpullする必要があります。Apexクラスの作成はローカルで行うことが多いため問題になりにくいですが、Apex以外のメタデータについてはpullし忘れが発生し得る状態でした。

 そのため、本来揃っているべきメタデータが欠如した状態でPRが作成されてしまいます。該当ブランチのソースコードの状態はSalesforce組織にデプロイして初めて正常なメタデータセットであるかがわかります。

 結果、PR作成時点でメタデータ不足に気づかないままリリース作業まで進んでしまっていました。

UTの実装修正漏れ

 現在、各開発者が個別のPDEでUTを手動で実行しているため、テスト実施可否が担当者に依存しており、稀にテスト実施をしないでリリース作業まで進んでしまっていました。

 その結果、本番環境でのパッケージアップロード作業中に初めてUTの失敗に気づくような不具合の検出遅れが発生し、リリース日が迫り汗汗した状況での修正対応に陥るといったこともありました。

手動デプロイ作業の手間

 パッケージ作成環境 へのデプロイ作業は手動で行われており、差分ファイルが大量にある場合や、日本語・スペースを含むファイル名が含まれる場合に、デプロイコマンドの作成に手間がかかり、属人化してしまうという課題がありました。

改善後の運用

 上記の課題を解決するため、GitHub Actions と Salesforce CLI を用いた CIパイプラインを構築しました。

PR 更新タイミングで自動デプロイ検証

 PRの更新タイミングでsf project deploy validate を実行します。

 それにより、自動的にデプロイ検証とUTが実行されます。結果、UTが失敗する状態にあることやSalesforce組織にデプロイするにあたって本来必要であるメタデータセットの漏れなどの不具合の早期検出が可能になりました。

 これらの不具合の検出がPR更新時点で確認できることによって、パッケージ作成環境でのパッケージアップロード作業中でのメタデータやApexの修正をすることが無くなります。

GitHub Actions を介したデプロイ

 デプロイを GitHub Actions 上で実行できるようになったことで手動での作業手順を削減したことと、特定の担当者に依存しないデプロイプロセスのため、デプロイミスを減らす再現性の確保に期待できます。

 GitHub上から特定の条件で手動でワークフローを手動でトリガー可能です。任意のブランチを指定しmainブランチとの差分ファイルを自動検出しデプロイを実行します。

効果

デプロイ時エラーの早期検出

 PR 更新時の自動デプロイ検証と自動 UT 実行により、パッケージアップロード作業前の早期段階で不具合を検出できるようになりました 。

デプロイ作業の簡素化

 デプロイ対象ファイルの自動抽出や GitHub Actions 上での完結により、デプロイ作業の手間が大幅に削減されました 。

属人性の排除と再現性の確保

 マニュアルを参照すれば誰でもデプロイ作業が可能になり、特定の担当者に依存しないプロセスとなります。

GitHub ワークフロー実装例

 実装した GitHub ワークフローの主要なステップは以下の通りです。ここではデプロイ検証のワークフローをご紹介します。

name: Dry Run Salesforce Deployment

on:
  pull_request:
    types: [opened, synchronize, reopened]
    branches:
        - 'v*'
        - 'main'

jobs:
  deploy-dry-run:
    runs-on: ubuntu-latest

    steps:
        # リポジトリのコードをワークフローの実行環境にチェックアウトします。
        # fetch-depthは0を指定し最新のコミットを参照できる状態にする必要があります。
      - name: Check out the code
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      # Salesforce CLIのインストール
      - name: Install Salesforce CLI
        run: |
          node --version
          npm install @salesforce/cli --global
    
      # GitHubのSecretsに保存されている秘密鍵の内容を使って、Salesforce組織認証に必要なJWT秘密鍵のファイルを生成します。
      # Salesforce組織認証ステップでの --jwtkeyfile オプションはファイルパスを期待しているため、ここでファイルを作成する必要があります。
      - name: Create JWT key file
        run: |
          echo "${{ secrets.SF_JWT_KEY }}" > jwt_key_file.key    
      
      # 選択したデプロイ先組織に応じてSF組織のコンシューマ鍵を指定。
      # コンシューマ鍵(SF_CONSUMER_KEY)はGitHubのSecretsに定義しています。
      - name: Set SF_CONSUMER_KEY based on environment
        env:
          ENVIRONMENT: ${{ github.event.inputs.environment }}
          SF_CONSUMER_KEY: ${{ secrets.SF_CONSUMER_KEY }}
        run: |
            echo "SF_CONSUMER_KEY=${{ secrets.SF_CONSUMER_KEY }}" >> $GITHUB_ENV

      # Salesforce組織に認証
      # デプロイ先のSalesforce組織に対して認証を行います。JWT秘密鍵ファイルとコンシューマ鍵、ユーザー名、インスタンスURLを使用して、Salesforce CLI経由で認証セッションを確立します。
      - name: Authenticate with Salesforce Org
        run: |
          INSTANCE_URL=https://pkgMngOrg-dev-ed.my.salesforce.com/
          USER_NAME=test@example.com
          sfdx auth:jwt:grant --instanceurl=${INSTANCE_URL} --clientid ${{ env.SF_CONSUMER_KEY }} --jwtkeyfile jwt_key_file.key --username ${USER_NAME} --alias targetOrg

      # 差分ファイル抽出しデプロイ検証
      - name: Get diff files & dry run deploy
        id: diff
        run: |
          BASE_BRANCH="${{ github.head_ref }}"
          readarray -d '' DIFF_ARRAY < <(git diff origin/main..origin/$BASE_BRANCH --name-only -z --diff-filter=ACMRT | \
            grep -z '^force-app/main/default/' | \
            grep -zv '^force-app/main/default/profiles/' | \
            grep -zv '^manifest/package.xml')

          echo "👇 以下ファイルのデプロイ検証・UT実行:"
          printf '%q\n' "${DIFF_ARRAY[@]}"

                   # 差分ファイルがない場合は、デプロイ検証をスキップします。
          if [ "${#DIFF_ARRAY[@]}" -eq 0 ]; then
            echo "✅ 差分がありません。スキップします。"
            exit 0
          fi

                   # 差分ファイルがある場合、sf project deploy validate にて、Salesforce組織へのデプロイ検証(ドライラン)とテスト(-test-level RunLocalTests)を実行します。
                   # これにより、実際にデプロイすることなく変更が組織にデプロイ可能かの検証とデプロイされたと仮定した状態(仮想トランザクション内での)テストを実行します。
          echo "🧑<200d>🚀 差分ファイルのデプロイ検証・UT実行中です..."
          sf project deploy validate \
            --source-dir "${DIFF_ARRAY[@]}" \
            --target-org targetOrg \
            --test-level RunLocalTests

今後の展望

 デプロイの事前検証の時点でデプロイ検証が完了しているため、検証後のジョブID を指定することで迅速にデプロイを完了できるクイックデプロイの検討をしています。また、デプロイ手順のマニュアル整備を進め、誰でも簡単に利用できる状態を目指したいです。

 さらに、パッケージ作成環境にデプロイ後のパッケージアップロード作業についてもCLIで行えるようにする状態も目指しています。

 今後、当技術については私の関わる請求管理ロボ for Salesforce 以外のApp Exchange プロダクトにも適用可能なため、今後展開していければ良いとも思っております。

まとめ

 デプロイの事前検証とUT が自動で実行されることで不具合の早期発見によって品質向上の貢献に期待できると思います。 また、デプロイ作業も簡素化できました。

 日々の開発業務とは別で、このような運用改善にも今後積極的に関わっていきます!!!



We are hiring!!

ROBOT PAYMENTでは一緒に働く仲間を募集しています!!!


www.robotpayment.co.jp