Salesforce Developers Japan Blog

Salesforce CLI の出力とスクリプトの作成

(この投稿は Thomas Dvornik(Salesforce.com) による『Using Salesforce CLI Output and Scripting』の翻訳です)

ここ数年で、 Salesforce CLI は 開発者が Salesforce を操作するためのツールとして広く認知されるようになりました。これまでも Salesforce は継続的にこのツールの改良に努めてきましたが、時として出力形式の仕様の変更といった利用者に影響のある変更も行ってきました。そこで、このブログでは Spring ’20 で生じた変更と、どのようにその変更に対応すればいいのかをご紹介します。

提供開始当初の Salesforce CLI は、ソース駆動型開発のためのツールという位置づけで、その機能も限定的でした。ところが、時間の経過と共に Salesforce CLI は単なるコマンドラインツールから、Salesforce を操作するための標準的なツールへと成長を遂げました。今では毎週数百万のコマンドが実行されています。CLI の成長に合わせて、Salesforce はコマンドやフラグ、出力の標準化に取り組んできました。例えば、全てのコマンドで –json を指定出来るようにしました。これにより Salesforce CLI を利用したツールやスクリプトをより簡単に作成できるようになりました。

このブログポストでは以下について、詳しく説明していきます。

  1. Salesforce の出力
  2. 出力ストリームの種類と用途を説明
  3. Salesforce CLI のインパクトと将来的な変更への対処
  4. スクリプト、ツール、継続的インテグレーションでの出力の利用におけるベスト・プラクティス

それよりも、まずは Salesforce DX や Salesforce CLI について詳しく知りたいという方はこちらの Trailhead プロジェクトを御覧ください。

既に、Salesforce CLI について知っており、スクリプトの作成や CI/CD での活用が考えている方にとって、このブログの内容は役に立つはずです。

ヒューマン・リーダブルとマシン出力

CLI コマンドを実行した際の出力は、読みやすければ助かります。そのためには、読み手に合わせて出力の形式を出し分ける必要があります。出力の形式は、読み手が人間なのか、もしくはマシンなのかによって全く違うものになるでしょう。

ここで、一つ例を見てみましょう。

-> ls -l
total 20
-rw-r--r-- 1 username staff 12 Feb 5 21:08 example.txt
-rw-r--r-- 1 username staff 8 Feb 5 21:10 example2.txt

このような出力であれば、多くの方が比較的容易に解読できるかもしれません。現在開いているディレクトに存在する全てのファイルの所有者、ファイルサイズ、作成日、ファイル名などを表示するテーブルです。ところが、マシンにとってこのような形式の出力の解読は、簡単とは言えません。最初の行はテーブルの形式ではないでの解析出来ません。以降の行を解析するには、コンピュータは空白で区切られた文字列を一行毎に検知し、スクリプトやツールで指定された通りに情報を読み取っていく事になります。このような解析も可能ではありますが、将来に渡って常に同じ形式で出力される事が条件となるでしょう。出力の形式が変更された途端に、解析ツールは正常に動作しなくなります。

人間が解読可能(ヒューマン・リーダブル)な出力の改善を継続しながらも、それによってスクリプトやツールが壊れる心配を排除するために、–json は全てのコマンドに対応したのです。JSON 形式の出力については、Salesforce の CLI 非推奨ポリシーでも触れられています。

CLI 非推奨ポリシーについても復習しておきましょう。

Salesforce では Salesforce CLI のヒューマン・リーダブルな出力に対する解析やその方法についてはサポートしていません!ツールやスクリプトの作成時は JSON 形式の出力を利用して下さい。

仮に JSON 出力に関して何らかの変更が生じた場合は、利用者には事前に警告が表示され修正のための猶予が提供されます。

標準出力(sdtout) と標準エラー出力(stderr)

プログラムが出力を送信できるターミナルの標準ストリームには、stdout と stderr の二種類があります。名前からも分かる通り stderr にはエラーや警告が送られ、その他は stdout に送られる事になります。ところが、他にも処理の進捗や診断情報、デバッグ情報など stderr に送られてくる有益な情報はたくさんあります。実のところ、stderr はプログラムによって解析される想定にない出力の送信先として使われており、いつ誰がどんな情報を送信しているか分かりません。例えば、自身で作成したツールが依存しているライブラリが、新しいバージョンの利用を促す警告メッセージを stderr に出力することもあり得ます。

ストリームの利用用途については多くの議論がありますが、共通して言われているのは、stderr の出力は解析すべきではないと言うことです。

stderr の利用には多くのメリットがあります。警告や進捗情報などのノイズとなるメッセージを分離して出力できるのもその一つと言えます。

# stdout.txt には echo の結果が出力されるが、stderr.txt は空となる
echo "print to stdout" > stdout.txt 2> stderr.txt

それでは、 Salesforce CLI がこれらのストリームをどのように利用しているのか、Spring ’20 ではどのような変更があったのか見てみましょう。

Salesforce CLI の場合

Salesforce CLI は stdout と stderr のガイドラインに厳密に従ってきたつもりでした。–json が指定された時を含めて、全てのエラーメッセージを stderr に送信する方針をとってきたのもそのためです。
しかし、この仕様を元に開発されたツールやスクリプトは、ステータスが 0 の時は stdout を、ステータスが 0 よりも大きい時は、誰が何を送信するか分からない stderr の出力を解析しなければなりませんでした。そこで、最終的に生成された JSON 以外の出力を全て無効化することにしました。それでも、全く予想できない形で送信される stderr への出力の全てを排除する事は出来ませんでした。このようなケースで、JSON の解析は異常終了します。。

sfdx force:org:display -s --json > stdout.txt 2> stderr.out
# 警告やデバッグメッセージが出力されると以下はエラーとなる
more stderr.txt | jq # parse the json error with jq

予期しない出力を全て捉えるための挑戦を続ける事も出来ましたが、これでは stderr への出力は解析しないというガイドラインへの違反を解決することが出来ません。そこで、例えエラーであっても JSON オブジェクトは stdout へ出力するべきと方針を転換する事になりました。しかし、この変更は既存のツールとスクリプトにとって破壊的な変更となるため、全ての JSON 出力を stdout に出力するための環境変数を追加することになりました。これによって、stderr ではあらゆる情報の出力を許容したまま、JSON を解析するツールが異常終了する状況を救えます。

# stderr を無視することで jq による解析が常に可能となる
SFDX_JSON_TO_STDOUT=true sfdx force:org:display -s --json 2> /dev/null | jq

SFDX_JSON_TO_STDOUT は v44 でリリースされ、v45 にでもデフォルト設定となる予定でした。
残念ながらそれは実現しませんでしたが、2 月にリリースされた v48 で無事にデフォルトの挙動となりました。もし、あなたの作成したツールが –json を指定していて stderr への出力に依存しているのであれば、忘れずにツールを更新するか SFDX_JSON_TO_STDOUT を false に設定するようお願いします。–json を指定していても多くの警告やエラーが stderr へ出力される可能性があります。

ツールの作成中、一部のメッセージが誤ったストリームに出力される事があるかもしれません。実際に、Salesforce CLI のプラグインである salesforcedx のバージョン 47.18.0 ではプログレスバーが stdout に出力されていたため、本来あるべき stderr に移動するという対応を実施しました。もし、他にも間違った場所に表示されているメッセージを見かけたら、こちらまでご連絡下さい。

スクリプト作成のベスト・プラクティス

スクリプトを作成する事で、非常に広く事が実現出来ます。その中でも、プログラムのテストや日々の業務など、繰り返し行うような作業を自動化出来るのが最大のメリットと言えます。例えば、開発を始める前に開発環境を構築したり、スクラッチ組織にメタデータ、データ、権限セットといった必要なデータを前もって流し込むこともできます。

また、いわゆる CI/CD もスクリプトの一種と言えます。アプリケーションのテストやデプロイといった繰り返し実行される決まった作業を、開発者が手作業で行う代わりに自動化しているのです。例えば、プロジェクトチームの開発者達が、一つの CI ツールを共有すれば、全く同じスクラッチ組織を構築する事も可能になります。

一方で CI/CD のようなスクリプトでも、実行環境の違いや利用するツールが原因で異常終了してしまうのは珍しいことではありません。こういったスクリプトが予期せず異常終了する可能性を減らし、将来的に避けられないツールの仕様変更へに対応してもらうための時間を十分に提供することこそが、JSON 出力への対応と Salesforce の CLI 非推奨ポリシーのゴールです。

ここまでの説明の通り、Salesforce CLI ではスクリプトによる JSON 出力の解析をサポートしています。これは JSON 出力ではないものは解析すべきではないという事でもあります。プログレスバーやヒューマン・リーダブルな出力の解析は、スクリプトの異常終了に繋がる事を意識しておいて下さい。

一つ例を見てみましょう。時間のかかるデプロイの処理をキューに追加した上で、別の処理を実行してから、ジョブの進捗状況を確認したいとします。このスクリプトでは、sed によってヒューマン・リーダブルな出力から Id を取得しておく設計としたようです。

# sed を使ってジョブ Id の値を取得
ID=$(sfdx force:source:deploy --metadata=StaticResource -w=0 | sed 's/^Id: \(.*\)/\1/')
# その後ジョブの進捗を確認
sfdx force:source:deploy:report --jobid=$ID

後日、開発者コミュニティからの強い要望を受け、”Id: <jobid>” であったツールの出力形式が “Enqueued Deploy Job Id: <jobid>” に変更されたとします。新しい出力形式は現在のスクリプトでは上手く解析できず、異常終了してしまうでしょう。 –json フラグを使って JSON 出力を解析していれば、このような事は起きませんでした。

# sed を使ってジョブ Id の値を取得
ID=$(sfdx force:source:deploy --metadata=StaticResource --json -w=0 2> /dev/null | jq -r .result.id)
# その後ジョブの進捗を確認
sfdx force:source:deploy:report --jobid=$ID

正規表現による解析が不要となったことでより簡単に Id を取得出来るようになっただけでなく、将来的な CLI の変更にも対応可能になりました。また、SON 形式でないメッセージを 2> /dev/null によって分離できるので誤って解析してしまう恐れありません。

また、一般的には JSON 出力であれば実行結果に関する詳細な情報などより多くの情報を提供する事ができます。これはエラー発生時に特殊なエラーハンドリングを必要とする場合などに役立ちます。

まとめ

4 年前、Salesforce は開発者体験をより改善していくことを宣言しました。
その約束を守るためにも、開発ツールの改善に取り組み続け、今も当初勢いを保っています。そして、これからも継続して開発者体験の改善に取り組んでいきます。

今回ご紹介した Salesforce CLI について更に詳しく知りたい方は、Trailhead のプロジェクトをオススメします。

自動化の推進にあたっては、いくつかの CI ツールで使えるテンプレートも提供していますの合わせてご確認下さい。

この記事で、少しでも Salesforce CLI の出力とその利用方法について知って頂けたら幸いです。

重要なのは –json を指定する事と、出力の解析は stdout に対してのみ行うという事でした。

最後に個人的なものではありますが、このツールを利用してくださる皆さん、バグの報告をくださる皆さん、機能追加のリクエストをくださる皆さんに感謝をお伝えします。
まだまだ遠い道のりではありますが、Salesforce のカスタマーサクセスプラットフォームが、世界最高の開発プラットフォームになれることを日々楽しみに、これからも改善に努めていきます。

トピック:

コメント

Salesforce CLI の出力とスクリプトの作成