Renovateが作成したPRを楽にチケット管理する

# 概要
私たちの環境では[Renovate](https://docs.renovatebot.com/)を利用して、パッケージのアップデートを検知してPRを自動作成することで、最新バージョンに追従しやすい状態を維持しています。詳細は[Techblog](https://techblog.zozo.com/entry/update-versions-with-renovate)をご確認ください。

運用する中でちょっとした課題となったのは、アップデート対応をタスクとして管理しづらいということです。私たちはスクラムを模したチーム運営の形を取っており、スプリント内で対応可能なタスクの上限をチケットに付与するストーリーポイント（以下、spとします）から判断しています。この運用の場合、積み上がったRenovateのバージョンアップ対応がチケット化されないことでspとして計上されず、sp外労働（※造語です）を強いられることになります。

そのくらい手動でチケットを作ればいいじゃない、という声も聞こえてきそうですが、似たようなチケットを繰り返し作成するのは人によっては苦痛な作業なので、自動化することに決めました。


# 自動化について

まず、自動化の概要から説明します。

## 自動化の概要

今回の自動化の大まかな流れは以下の図の通りです。

![RenovateのPR生成時にClickupのチケット作成を自動化する.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/22d240fd-90af-a4e1-90b9-b59844ec8d8b.png)

自動化で利用したツールはGithub ActionsとZapierです。
当環境では、タスク管理ツールとしてClickupを利用していますが、Zapierに対応していれば他のものでも適用可能な記事内容になっているかと思います。

## 各ステップについて

次に上記の図に沿って各ステップの詳細について説明します。

### 1. RenovateによるPR作成

この項目については基本的なRenovateの利用方法しか書くことがなく、今回の趣旨から外れるので割愛します。
詳細を知りたい方は再掲となりますが、[Techblog](https://techblog.zozo.com/entry/update-versions-with-renovate)をご確認ください。一点補足すると、後のZapierのフィルター条件に使うため、[labelsプロパティ](https://docs.renovatebot.com/configuration-options/#labels) を利用してPRにラベルを付与しています。

### 2. Github Actionsによるアサイン

続いて、Github Actionsを用いてPRにAsigneesを設定します。アップデート作業が特定の個人に偏らないようにGithub Teamに所属するメンバーからランダムでアサインをしています。これは後にタスク管理ツールのチケットにアサインを設定するための情報としても利用します。

尚、RenovateにもPRに[Asigneesを設定する機能](https://docs.renovatebot.com/configuration-options/#assignees)はありますが、Github Userを個別に設定できるもののTeamは対応していない（[Issue](https://github.com/renovatebot/renovate/issues/7368)を見ると今後も対応されなさそう？）ので、Github Actionsでカバーしています。

メンバーを個別にrenovate.jsonに設定する形だとメンバーの増減に対応しづらく、複数リポジトリを管理しているとより大変になってしまいますが、Teamを設定しておけば一元管理できるので楽になります。

### 3. Github WebhookによるPRイベントの送信

今回はGithubのイベントをトリガーにチケットを作成するツールとして[Zapier](https://zapier.com/)を利用しますが、Githubと連携する際、Zapierの基本機能では一つのZap（ワークフローのこと）につき、単一のリポジトリしか対象にできません。

以下はZapierでGithubに新しくPRが作成された場合をトリガーとした場合の設定画面ですが、ラジオボタンになっており複数の選択はできません。

![image2023-9-1_16-0-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/c24bfe68-da94-1eef-d115-63f6842db6e5.png)

リポジトリの数に応じたZapを個別に作れば回避できなくはないですが、その場合は管理コストが高くなります。
これの回避策として、Github Webhooksと[Webhooks by Zapier](https://help.zapier.com/hc/en-us/articles/8496288690317-Trigger-Zaps-from-webhooks#limitations-0-0)の機能を組み合わせることで、複数のリポジトリのイベントを一つのZapに向けて発火することで要件を満たせると考えました。

注意点として、Webhooks by ZapierはPlemium Appsという位置付けのため、Professional以上のプランでないと利用制限があります。
cf. https://zapier.com/pricing

Webhooks by Zapierをトリガーに設定するとWebhook URLが発行されるので、これをGithub Webhookの`Payload URL`に設定します。 `Which events would you like to trigger this webhook?`には`Pull Requests`だけチェックをしておけばokです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/ebaea1f5-987f-3012-160c-c8a66be962b5.png)

### 4. Clickupにチケットを作成

ここまで来れば、あとはWebhookから受け付けた内容をもとにチケットを作成するだけなのですが、次の考慮点があったので紹介させていただきます。

- Github User名からタスク管理ツールのアカウント名への変換
- 重複したチケットの作成の防止

#### Github User名からタスク管理ツールのアカウント名への変換

前述の通り、インプットとして受け付ける情報はPRのAssigneesに設定されたGithub User名なのですが、タスク管理ツールでは別のアカウント名で設定されていることが多いと思います。私たちの環境ではメールアドレスでアカウントが作成されているので、チケットにアサインするための変換処理が必要になります。
これを実現するためにZapierの[Tables](https://zapier.com/blog/zapier-tables-guide/)という機能を用いました。これはRDBのようにデータをレコードとして保存し、クエリ操作のように検索して値を返せる機能です。これを利用してGithub User名とEmailをレコードとして登録します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/f1642fcb-6982-e322-4847-f1907ade5130.png)

取得時は以下のようなステップを追加します。これによりGithub User名からメールアドレスを取得できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316261/0d26bf15-238c-9bdb-ca55-94971e4d2c66.png)


#### 重複したチケットの作成の防止

先ほど、Github Webhooksの`Pull Requests`を送信対象のイベントとして指定しているとご説明しましたが、これは文字通りPull Requestsに関連するイベントが全てZapierに送信されます。このイベントにはopened、closed、synchronizeといった複数のアクティビティに細分化されます。
cf. https://docs.github.com/ja/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#pull_request

今回の対象はアサインが設定されたタイミングなのでassignedを指定したのですが、業務負担を考慮して別のメンバーに作業をお願いするケースで、アサインを付け替えると重複してチケットが作られてしまいます。これは混乱のもとになりうるのでなんとかしたいという気持ちが運用する中で高まっていきました。

これについての対処にも先ほどのTablesを利用しました。処理済みのPRのURLをテーブルに登録し、すでにテーブルにレコードが存在していたら処理をスキップします。
また、PRのクローズ時のイベントをキャッチしてテーブルからレコードを削除しています。クローズ時のイベント処理はチケット作成とは別のZapとして管理しています。

# さいごに

以上がRenovateから作成されたPRをチケット管理するためにやった自動化作業の例になります。
Zapierはノーコードツールならではの楽さもありつつカスタマイズ性にも優れているので、使ってみたはいいものの実現できなくて詰むような事態には今のところ陥っていないので気に入っています。