みーのぺーじ

みーが趣味でやっているPCやソフトウェアについて.Python, Javascript, Processing, Unityなど.

GitHub Actionsでブランチ毎のSecretsを取得する

おそらくGitHub Actions Environmentsで簡単に実現できることだと思うのですが,privateレポジトリでは使えないので,少し工夫してブランチ毎のSecretsを取得できるようにしました.

要件

testブランチのpushイベントで起動したら,VAL_TESTという名前のsecretを取得し,masterブランチで起動したら,VAL_MASTERという名前のsecretを取得する.

GitHub Actionsのenvの制限が辛い

ブランチの名前を取得するには,${{ github.ref }} が使えますが,"refs/heads/test"のような形式になるため直接は使えません.

また,以下に記載されているコンテキストを使用しなければなりません.

GitHub Actions のコンテキストおよび式の構文 - GitHub Docs

コンテキストはシェルスクリプトのような柔軟さはなく,かなり制限があります.加算ができない,split関数がない,三項演算子が使えない.辛いですね.以下のstackoverflowの質問を見るだけで,苦労している人がいることが分かります.

Dynamically retrieve GitHub Actions secret - Stack Overflow

ブランチ毎に処理を変えるコンテキスト

format(), contains(), &&, ||が使えるので,少し工夫すればブランチの名前に従った任意の文字列を取得することができます.

以下の例では,testブランチならば"TEST"を,masterブランチならば"MASTER"を,いずれでもなければ"INVALID"を返します.

${{ (contains(github.ref, 'test') && 'TEST') || (contains(github.ref, 'master') && 'MASTER') || 'INVALID' }}

あとはformat()を使用して,secretの名前を生成します.まとめると,以下のようになります.

name: Test
on:
  push
  
env:
  REF: ${{ github.ref }}
  A: ${{ format('VAL_{0}', (contains(github.ref, 'test') && 'TEST') || (contains(github.ref, 'master') && 'MASTER') || 'INVALID') }}

jobs:
  check-values:
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo REF=${REF}
          echo A=${A}
          echo ${{ secrets[env.A] }}
          echo "${{ secrets[env.A] }}" | tr "[:upper:]" "[:lower:]"

これをtestブランチより実行すると,以下のようになりました.

REF=refs/heads/test
A=VAL_TEST
***
this is val_test.

同じコードを,masterブランチより実行すると,以下のようになりました.

REF=refs/heads/master
A=VAL_MASTER
***
this is val_master.

これで,ブランチ毎にsecretが変わり,ブランチ毎の複数の環境を実現することができます.

なお,上記の例ではtrコマンドを使って,secretが隠されるのを回避しています.

envの場所

envは場所により範囲が異なります.先頭に記載したenvは,ワークフロー中のすべてのジョブのステップから利用できます.それに対して,jobやstepに記載したenvはその範囲でしか有効になりません.

ブランチ毎に動作を変えるには,ワークフロー全体で使用できるほうが便利なので,先頭に記載しました.

また,envの中では,同じenvで宣言した変数は使用できないので,先頭のenvではsecretの名前を代入し,secretが必要となる各場所で${{ secrets[env.A] }}のように参照するのが実用的だと思われます.