その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

GitHub Actionsで複数のworkflowを連携する時にハマったあれこれ

GitHub Actionsで或るworkflowが終わったら別のworkflowを動かす、みたいなことをやりたくなった時にちまちまハマったのでメモとして残します。

workflow_run で呼び出されたworkflowで前workflowのステータスを取る

これはハマったことというか「こうやれば良い」という話なんですが、

on:
  workflow_run:
    workflows:
      - check
    types:
      - completed

jobs:
  ...

みたいに書いておくと check workflowが完了した時にこのworkflowが呼び出されるのですが、この時 check の成否は関係無く呼び出されます。
従って、check が完了した時にのみ実行したい時には以下のようにステータスチェックを入れる必要があります。

on:
  workflow_run:
    workflows:
      - check
    types:
      - completed

jobs:
  do_something:
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    steps:
      ...

ref: Events that trigger workflows - GitHub Docs

それはそうとして completed typeだけじゃなくて succeededfailed みたいなtypeを workflow_run で指定できると嬉しいような気はするのですが......

workflow_run はdefault branchに存在していないと動かない

Events that trigger workflows - GitHub Docs

Note: This event will only trigger a workflow run if the workflow file is on the default branch.

公式ドキュメントにめっちゃ目立つように書いてある!!
workflowを整備するブランチで作業してて「おかしいな〜動かないな〜」と思っていたらこういう話だったというオチ。default branchに workflow_run を使うworkflowをpushしておかなければ駄目。

workflow_run で呼び出されるworkflow中では github.ref_type は常に branch になる

1つ前の話題にも通ずるところですが、

Events that trigger workflows - GitHub Docs

このドキュメントにもあるように `GITHUB_REF` はdefault branchとなっているため github.ref_type は常に branch となります。

on:
  workflow_run:
    workflows:
      - check
    types:
      - completed

jobs:
  do_something:
    if: ${{ github.ref_type == 'tag' }}
    steps:
      ...

上のように書いていると、仮に元のworkflow (この場合は check) がtagのpushによってトリガーされていたとしても github.ref_typebranch となるため絶対に do_something は実行されません。これはちょっとハマった......

workflow_call で呼び出されたworkflowからはrepositoryに登録されているsecretsを直接参照できない
on:
  workflow_call:

jobs:
  do_something:
    runs-on: "ubuntu-latest"
    steps:
    - env:
        PASSWORD: ${{ secrets.PASSWORD }}
      run: |
        echo ${{ env.PASSWORD }}
  ...

今度は workflow_run ではなく workflow_call の話題。なぜなら workflow_run では「tagがpushされた時だけなんかやる」が実現できなかったため......
workflow_call により、他のworkflowから明示的に呼び出されたworkflowはrepositoryに登録されているsecretsを直接参照することができないため、上記のechoは何も表示しません。

on:
  workflow_call:
    secrets:
      PASSWORD:
        required: true

jobs:
  do_something:
    runs-on: "ubuntu-latest"
    steps:
    - env:
        PASSWORD: ${{ secrets.PASSWORD }}
      run: |
        echo ${{ env.PASSWORD }}
  ...

上記のように workflow_call.secrets で受け取る変数を明示しておいて、

  call-workflow:
    uses: ./.github/workflows/next.yml
    secrets:
      PASSWORD: ${{ secrets.PASSWORD }}

のような感じで呼び元のworkflowから適切に渡してあげる必要があります。

ref: Reusing workflows - GitHub Enterprise Cloud Docs




というわけで、これらを総合した「tagがpushされ、なおかつ元のworkflow (この場合は check job) が成功した時にrepoに登録されたsecretsを渡しながら別のworkflowを呼び出す」という定義を書きたい時は元のworkflowでは

on:
  push:
jobs:
  check:
    ...
  call-workflow:
    needs: [check]
    if: ${{ github.ref_type == 'tag' }}
    uses: ./.github/workflows/next.yml
    secrets:
      PASSWORD: ${{ secrets.PASSWORD }}

と書いておきつつ、呼ばれるworkflowでは

on:
  workflow_call:
    secrets:
      PASSWORD:
        required: true

jobs:
  do_something:
    ...

というふうに書いておけば目的を満足できることがわかりました。これがやりたかった......