LoginSignup
20
7

More than 1 year has passed since last update.

GitHub Actions の Workflow 内でグローバル変数を使う(RUN 間の変数渡し・共有)

Last updated at Posted at 2020-10-05

2022/10/11 この記事で紹介している set-output は廃止(deprecated)されることが決定し、近々使えなくなることがアナウンスされました。

本来、set-output は「アクション毎の環境変数」を保持し、どのアクションが設定したのか明確にするためのものでした。しかし、ユーザーが知らない間にアクション間で意図しない値をやりとりされる可能性もあったことから、GITHUB_OUTPUT に変数定義を追記する形に統一するそうです。

before
- name: Save state
  run: echo "::save-state name={name}::{value}"

- name: Set output
  run: echo "::set-output name={name}::{value}"
after
- name: Save state
  run: echo "{name}={value}" >> $GITHUB_STATE

- name: Set output
  run: echo "{name}={value}" >> $GITHUB_OUTPUT

run 内でグローバル変数をセットして他の run で使いまわしたい

GitHub Actions の Workflow で、env ではなく、異なる run ステップ間で変数を共有したい。

変数がrunステップ間で引き継がれない例
name: Sample Workflow

on:
  pull_request:

jobs:
  sample_job:
    runs-on: ubuntu-latest
    steps:
      - name: Step1
        run: |
          FOO='bar'
          echo "The FOO is ${FOO}"
          : # 結果: The FOO is bar
      - name: Step2
        run: |
          echo "The FOO is ${FOO}"
          : # 結果: The FOO is
          : # $FOO は引き継がれない

TL; DR (今北産業)

  1. 別ステップへの変数渡しには大きく 2 種類がある。

    1. ワークフロー全体の「環境変数」経由:
      • GITHUB_ENV に変数を追加セット(追記)する
    2. 各々のステップの「公開変数」経由:
      • ::set-output でセットされた変数
  2. ワークフロー全体の「環境変数」渡しの場合:

    • GITHUB_ENV に追記する。
      • Set: run: echo "<name>=<value>" >> $GITHUB_ENV
      • Get: ${{ env.<name> }}
    • 一番楽。
      • 後日、汎用化する可能性が「ない」場合に使う。他と変数名がバッティング(重複)する可能性があるため。
        アクション化やコピペピピックな使い方など、汎用的に利用する可能性がある場合は、env への書き込みは推奨されない。どのアクションで設定された値か、ユーザがトレースしにくくなるため。その場合、env 値は参照のみに限定して、次項の「ステップのグローバル変数」を使う。
  3. 各々のステップの「公開変数」渡しの場合:

    • 一番安全(変数名がバッティングしないため再利用性が高い)
    • run::set-output を使う。
      1. ステップ内で id を宣言する。(ステップ ID の設定)
      2. 同ステップの run 内で「::set-output」と「変数」を echo して値を設定する。
      3. 他のステップで id を参照すると同じ値が使える。
    idの構文
    id: <ステップ ID>
    
    set-outputの構文(パラメーター)
    ::set-output name=<変数名>::<値>
    
    呼び出し時の構文
    ${{ steps.[設定した時点のステップID].outputs.[設定した変数名] }}
    
    設定例(変数MY_VALUEに"fuga"がセットされる。ステップIDは"hoge")
    - name: Step1
      id: hoge
      run: echo '::set-output name=MY_VALUE::fuga'
    
    呼び出し例(ステップID"hoge"の変数MY_VALUEを取得。ステップのnameが違うことに注目)
    - name: Step2
      # $value1 には 'fuga' が入る
      run: value1=${{ steps.hoge.outputs.MY_VALUE }}
    
    使用例
    ...
         - name: Step1 Set FOO
           run: |
               hoge='bar'
               echo "::set-output name=FOO::${hoge}"
           id: step-foo
         - name: Step2 Get FOO
           # 結果: The FOO is bar
           run: echo 'The FOO is' ${{ steps.step-foo.outputs.FOO }}
    ...
    

TS; DR RUN の変数を理解するまでのコマケーこと)

Workflow の run ステップで定義された変数は、たとえ export しても続く他の run ステップでは使えません。Docker の RUN ディレクティブ(指示子)と似た動きをします。

確かに、env を使えば環境変数として定義できます。つまり、どの run ステップでも使える変数を設定できます。

あらかじめわかっている値なら環境変数が良い
name: Sample Workflow

on:
  pull_request:

env:
  HOGE_FUGA: Piyo

jobs:
  sample_job:
    runs-on: ubuntu-latest
    env:
      FOO_BAR: Buzz
    steps:
      - name: Step1
        run: |
          echo "The HOGE is ${{ env.HOGE_FUGA }}"
          : # Output: The HOGE is Piyo
      - name: Step2
        run: |
          echo "The FOO is ${{ env.FOO_BAR }}"
          : # Output: The FOO is Buzz

しかし、このパターンで env 文を使う場合、あらかじめわかっている値しか代入できません。例えば「ステップの中で日付をセットしたい」といったことができません。

実は、この env 文は、環境変数の GITHUB_ENV に追記する役割があります。

GITHUB_ENV は「シェル配列」となっており、1 行 1 変数定義で構成されています。

そのため、以下の様に変数定義を改行付きで GITHUB_ENV に(>> で)追加すると、各ステップで取得した情報をセットして利用できます。

あらかじめわかっている値なら環境変数がらく
name: Sample Workflow

on:
  pull_request:

jobs:
  sample_job:
    runs-on: ubuntu-latest
    steps:
      - name: Step1
        run: |
          echo "HOGE_FUGA=Piyo" >> $GITHUB_ENV
          : # 改行付き echo であることに注目
      - name: Step2
        run: |
          echo "The HOGE is ${{ env.HOGE_FUGA }}"
          : # Output: The HOGE is Piyo

通常は、これが一番楽な設定です。

しかし、どのステップでも書き換えることができるため、逆に言えば「どのステップで追加・編集・削除されたか」も不透明になります。

そのワークフローを見れば一目瞭然なのですが、ワークフローを同じリポジトリ内の別のワークフローで再利用する場合や、アクションとして公開する場合に、追跡するのが大変になります。

「特定のステップで作成された変数が使いたい」と調べたところ、下記のように公式ドキュメントに記載がありました。

You can use the set-output command in your workflow to set the same value:

sample.yaml
     - name: Set selected color
       run: echo '::set-output name=SELECTED_COLOR::green'
       id: random-color-generator
     - name: Get color
       run: echo 'The selected color is' ${steps.random-color-generator.outputs.SELECTED_COLOR}

Using workflow commands to access toolkit functions | Workflow commands for GitHub Actions @ GitHub Docs より)

【筆者訳】
run ステップ内で set-output コマンドを使うと、同じ値を他のステップでも使えるようになります。

sample.yaml
     - name: Set Foo
       run: |
           hoge='bar'
           echo "::set-output name=FOO::${hoge}"
       id: step-foo
     - name: Get Foo
       # 結果: The FOO is bar
       run: echo 'The FOO is' ${{ steps.step-foo.outputs.FOO }}

※ 筆者注) 上記の訳の YAML はわかりやすいように変更、および原文の YAML の typo を修正しています。

実は、この原文には typo があるようで ${steps.random....COLOR} では動かず、 ${{ steps.random....COLOR }} と二重の ${{ ... }}(カギ括弧)で囲う必要があります。

GitHub Actions で実行した日付を取得する

echo + ::set-output key=value:: の仕組みを応用すると日付も取得できます。イメージ作成やビルドなどには便利ではないでしょうか。

Dockerのイメージ作成時の"--build-arg"オプションで、TAG_BUILDの値に日付を渡す例
      - name: Get current date (YYMMDD)
        id: date
        run: echo "::set-output name=today::$(date +'%Y%m%d')"

      ...

      - name: Build and push Docker image
        uses: docker/build-push-action@v2
        with:
          context: .
          push: true
          tags: |
            keinos/helloworld:latest
          build-args: |
            TAG_BUILD=Build: ${{ steps.date.outputs.today }})

参考文献

20
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
7