GitHub Actionsで変数を間接参照したい

こんにちは。サービスグループの武田です。GitHub Actionsで変数を定義し、それを間接参照する方法を調べました。
2022.04.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。サービスグループの武田です。

GitHub Actionsでは変数を定義し、それをワークフローの中で利用できます。それでは、たとえば環境名に対応した変数を定義し、それをワークフローの引数の値によって使い分けることは可能でしょうか。

例として次のようなワークフローを考えてみます。

name: test

on:
  workflow_dispatch:
    inputs:
      env:
        type: choice
        options:
          - dev
          - prod

env:
  name_dev: scott
  name_prod: tiger

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: output test
        run: |
          echo ${{ github.event.inputs.env }}
          # ここでenvがdevならscott、prodならtigerを表示させたい

実行時の引数としてenvを指定します。今回はdevprodから選べるようにしました。次に環境変数としてname_devname_prodを定義しています。どちらもnameとして使いたい変数ですが、環境によって値が異なるというシチュエーションです。最後に、ステップの中でその変数を利用します。${{ github.event.inputs.env }}はワークフローの入力値を参照する記法です。さて、その次の行で変数の間接参照をしたいんだ、というわけです。

単純な参照であれば、${{ env.name_dev }}などと書けばOKです。もちろん${{ env.name_${{ github.event.inputs.env }} }}なんてのは書けません。ここで思い出してほしいのは、GitHub Actionsでは プロパティ参照外しの構文インデックス構文 をサポートしていることです。次の2つの書き方は同値です。

  • ${{ env.name_dev }}
  • ${{ env['name_dev'] }}

そのため、参照したい名前を文字列として組み立てられれば間接参照も可能となります。調べてみたところ、GitHub Actionsでは文字列をつなげる+concatなどはありませんでした。代わりにformat関数があり、これを使えば実現できそうです。結果として次のような定義になりました。

name: test

on:
  workflow_dispatch:
    inputs:
      env:
        type: choice
        options:
          - dev
          - prod

env:
  name_dev: scott
  name_prod: tiger

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - name: output test
        run: |
          echo ${{ github.event.inputs.env }}
          echo ${{ env[format('name_{0}', github.event.inputs.env)] }}

実行結果

さきほどのワークフローを実行した結果です。うまくいきました。

devを指定。

prodを指定。

まとめ

GitHub ActionsではEnvironmentsという機能があり、これを使うことで環境ごとに異なるシークレットを定義できたりします。しかしそれが使用できない場合であったり、そこまでの規模ではないケースなどはちょっと便利になるでしょう。

補足

今回は間接参照で環境によって異なる変数を使用しましたが、次のような三項演算的な方法でも実現できます。分岐が少ない場合は、この書き方も有用でしょう。

    steps:
      - name: output test
        run: |
          echo ${{ github.event.inputs.env }}
          echo ${{ github.event.inputs.env == 'prod' && env.name_prod || env.name_dev }}

参考URL