gotohayato.com

GitHub Actions で複数行の文字列を output にセットする方法

GitHub

GitHub Actions で改行文字を含む複数行の文字列をコマンドの output パラメータにセットする方法についてです。

前提

この記事は 2022 年 05 月に書きました。 時間が経つと GitHub Actions の仕様変更などで情報が古くなるので参考にされる際は注意してください。

問題

通常 GitHub Actions では ::set-output name={name}::{value} というフォーマットの文字列を標準出力に出力すると value の部分がコマンドの output パラメータとして認識されます。

たとえば、次のように書くと action_fruit という名前の output パラメータに strawberry という文字列がセットされます。

run: |
value=strawberry
echo "::set-output name=action_fruit::${value}"
shell: bash

しかし、 value の文字列に改行文字が含まれていると output パラメータには最初の行のみがセットされてしまいます。 これはたとえば、 Hello\nWorld という文字列を value にセットした場合、 output パラメータ(次のコードの場合は greeting )には Hello だけがセットされるということになります:

run: |
name=greeting
value="Hello\nWorld"
echo "::set-output name=greeting::${value}"
shell: bash
id: my_command
# => `steps.my_command.outputs.greeting` には `Hello` だけが含まれる

関連イシューなど:

対応方法

複数行の文字列を output にセットするための方法としていくつかの選択肢があります。

  • 方法 A) エスケープしてから出力する
  • 方法 B) output のかわりに環境変数を使う
  • 方法 C) @actions/corecore.setOutput() を使う

後述しますが、私はシンプルな C) のアプローチを選びました。

方法 A) エスケープしてから出力する

標準出力に出力する前に value 内に含まれる改行文字などをエスケープします。

Bash スクリプトの場合は次のような処理を行うことになります:

value="${value//'%'/'%25'}"
value="${value//$'\n'/'%0A'}"
value="${value//$'\r'/'%0D'}"

参考:

方法 B) output のかわりに環境変数を使う

set-output による output パラメータのセットは行わず、かわりに環境変数を使うという手もあります。 環境変数のセットには $GITHUB_ENV を使用します。 このときヒアドキュメント風の書き方をすれば変数に複数行の文字列をセットできます。

次のサンプルでは、改行文字を含みうる curl コマンドの出力を JSON_RESPONSE という環境変数にセットしています( GitHub 公式ドキュメントのサンプルです):

steps:
- name: Set the value in bash
id: step_one
run: |
echo 'JSON_RESPONSE<<EOF' >> $GITHUB_ENV
curl https://example.lab >> $GITHUB_ENV
echo 'EOF' >> $GITHUB_ENV

参考:

方法 C) @actions/corecore.setOutput() を使う

NPM パッケージ @actions/corecore.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@v6
with:
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 にセットする」というパターンは頻出な気がするので、そのためのかんたんなカスタムアクションを作りました:


アバター
後藤隼人 ( ごとうはやと )GitHubPython

ウェブ制作・開発やマーケティング、プロジェクト支援などをしています。

© 2022 gotohayato.com
サイトについてタグアーカイブ
メッセージを送る