Help us understand the problem. What is going on with this article?

GitHub Actionsの複数Jobで構成されるWorkflowの正しい結論を知る方法

GitHub Actionsで複数Jobが動くWorkflowがあったとして、この最終的な結論を知る方法について調べてみた。

そもそもどうして複数Jobが動くWorkflowの結論が知りたいのかというと、例えば次のようにBuild->Test->Pulibshのようにシリアルに実行されるJobで構成されるWorkflowがあったとして、最後にその成功・失敗いづれかの結果をSlackで通知したかったから。なお、通知の際は、成功・失敗のステータスを区別する必要があった。

Build Job => Test Job => Publish Job => Slack通知 (成功・失敗いづれも通知)

ダメだった例

まずはダメだった例を紹介する。下記のようにJob群(build、test、publish)と、always()とneedsを使って、それらJob群の結果を取得するJob(slack_notification)を用意した。 下記の、slack_notificationのように、needsでその前のJobとの依存関係を設定した上で、Job実行条件にalways()を指定することで、その前のJob群がどこかでfailしてスキップされたとしても必ずslack_notificationは実行されるようになる。 ただし、結論からいうと、これは要件を満たさない。slack_notificationの前のJobが成功・失敗関係なく、得られるjob.statusは必ずsuccessjob.statusとは現在実行中のJobのステータスであるためsuccessとなる。当たり前の話だった。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: exit 0
  test:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - run: exit 1
  publish:
    runs-on: ubuntu-latest
    needs: test
    steps:
      - run: exit 0

  slack_notification:
    if: always()
    needs: publish
    runs-on: ubuntu-latest
    steps:
      - run: |
          echo "let's see the workflow conclusion"
          echo ${{ job.status }}

このWorkflowの実行結果は下記の通りで、test Jobで失敗しているにも関わらず、slack_notification Jobではステータスをjob.statusから取得しているためsuccessと表示されてしまっている。

ng-case.png

方法1: GitHub API v3 Workflow Jobを使う

GitHub API v3のWorkflow Job APIは、全てのJobの実行結果をconclusionとして返却してくれる。このAPIを上記のslack_notificationでたたけば、そのWorkflowにおいて、それまでのJobの実行結果が成功なのか失敗なのか一覧取得でき、そこから最終結果を判断することが可能となる。

https://developer.github.com/v3/actions/workflow-jobs/

方法2: Workflow Conclusion Actionを使う

方法1で紹介したGitHub API v3のWorkflow Job APIを内部で利用して、Workflow内のJobの結果を全て取得し、その最終結果を環境変数(WORKFLOW_CONCLUSION)に入れてくれる便利なActionがある。それが、workflow-conclusion-action。正しいJob群の最終結果が得られるので、上記の要件は満たせるわけです。上記のサンプルをworkflow-conclusion-actionをつかって変更すると次のようになる。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: exit 0
  test:
    runs-on: ubuntu-latest
    needs: build
    steps:
      - run: exit 1
  publish:
    runs-on: ubuntu-latest
    needs: test
    steps:
      - run: exit 0

  slack_notification:
    if: always()
    needs: publish
    runs-on: ubuntu-latest
    steps:
      - uses: technote-space/workflow-conclusion-action@v1
      - run: |
          echo "let's see the workflow conclusion"
          echo ${{ env.WORKFLOW_CONCLUSION }}

このWorkflowの実行結果は下記の通り。今度はslack_notification Jobで、ステータスが無事successと表示された 🎉🎉🎉

ok-case.png

まとめると、基本的に、方法1も2もGitHub v3 API Workflow Jobを利用したアプローチ。APIの仕様に準じてパラメータを組み立て、結果をパースすることが苦ではない人は方法1、楽をしたい人は方法2を選択ください。

最後に、slack_notification Jobの中身を、目的のslack通知の内容に書き換えると次のようになる

  slack-notification:
    if: always()
    needs:  publish
    runs-on: ubuntu-latest
    steps:
      - uses: technote-space/workflow-conclusion-action@v1
      - name: Slack Notification
        uses: sonots/slack-notice-action@v3
        with:
          title: My deployment
          status: ${{ env.WORKFLOW_CONCLUSION }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          SLACK_WEBHOOK_URL: ${{ secrets.MY_GITHUB_CHANNEL_WEBHOOK }}

本記事で紹介したサンプルコード
- https://gist.github.com/yokawasa/b3e4c49c66ba9069f3904163ecf841d6

zozotech
70億人のファッションを技術の力で変えていく
https://tech.zozo.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away