Heroku
Salesforce

Salesforce DXとHeroku Pipelineを組み合わせる

Salesforce DX とは?

https://developer.salesforce.com/platform/dx

Salesforce DXとは、SalesforceのLightning Platform上でアプリケーション開発を行う際に利用する、一連のサービス群のことを指しています。大きく分けると以下のような機能を提供しており、今までSalesforceの開発は独自志向と言われていましたが、DXを使えば一般的なツールやプロセスに沿って開発が行えるようになると言われています。

機能 概要  
DevHub組織 & Scratch組織 本来のSalessforce組織(インスタンスのようなもの)は、一度生成したら長い期間に渡って永続的に使用するというのが一般的でした。これに対して、DevHubと呼ばれる機能を利用すると、Hubとなる組織の配下に、Scratch組織というSalesforce環境をAPI経由で生成出来るようになりました。Scrach組織は任意のタイミングで新規に生成し、デプロイし、利用が済んだらすぐに破棄が可能です。
Salesforce CLI 上記Scratch組織の生成・破棄や、Hub組織への認証の管理、各種APIのCallなどといった一連の処理を、CUIから簡単に行えるようになるためのコマンドラインツールを提供します。
Development Tools VisualStudio Code向けのプラグインを提供しており、GUIからSalesforceのデプロイなどを行ったり、コードのシンタックスハイライトを提供します。
Package 2 (Beta) 開発したコードをDev Hub組織を経由して、他のSaelsforce組織へのインストールや、プッシュでのアップグレードを提供します。

dx.png

Heroku Pipelines とは?

https://devcenter.heroku.com/articles/pipelines

Heroku PipeLinesはHerokuの提供するCI/CD機能で、アプリケーション開発のライフサイクル管理を提供します。
アプリケーションのステージを

  1. Review Apps (マージ前のプルリクエストからデプロイ)
  2. Staging(マスタ/リリースブランチからデプロイ)
  3. Production (実際の本番運用してるインスタンス)

の3つの状態に分け、Githubのリポジトリと連携することによって、アプリケーションのビルドやテストを自動化することが可能です。

pipeline.png

今回はこのSalesforce DX のツール群と、Heroku Pipelineを使って、 「Githubにプルリク来たらソースDeploy済みのSalesforce組織が出来上がる」 を実現したいと思います。

前提条件

Salesforce DXとHeroku PipleLineを組み合わせるには、以下のアカウントが必要となります。

事前準備 : Salesforce CLIのインストール

ローカルマシンにDXのCLIが入っていることは必須ではないのですが、何かとあった方が良いのでインストールしておきましょう。

https://developer.salesforce.com/tools/sfdxcli

1. どのようにHerokuでSalesforceプロジェクトをビルドするか?

まずはどのようにHeroku上でSalesforceへのデプロイ処理等々をやらせるか、その原理を確認します。

Heroku PipeLinesでは対象リポジトリのコードが更新されると、

  1. リポジトリのコードをHeroku上にとってくる
  2. コードの動作に必要となるランタイムを用意
  3. パッケージーマネージャ(npm,gradleなど)の記述を元に、依存ライブラリをダウンロード
  4. ビルド・デプロイ

の処理が行われます。
しかしSalesforceはHerokuなどの外部の環境ではビルドできませんので、今回はソースコードをデプロイする先となるScratch組織の新規生成と、その組織へコードを送信を行わせます。

そこで、まずは BuildPacks を使ってsfdxコマンドをHerokuが扱えるようにします。元々からSalesforce DXのPMであるWade Wegnerが作ってくれたBuildpackが元からあるので、このビルドパックを使うように、Herokuアプリを設定します。

shell
## Buildpackの追加
heroku buildpacks:add https://github.com/heroku/salesforce-cli-buildpack

次にどの段階で、ビルドパックによって使えるようになったsfdxコマンドでSalesforceへコードを送信するかですが、これビルド後のアプリケーションリリース時に任意のコマンドを実行できるRlease Phaseやpostdeploy/pr-predestroy scriptと呼ばれる機能を使います。

機能 概要   利用方法
Release Phase Herokuへアプリケーションがデプロイされるたびに任意の処理を動作させることが可能 Procfile内でリリースタスクを指定
postdeploy/pr-predestroy script Herokuへ初回にアプリケーションがデプロイされる際に任意の処理を動作させることが可能 app.json内で指定

この機能を利用することで、プルリクエストが送信された際などに何かしらの変更があった場合に、Salesforce組織の生成とソースコードを送信することが可能になります。

2. Dev Hub組織への認証情報をHerokuで管理するには?

理論的にはHerokuの仕組みを使ってSalesforceのScratch組織の生成とコードのデプロイが可能なことは分かりましたが、もう一つ大きな課題として、cratch組織を生成・破棄するためには、DevHub組織へのアクセス(認証)が必要になると言う点です。

ここは、デジタル署名を利用したSalesforceの接続アプリケーションを作成し、暗号化した鍵のパスワードをHeroku Configで管理することによって、セキュリティを担保します。

ssl.png

鍵の生成
鍵の生成、暗号化をローカルで行い、そのcertを使用した接続アプリケーションを作成することで、HerokuからDev Hub組織へのアクセスを可能とします。

## RSA秘密鍵の生成
openssl genrsa -des3 -passout pass:x -out server.pass.key 2048
openssl rsa -passin pass:x -in server.pass.key -out server.key
rm server.pass.key
## certificateの作成
openssl req -new -key server.key -out server.csr

##########
## ......パスワード($DEVHUB_KEY_CRYPT_PASSに格納と仮定)などを入力
##########

## SSL certificateの作成
openssl x509 -req -sha256 -days 365 -in server.csr -signkey server.key -out server.crt

## 鍵の暗号化
openssl aes-256-cbc -e -k $DEVHUB_KEY_CRYPT_PASS -in server.key -out server.key.enc

出来上がったserver.key.encを使って、接続アプリケーションを生成します。

Salesforce DXプロジェクトにPipelines用のファイルを追加する

Saelsforce DXのプロジェクトに以下のようなHeroku Pipeline用のファイルを追加します。
また、app.json内にあるenv及びBuildpacksを、Herokuアプリケーションに追加しておきます。

app.json
{
    "name":"DX with Heroku Sample",
    "scripts": {
      "postdeploy": "./dx_postdeploy-tasks.sh",
      "pr-predestroy": "./dx_pr-predestroy-tasks.sh"
    },
    "env": {
      "DEVHUB_USERNAME": {
        "description": "Salesforce Username of DevHub Org",
      },
      "DEVHUB_CONSUMERKEY": {
        "description": "Consumerkey of Connected Application on DevHub Org"
      },
      "DEVHUB_KEY_CRYPT_PASS": {
        "description": "Password for Encripting Secret Server Key",
      }
    },
    "buildpacks": [
      {
        "url": "https://github.com/mokamoto/salesforce-cli-buildpack.git"
      },
      {
        "url": "https://github.com/chrismytton/heroku-buildpack-jq.git"
      }
    ]
  }
heroku config:add DEVHUB_USERNAME=<DevHub組織のユーザ名>
heroku config:add DEVHUB_CONSUMERKEY=<DevHub接続アプリケーションのコンシューマ鍵>
heroku config:add DEVHUB_KEY_CRYPT_PASS=<SSL証明書を暗号化・復号化のパスワード>

次に、デプロイされた際に動作するスクリプトを追加します。テスト用途となりますが、何かソースが変更されるたびに都度このタスクが動作する事を確認したいという方は、ProcfileにRelease Phaseとして追加して実行しても良いでしょう。
また、初回のDevHub組織へのjwtでの認証に使う鍵の暗号化されたものを assets/server.key.enc に配置しておきます。

shell
## 暗号化されたserver.key.encを移動
mkdir assets
mv server.key.enc assets/server.key.enc
dx_postdeploy-tasks.sh
#!/bin/sh

#Decrypt server.key
openssl aes-256-cbc -d -pass pass:$DEVHUB_KEY_CRYPT_PASS -in assets/server.key.enc -out assets/server.key

#update sfdx command
sfdx update
sfdx --version
sfdx plugins --core

sfdx force:auth:jwt:grant --clientid $DEVHUB_CONSUMERKEY --jwtkeyfile assets/server.key --username $DEVHUB_USERNAME --setdefaultdevhubusername -a HubOrg
sfdx force:org:create -v HubOrg -s -f config/project-scratch-def.json -a DevOrg
sfdx force:source:push -u DevOrg
sfdx force:user:permset:assign -n purealoe -u DevOrg
sfdx force:data:tree:import -p data/sample-data-plan.json -u DevOrg
sfdx force:org:display

DX_JSON_RESPONSE=$(sfdx force:org:display --json)
INSTANCE_URL=$(echo $DX_JSON_RESPONSE | jq -r ".result.instanceUrl")
ACCESS_TOKEN=$(echo $DX_JSON_RESPONSE | jq -r ".result.accessToken")
LOGIN_URL=${INSTANCE_URL}/secur/frontdoor.jsp?sid=${ACCESS_TOKEN}

echo "Login URL is Here : ${LOGIN_URL}"

実際に動かしてみる

あとは実際に初回にデプロイする、 or プルリクエストを作成してみれば、HerokuのReview AppやPostdeploy Scriptから組織が出来上がるのが確認できます。

課題

上記の工程によって、Salesforce DXを使ってHeroku Pipelineで動作させることが出来るようになっているのですが、幾つか課題もあります。

Scratch組織の破棄

Scratch組織はEE組織だと日に80組織までしか生成できず、保持できる組織も40組織までとなっています。今回のコマンドを使ってScratch組織をDeployのたびに生成していった場合、その組織は生成しっぱなしになってしまいますので、predestroyタスクを使って削除時に組織を削除する必要があります。

が、今のこのScriptだけだと、HerokuのAppがDestroyされる頃には(というよりビルドが終わった瞬間)、自分が作ったScratch組織の情報を忘れてしまっているので、消すことができません。
Redisなどを使って、生成したScratch組織の情報を保持しておく必要がありそうです。

Apex/Lightningテスト結果のハンドリング

CIを実施しようと思うと、Apexテスト、Lightning Test Serviceなども実行しなくてはなりませんが、コマンドを実行するとIDが発行され、そのステータスの完了を待ってから見るという構成になっています。
こちらもCLIだけで完了しようと思うと、ある程度ハンドリングが必要になるかと思われいます。

 まとめ

ということで、HerokuのPipelinesでSalesforce DXを動かすための構成でした。