GitHub ActionsでWorkFlowやJobを連鎖させる方法

はじめに

この記事は、GitHub Actionsでjobやworkflow同士を連鎖させる方法を記録、共有するためのものです。

想定する環境

この記事は、2021/11/12時点でのGitHubを前提に書かれています。GitHubが更新されると、記事の内容をそのまま適用できないことがあります。ご注意ください。

想定する読者

  • gitを使ったことがある
  • GitHubのアカウントを持っている
  • GitHub Actionsを使ったことがある

この記事ではgitの使い方やGitHubの導入方法などは取り扱いません。ご承知ください。

GitHub Actionsとは

GitHub Actionsとは、GitHubが提供するCI/CD環境です。リポジトリへのPushやPull requestの作成、Issueへのコメントなどさまざまなイベントを引き金としてコンテナーが立ち上がり、指定された命令を処理します。

利用ケースとして

  • Pull requestが作成されたら、テストを実行し合否を判定する
  • デフォルトブランチが更新されたら、APIドキュメントを生成しGitHub Pagesで公開する
  • Issueが作成されたら、内容にしたがって特定のラベルをつける
  • 一定期間Issueに活動がなかったら、IssueをCloseする

などがあります。

ワークフロー

GitHub Actionsのアクションは、以下のような粒度で管理されています。(公式ドキュメント)

ステップ

アクションの最小単位です。シェルコマンド1行に相当します。

ジョブ

複数のステップで構成された処理です。ジョブ同士は並列処理されます。

ワークフロー

複数のジョブで構成され、イベントを引き金として実行される処理の塊です。1つのワークフローは1つのYAMLファイルに記述されます。

ワークフローファイルは.github/workflowsというディレクトリに保存され、このファイル自体もgitでバージョン管理されます。

ワークフローファイルの肥大化

複雑なワークフローを構成すると、ワークフローファイルが肥大化して管理が難しくなっていきます。そのためジョブを分割したり、相互に関連しないジョブを別々のワークフローに切り分けなければいけません。

処理の連鎖

GitHub Actionsには、ワークフローやジョブの分割のための連鎖機能があります。この連鎖機能を使えば「テストが成功し、デフォルトブランチにマージされたら、APIドキュメントを更新してGitHub Pagesで公開し、npmでパッケージを公開する」といった複雑な処理を管理しやすくなります。

GitHub Actionsでは、依存ジョブとworkflow_runトリガーの2種類の連鎖機能が提供されています。

ジョブの連鎖 : 依存ジョブ

GitHub Actionsのジョブはデフォルトでは並列で実行されます。依存ジョブにneedsフィールドを設定すると、指定した他ジョブの完了を待ちます。

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: ./build_server.sh
  test:
    needs: build
    ^^^^^^^^^^^^ ここが依存ジョブの設定
    runs-on: ubuntu-latest
    steps:
      - run: ./test_server.sh

上記の例ではbuildジョブが成功したら、testジョブが実行されます。buildジョブが失敗したらtestジョブは実行されずに中断されます。

依存ジョブは並列実行されないため、ワークフロー全体の処理時間は長くなります。後続の処理が中断される利点と、処理時間が長くなる欠点を比べて設定してください。

ワークフローの連鎖 : workflow_runトリガー

workflow_runトリガーを使うと、前ワークフローの完了を引き金に次のワークフローが開始されます。

on:
  workflow_run:
    workflows: ["Run Tests"]
    branches: [main]
    types:
      - completed

上記の例ではRun Testsという名前のワークフローが、mainブランチで完了したときに処理が始まります。

なお、workflow_runトリガー単体では、前ワークフローの処理が成功したか失敗したかをチェックできません。前ワークフローが成功したか否かを確認するにはコンテキストgithub.event.workflow_runを確認します。このコンテキストには前ワークフローの情報が格納されています。

on:
  workflow_run:
    workflows: ["Build"]
    types: [completed]

jobs:
  on-success:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}
    steps:
      ...

たとえばgithub.event.workflow_run.conclusionには前ワークフローの成否が格納されています。

処理を分割することで、再利用しやすく可読性の高いワークフローを作れます。お手元の環境で複雑すぎるワークフローがある場合、ぜひ分割を検討してみてください。 以上、ありがとうございました。