Edited at
herokuDay 19

HerokuのRelease PhaseやPreDeploy Script中に得た値を保持する方法


Release Phase, predeploy 中に得た値を pr-predestroy でも使いたい

HerokuにはRelease Phaseやpredeploy,pr-predestroyといった、アプリケーションがビルド・リリースされる際に自由にScriptを差し込むことができる機能があります。

image.png

Release Phase : https://devcenter.heroku.com/articles/release-phase

非常に便利なのですが、単純にScriptを動作させる機能ですので生成・取得した値をアプリケーションに渡す方法などは備わってません。

しかしHerokuをCI/CDの実現の為にPipelineサービスとして利用するようなケースだと、predeployやRelease Phaseの中でビルド処理などを行い、pr-predestroyで環境のクリーンアップを行う様なケースも出てきます。その際には、Script中で得られたビルドに関する情報を保持しておく必要があります。

例えばSalesforceアプリをCI/CDするケースでは、Herokuはそのビルド処理とパイプライン管理を担当します。

predeployのScript中でインスタンスの情報(インスタンスURL、Usernameなど)を生成しますが、この情報を覚えておけないため後で作成したアプリを破棄することができず、PRが作成されるたびに無駄なSalesforceインスタンスが生成され続ける事になります。

ここでHeroku標準では環境変数の置き場であるConfig Varsの機能がありますが、Herokaiな貴方ならもうお気付きの通りHeroku Config Varsは変更されるとリリースプロセスが再実行されます。つまり場合によっては無限ループとなってしまったり、そもそもHerokuコマンドでHeroku VarsをDynoの中で利用するには自分のアプリ名を受け渡す必要があるなど、あまりシンプルな作りになりません。

ではどのように解決するか? ですがHeroku Redisを利用するという方法があります。


Heroku Redis Add-onを利用して値を受け渡す

言ってしまえば単純な話ですが、Heroku Redis Add-onを用意してRedis経由で値をやりとりします。

もちろんPostgresを使ったり、他の何かしらのデータ永続化サービスを使えば同様の事は実現できますが、Redisの場合には設定及びCLI経由でのアクセスが簡単なのでお手軽です。


Step1. 必要な BuildPack 及び Add-on の追加

RedisにRelease Phaseやpredeploy, pr-predestroyからアクセスするには、redis-cliを利用する方法が手っ取り早いです。Heroku標準ではredis-cliは入っておらず、専用のBuildPackもありませんが、aptコマンドを実行して任意のパッケージをインストール可能にする apt BuildPack (https://github.com/heroku/heroku-buildpack-apt.git) があるのでこれを利用します。

サンプルでは他の処理をするSalesforce-cliとJSONの処理用にjqの BuildPackが定義されていますが、apt BuildPackはこのように他のBuildPackと併用して利用することが可能です。

また当然Redisが必要となりますので、heroku-redis Addonも追加しておきます。

app.jsonで表現すると以下の様な構成です。


app.json

{

"name": "Sample App",
"description": "Sample app for Salesforce Pipeline",
"keywords": [
"heroku"
],
"scripts": {
"predeploy": "./predeploy.sh",
"pr-predestroy": "./pr-predestroy.sh"
},
"addons": [
"heroku-redis"
],
"buildpacks": [
{
"url": "https://github.com/mokamoto/salesforce-cli-buildpack.git"
},
{
"url": "https://github.com/heroku/heroku-buildpack-apt.git"
},
{
"url": "https://github.com/chrismytton/heroku-buildpack-jq.git"
}
]
}

実際のRedis-cliはaptのredis-toolsのパッケージの中にあります。apt BuildPackはトップディレクトリのAptFileというファイルを読み込んでパッケージを展開する仕様となっていますのでこちらも用意します。


Aptfile

redis-tools



Step2. Script 中で Redis を利用する

環境さえ整えばあとは簡単です。

Heroku Redis Add-onを入れるとConfig VarsのREDIS_URLに接続するためのURIが入りますので、これを利用するだけです。

サンプルとしてSalesforce CLIを用いた組織生成のコードの一部を書いていますが、重要な部分は下部のredis-cliを利用すれば任意のkeyに対して値を保存できるという部分です。


predeploy.sh

#!/bin/sh

############ Salesforce関連処理。検証用インスタンス(Scratch組織)を立ち上げ、ソースコードをデプロイする ############
#Decrypt server.key
openssl aes-256-cbc -d -pass pass:$SFDX_DEVHUB_KEY_CRYPT_PASS -in assets/server.key.enc -out assets/server.key

#管理アカウントで認証
sfdx force:auth:jwt:grant --clientid $SFDX_DEVHUB_CONSUMERKEY --jwtkeyfile assets/server.key --username $SFDX_DEVHUB_USERNAME --setdefaultdevhubusername -a HubOrg

#Salesforceインスタンス生成
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

#設定情報の取得
TEMP_JSON_RESPONSE=$(sfdx force:org:display --json)
TEMP_LOGIN_URL=${INSTANCE_URL}/secur/frontdoor.jsp?sid=${ACCESS_TOKEN}
TEMP_USER_NAME=$(echo $SFDX_JSON_RESPONSE | jq -r ".result.username")
################################################################################################

#################################### Redisへ値を保持しておく ####################################

#ログインURL (WebアプリがRedirectするURL)
redis-cli -u $REDIS_URL set SFDX_SCRATCH_ORG_LOGIN_URL ${TEMP_LOGIN_URL}

#ユーザ名 (Salesforceインスタンスを削除する際に必要)
redis-cli -u $REDIS_URL set SFDX_SCRATCH_ORG_USERNAME ${TEMP_USER_NAME}
################################################################################################


保持した値を利用する場合にも、redis-cliを利用します。

例えばPull RequestがCloseされた際に、Redisから取得してDeploy時に作成したSalesforceインスタンスを削除します。


pr-predestroy.sh

#!/bin/sh

#################################### Redisから値を取得する ####################################

TEMP_USERNAME=$(redis-cli -u $REDIS_URL get SFDX_SCRATCH_ORG_USERNAME)

################################################################################################

############ Salesforce関連処理。一時的に作成したSalesforceインスタンスを削除する ############
#Decrypt server.key
openssl aes-256-cbc -d -pass pass:$SFDX_DEVHUB_KEY_CRYPT_PASS -in assets/server.key.enc -out assets/server.key

#管理アカウントで認証
sfdx force:auth:jwt:grant --clientid $SFDX_DEVHUB_CONSUMERKEY --jwtkeyfile assets/server.key --username $SFDX_DEVHUB_USERNAME --setdefaultdevhubusername -a HubOrg

#Salesforceインスタンスを削除
sfdx force:org:delete -u $(TEMP_USERNAME)


Pull Requestが来るたびにRedis Addonなどの環境は都度出来上がりますので、この様な簡易的なScriptでもSalesforceのPilelineを上手く回すことができます。リクエスト環境に応じて適宜書き換えていけば、かなり自由度が高くScriptingができると思います。

Happy Hacking!!