GitHubActionsでプルリクについたコメントを取得しワークフローを分岐させる

CIの実行結果をGitHubのプルリクに対してコメントとしてつけると便利です。 CIを走らせるたびに新しいコメントを追記されると大量のコメントが出てきて邪魔なので、marocchino/sticky-pull-request-commentを用いてコメントをアップデートしています。

github.com

やんごとなき理由ですでにコメントされているか、されていないかをもとに分岐したい処理が発生したため特定の文字列を含むコメントがあるかを調べるGitHubActionsのStepを作成しました。

作成

自分がコメントの追加、更新に使用している marocchino/sticky-pull-request-comment はコメントの管理のためにコメントアウトした形で制御用のHeaderをつけます。 <!-- Sticky Pull Request Comment'${HEADER}' -->がHeaderとして加えられた文字列です。

この文字列を含むコメントがあるか調べるステップを追加します。 まずは実際に作成したGitHubActionsファイルを示します。

name: Comment Exist
on: push

jobs:
  CreateComment:
    name: createComment
    runs-on: ubuntu-20.04
    steps:
      - name: Create Comment Hoge
        uses: marocchino/sticky-pull-request-comment@v1
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          header: Hoge
          message: 'Hoge'

      - name: Check Comment Exist
        id: comment_exist
        env:
          HEADER: Hoge
        run: |
          PR_NUM=$(echo ${{ github.ref }} | sed -e 's/[^0-9]//g')
          COMMENT_LISTS=$(curl --request GET \
            --url https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUM/comments \
            --header 'authorization: token ${{ secrets.GITHUB_TOKEN }}' \
            --header 'content-type: application/json' \
            --header 'Accept: application/vnd.github.v3+json')
          EXTRACT=$(echo -E $COMMENT_LISTS \
            | jq -r '.[] | select(.body | contains("<!-- Sticky Pull Request Comment'${HEADER}' -->"))')
          if [ -z "$EXTRACT" ]; then
            echo ::set-output name=exist::false
          else
            echo ::set-output name=exist::true
          fi

      - name: Test
        if: steps.comment_exist.outputs.exist == 'true'
        run: |
          echo 'YES!'

解説

GitHubAPIを叩いてプルリクについているコメントを一覧で取得、ほしいコメント文字列が含まれているかを調べることで実現しています。

PR_NUM=$(echo ${{ github.ref }} | sed -e 's/[^0-9]//g')で現在のプルリク番号を取得します。 github.refはワークフローを実行するホスト上にデフォルトで設定されている変数でトリガーとなったブランチやタグが記録されます。 プルリクをトリガーにした場合プルリク番号は直接入っておらず、refs/pull/2/mergeのような形のためsedコマンドで変換する必要があります。

プルリク番号を取得することでプルリクに紐づくコメントを取得するAPIを利用できます。 GitHubActionsからの実行ならばトークンはデフォルトでsecretsに登録されているためそのまま利用できます。 ローカルからcurlする際には設定からトークンを発行しましょう。

curl --request GET \
    --url https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUM/comments \
    --header 'authorization: token ${{ secrets.GITHUB_TOKEN }}' \
    --header 'content-type: application/json' \
    --header 'Accept: application/vnd.github.v3+json'

docs.github.com

取得したコメント一覧のJsonからbodyに目的の文字列が含まれるか調べます。 jq -r '.[] | select(.body | contains("<検索対象文字列>"))' とすることでBodyに目的の文字列が含まれているJsonが抽出できます。 このJsonが空か空でないかをもとにecho ::set-output name=exist::trueで出力を作成し、 別のステップで出力結果をもとに分岐させます。

正常に動作しているかコメントの存在を確認するステップを増やして確認しました。

まとめ

GitHubActionsかなりいろいろなことができて便利です。 もっといいやり方あるよ〜等あればコメントいただけると幸いです。

この記事がどなたかの開発効率の向上につながったら嬉しいです。