アクトインディ開発者ブログ

子供とお出かけ情報「いこーよ」を運営する、アクトインディ株式会社の開発者ブログです

Github workflow の実行をラベルで制御する

あけましておめでとうございます。morishitaです。
世間はコロナで大変な状況ですが、早くいこーよでお出かけ先を探して思う存分遊びに行けるようになればいいのになぁと思いながら新年を迎えました。本年もよろしくおねがいします。

さて、今回は小ネタを1つ。

以前、Pronto を Github Action で実行するというエントリを投稿しました。

tech.actindi.net

アクトインディの開発では Github のプルリクエスト上で Pronto を実行して、Rubocop によるチェックを行い、違反があれば次のようにコメントで指摘されるというワークフローを使っています。

f:id:HeRo:20210107191837p:plain
指摘コメント

プルリクエストに Push するたびに実行され便利なのですが、毎回の Push で実行されると不便な場合もあります。

例えば次のようなケースです。

  • 違反があるのはわかっていて、後でまとめて修正しようと思ってたのに Push したら指摘コメントがたくさんついてしまった
  • UI の微調整で修正しては細かく Push して、たくさん実行してしまい無駄に Github Action の無料枠を食いつぶしてしまう。
    (いこーよは作業ブランチ毎にステージング環境が作成され、Push すると自動的にデプロイされます。ディレクターチェックで UI の仕上がりをステージングで確認しながら修正していくときに起こりがちです)

実行したいときに実行を指示する方法としてはコマンドコメントを使う方法があります。
例えば、Dependabot が作ったプルリクエストに @dependabot rebase とコメントすると Rebase するようなやつですね。同じようにワークフローも制御できそうなのですが、これだとどんなコマンドがあるか覚える必要があったり、タイピングが若干面倒です。

で、アクトインディでは特定のラベルの有無によって実行を制御しています。
具体的には Pronto というラベルを付けているときだけ実行されるようにProntoを実行するワークフローを使っています。

Github workflow のトリガーイベント

ワークフローには実行トリガーとなるイベントを定義する必要があります。 いろんなイベントがありますが1、プルリクエスト上での操作をトリガーにしたい場合には、pull_request イベントを使います。
そして、pull_request イベントにはいくつかのアクションが定義され、どんな操作でトリガーされるのか指定できるようになっています2

例えば、次のように定義するとプルリクエストを作ったときと、Push したとき、ラベルを付けたときにトリガーされます。

name: Pronto
on:
  pull_request:
    types: [opened, synchronize, labeled]
jobs:
  pronto:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v1
      - uses: HeRoMo/pronto-action@v1.10.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

で、これだと Push するたびに実行されてしまいますし、どんなラベルをつけたときにも実行されてしまいます。

コンテキストと式

さて、ここからが本エントリの本題です。

ワークフローの実行を制御する方法はトリガーイベントだけではありません。
イベントの中身を見て、実行するかどうかを判定できるコンテキストと式があります。

コンテキストとはワークフローの実行、ランナーの環境、ジョブ、ステップに関する情報にアクセスできるオブジェクトです。
いくつかの種類のコンテキストがあるのですが、その中で、github コンテキストにはトリガーしたイベントの詳細情報が入っています。

pull_request イベントの場合、github.eventに Webhook の pull_request イベントのペイロードと同等の情報が含まれています。

github.event の中にはどんなラベルを付けたのか? あるいはどんなラベルが付いているのか? という情報が含まれているのでそれらを使って実行を制御できます。
更に、コンテキストとリテラル、演算子を組み合わせて式を作ることもできます。

例えば、次の条件を満たす場合のみ実行したいとします。

  • プルリクエストに Pronto というラベルを付けたとき
  • Pronto というラベルがついている状態で、 Push したとき

これは次のように if 条件に式を与えることで実現できます。

name: Pronto
on:
  pull_request:
    types: [opened, synchronize, labeled]
jobs:
  pronto:
    runs-on: ubuntu-latest
    # ↓ 追加
    if: |
      ((github.event.action == 'labeled') && 
        (github.event.label.name == 'Pronto')) ||
      ((github.event.action == 'synchronize') &&
        contains(github.event.pull_request.labels.*.name, 'Pronto')
    # ↑ 追加
    steps:
      - uses: actions/checkout@v1
      - uses: HeRoMo/pronto-action@v1.10.0
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}

もう少し説明すると if 条件の中で使っている contains はワークフロー内で使えるよう定義されている関数です。第一引数で渡された文字列や配列の中に、第二引数の文字列が含まれれば true となります。
第一引数の github.event.pull_request.labels.*.name というのは github コンテキストからプルリクエストについたラベル名を配列で取り出す指定となります。

こうすることで、ラベルの付与やラベルの有無によりワークフローの実行を制御できました。

まとめ

  • Github ワークフローをトリガーするイベントについて説明しました。
  • イベントの情報を取得できるコンテキストについて紹介しました。
  • 具体例として特定のラベルの有無でワークフローの実行を制御する例を紹介しました。

ワークフローには他にもコンテキストや関数がありますし、ワークフローコマンドなんてものもあったりするので工夫次第で使い方が広がると思います。

参考

最後に

アクトインディではエンジニアを募集しています。 actindi.net