GitHub Actions で複数行の文字列を output にセットする方法
GitHub Actions で改行文字を含む複数行の文字列をコマンドの output パラメータにセットする方法についてです。
前提
この記事は 2022 年 05 月に書きました。 時間が経つと GitHub Actions の仕様変更などで情報が古くなるので参考にされる際は注意してください。
問題
通常 GitHub Actions では ::set-output name={name}::{value}
というフォーマットの文字列を標準出力に出力すると value
の部分がコマンドの output パラメータとして認識されます。
たとえば、次のように書くと action_fruit
という名前の output パラメータに strawberry
という文字列がセットされま す。
run: |value=strawberryecho "::set-output name=action_fruit::${value}"shell: bash
しかし、 value
の文字列に改行文字が含まれていると output パラメータには最初の行のみがセットされてしまいます。
これはたとえば、 Hello\nWorld
という文字列を value
にセットした場合、 output パラメータ(次のコードの場合は greeting
)には Hello
だけがセットされるということになります:
run: |name=greetingvalue="Hello\nWorld"echo "::set-output name=greeting::${value}"shell: bashid: my_command# => `steps.my_command.outputs.greeting` には `Hello` だけが含まれる
関連イシューなど:
- set-output Truncates Multiline Strings - #9 by andreasplesch - GitHub Actions - GitHub Community
- set-env truncates multiline strings · Issue #403 · actions/toolkit · GitHub
対応方法
複数行の文字列を output にセットするための方法としていくつかの選択肢があります。
- 方法 A) エスケープしてから出力する
- 方法 B) output のかわりに環境変数を使う
- 方法 C)
@actions/core
のcore.setOutput()
を使う
後述しますが、私はシンプルな C) のアプローチを選びました。
方法 A) エスケープしてから出力する
標準出力に出力する前に value
内に含まれる改行文字などをエスケープします。
Bash スクリプトの場合は次のような処理を行うことになります:
value="${value//'%'/'%25'}"value="${value//$'\n'/'%0A'}"value="${value//$'\r'/'%0D'}"
参考:
- set-output Truncates Multiline Strings - #17 by cherryleafroad - GitHub Actions - GitHub Community
- set-env truncates multiline strings · Issue #403 · actions/toolkit · GitHub
方法 B) output のかわりに環境変数を使う
set-output
による output パラメータのセットは行わず、かわりに環境変数を使うという手もあります。
環境変数のセットには $GITHUB_ENV
を使用します。
このときヒアドキュメント風の書き方をすれば変数に複数行の文字列をセットできます。
次のサンプルでは、改行文字を含みうる curl
コマンドの出力を JSON_RESPONSE
という環境変数にセットしています( GitHub 公式ドキュメントのサンプルです):
steps:- name: Set the value in bashid: step_onerun: |echo 'JSON_RESPONSE<<EOF' >> $GITHUB_ENVcurl https://example.lab >> $GITHUB_ENVecho 'EOF' >> $GITHUB_ENV
参考:
方法 C) @actions/core
の core.setOutput()
を使う
NPM パッケージ @actions/core
の core.setOutput()
を使うというアプローチもあります。
@actions/core
のコードとドキュメントは actions/toolkit
リポジトリの中にあります:
core.setOutput()
はまさに GitHub Actions において output パラメータをセットするための関数です。
core.setOutput(name, value)
core.setOutput()
に渡した文字列は内部で自動的に A) と同様のエスケープ処理(↓)が行われた後に標準出力に出力されます。
function escapeData(s: any): string {return toCommandValue(s).replace(/%/g, '%25').replace(/\r/g, '%0D').replace(/\n/g, '%0A')}
core.setOutput()
を使う場合、利用側は改行問題の心配から解放されます。
@actions/core
を手軽に利用したいときは @actions/github-script
アクションが便利です。
@actions/github-script
はたとえば次のように使用します:
- uses: actions/github-script@v6with:script: |const name = 'greeting'const value = 'Hello'core.setOutput(name, value)
なお、 actions/github-script
を使う場合は、 core.setOutput()
を使う方法の他にも、 output パラメータにセットしたい値を return
する使い方などもあるので、そのあたり詳細に興味のある方は actions/github-script
の README をご覧になるとよいかと思います。
A) B) の方法でもできないことはないですが、個人的には C) の方法がシンプルでよいのではないかと思います。
以上です。
おまけ
「コマンドを 1 つ実行してその結果を output にセットする」というパターンは頻出な気がするので、そのためのかんたんなカスタムアクションを作りました: