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

GitHub Actions でプルリクエストの自動アサインをする

これは ゆめみ Advent Calendar 2019 の10日目の投稿です。

皆さんはもう GitHub Actions を使っていますでしょうか?便利ですよね。

CI(継続的インテグレーション)でテストしたりビルドしたりするのに利用することが多いかと思いますが、GitHub 上の作業を自動化するのにも使えたりします。

今回は、プルリクエストを作成したら自動で AssigneesReviewers を設定するワークフローを紹介します。
(毎回これらが決まりきっている場合、プルリクエストを作る毎に設定するのは面倒ですよね。)

参考

Assignees の自動設定

assignees は基本的には当該プルリクエストの対応(レビューの対応)をする人になると思うので、プルリクエストを作成した本人とします。
ワークフローの設定は次のようになります。

.github/workflows/assign-auto.yml
name: Assign auto

on:
  pull_request:
    types: opened # プルリクを作成したタイミングだけで動かす

jobs:
  assign:
    name: Set assignees
    runs-on: ubuntu-18.04
    steps:
      - name: Set assignees
        env:
          ASSIGNEES: "${{ github.actor }}" # 変えたければここを変える
        run: |
          assignee_count=$(cat ${{ github.event_path }} | jq '.pull_request.assignees | length')
          if [[ 0 == $assignee_count ]]; then
            assignees=$(echo "\"${ASSIGNEES// /}\"" | jq 'split(",")')
            curl -X POST \
                 -H "Content-Type: application/json" \
                 -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
                 -d "{ \"assignees\": $assignees }" \
                 https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/assignees
          fi

${{ github.XXX }} は公式ドキュメントを見てもらえば分かりますが、GitHub 上の情報(今回はプルリクエスト)を参照する構文です。勘違いしやすいのですが、環境変数ではありません。「実行前に静的に文字列置換される」という感覚が近いです。${{ secrets.GITHUB_TOKEN }} も標準で利用できる構文で、GitHub API アクセス用のトークンに置き換えられます。

assignee_count はプルリク作成と同時に設定された assignees の数です。これがゼロの場合に curl コマンドで GitHub API を叩いて assignees を設定します。

assignees=$(echo "\"${ASSIGNEES// /}\"" | jq 'split(",")') の箇所が少し分かりづらいので補足します。仮に環境変数 ASSIGNEES に設定されたアカウントが hoge, fuga とすると、

  1. ${ASSIGNEES// /} でスペースを削除 .. hoge,fura
  2. "\"${ASSIGNEES// /}\"" でダブルクォートを付加しJSONの文字列とする(後続のjqコマンドで扱えるようにする) .. "hoge,fuga"
  3. jq 'split(",")'jqコマンドにより文字列をJSONの配列にする .. [ "hoge", "fuga" ]

といったことをしています。

Reviewers の自動設定

ワークフローの設定は次のようになります。

.github/workflows/assign-auto.yml
name: Assign auto

on:
  pull_request:
    types: opened

jobs:
  assign:
    name: Set reviewers
    runs-on: ubuntu-18.04
    steps:
      - name: Set reviewers
        env:
          REVIEWERS: "hoge, fuga, piyo" # edit here
        run: |
          reviewer_count=$(cat ${{ github.event_path }} | jq '.pull_request.requested_reviewers | length')
          if [[ 0 == $reviewer_count ]]; then
            reviewers=$(echo "\"${REVIEWERS// /}\"" | jq 'split(",") | .-["${{ github.actor }}"]')
            curl -X POST \
                 -H "Content-Type: application/json" \
                 -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
                 -d "{ \"reviewers\": $reviewers }" \
                 https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/requested_reviewers
          fi

assignee の設定とあまり変わらないので説明は割愛しますが、プルリクを作成した本人は reviewers から除外している(レビュアに設定する必要がないし、GitHub API でもエラーになる)ことだけ注意です。

まとめると

上記2つのワークフローをまとめると次のようになります。

.github/workflows/assign-auto.yml
name: Assign auto

on:
  pull_request:
    types: opened

jobs:
  assign:
    name: Set assignees and reviewers
    runs-on: ubuntu-18.04
    steps:
      - name: Set assignees
        env:
          ASSIGNEES: "${{ github.actor }}"
        run: |
          assignee_count=$(cat ${{ github.event_path }} | jq '.pull_request.assignees | length')
          if [[ 0 == $assignee_count ]]; then
            assignees=$(echo "\"${ASSIGNEES// /}\"" | jq 'split(",")')
            curl -X POST \
                 -H "Content-Type: application/json" \
                 -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
                 -d "{ \"assignees\": $assignees }" \
                 https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}/assignees
          fi
      - name: Set reviewers
        env:
          REVIEWERS: "hoge, fuga, piyo" # edit here
        run: |
          reviewer_count=$(cat ${{ github.event_path }} | jq '.pull_request.requested_reviewers | length')
          if [[ 0 == $reviewer_count ]]; then
            reviewers=$(echo "\"${REVIEWERS// /}\"" | jq 'split(",") | .-["${{ github.actor }}"]')
            curl -X POST \
                 -H "Content-Type: application/json" \
                 -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \
                 -d "{ \"reviewers\": $reviewers }" \
                 https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/requested_reviewers
          fi

もしブランチ毎に reviewers が異なる、という場合は、ワークフローの実行条件のところでブランチを指定するか(yamlファイルはブランチ分用意する)、

on:
  pull_request:
    branch:
      - master

もしくは steps 内で

- name: Set reviewers
  if: github.base_ref == 'master'
- name: Set reviewers
  if: startsWith(github.base_ref, 'develop') # 前方一致

のようにして各ステップを実行するか否かを制御すればいいでしょう。

今回は固定メンバーを全員 reviewrs として設定していますが、スクリプトを工夫すればランダムに選択して設定、等もできると思います。

おわりに

いかがだったでしょうか。もし他に良い利用事例があれば、紹介いただけると幸いです。
それではよい GitHub Actions ライフを!

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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした