GAS と Slack App でデータ集計用のボットを作りました

こんにちは!株式会社Hajimariの新卒エンジニアの濵田です。

今年の4月に新卒として入社致しました。 普段はGraspyの開発業務を行う傍ら

最近は会社のHPの管理を行ったりしています。 今回はGASとSlack Appで作った「360度レビューくん」がどう動いているのかを紹介します。

※このbotはエンジニアチームの中で走っている施策「360˚ソースコードレビュー」で使うために作成しました。 上記の施策に関しては責任者をされているエンジニアの先輩が解説してくださったこちらの記事でかなり詳しく解説されているのでぜひご一読ください。

bot の概要

slack の特定のチャンネルに配置しておき、メンションをつけてGitHubのプルリクのURLを送ると プルリクについた会話(conversation)を数えてシートに記録します。 また、メンションつけて「データをみたい」とメッセージを送信すると集計された内容が チャンネルに投稿されます。

f:id:hajimari_hamada:20200715092206j:plain 上記の写真ではプルリクのURLをbotにメンションつけて送る事で集計してもらっているシーンです。

今回はこのbotがどのようにして集計して、シートに記録・チャンネルに返信しているのか、ついて書いていきます。

全体的なbotの構成

Botが動く流れとしては以下の通りです。

① Slack でbotにメンションつけてイベント発生 => GASのAPI叩く ② GAS側では届いたURLを元にGitHub API を叩いて会話(今後コメントと表記)を取得。処理してシートに書き出し、レスポンスを返す。 ③ 戻ってきたレスポンスにあるメッセージをbotがチャンネルに投稿する

こちらのbotはGASプログラム(スプレッドシート)、Slack App(bot)を使って動いています。 それぞれ具体的にどのようになっているのか見ていきます。

GAS (スプレッドシート)

GASのプログラムは主に以下のような項目のコードで動いています。

  1. slack との最初の連携をする部分
  2. GitHub API を叩く
  3. 計算処理
  4. シートに書き込む
  5. Slack チャンネルにメッセージを送信

以下で順番に見ていきます。

1. slack との最初の連携をする部分

f:id:hajimari_hamada:20200714155903p:plain
GAS に来たデータを取得する部分です

上記写真の①では、このGASのプログラムに来たデータを取得しています。 後述するSlack 側の設定をしておくと、postData.event.text でメンションつけて送信したメッセージの内容が来ています。 今回は別箇所にプルリクURLだけ切り出す関数を用意してURLのみ使っていますが、 受け取ったメッセージはお好きなようにご利用ください。

そして②では、Slack側から来たデータが、認証用のリクエストだった場合に返してあげる内容を書いています。 このコードでSlack 側の期待したレスポンスが返ってくるかのチェックを通ることができます。 この記事を参考に(というかそのまま)用意しました。

Slack App の設定の部分で改めて説明します。

2. GitHub API を叩く

f:id:hajimari_hamada:20200714155214p:plain
GitHubAPI を叩いてレスポンスを返すメソッドです

このメソッドはGitHubAPIを叩くメソッドで、書いてる通りではあるのですが、 引数に来た GitHub API の url を叩いてレスポンスを返してくれるメソッドです。

今回はGitHubのプルリクについた会話を集計したいので、 引数に入ってくる apiUrl には

https://api.github.com/repos/ { レポジトリ名 }/pulls/{ プルリクの数値(#XXXXみたいに表示されてるやつ) }/comments が入ってきます。

また、今回は会社のレポジトリのプルリク情報を取得しているのでトークンをheaders に指定しています。

PropertiesService.getScriptProperties().getProperty('GITHUB_TOKEN')

上記に関して少し触れておくと、GASには今回のようなトークンなど、ベタ書きは避けたい情報を設定する時 別に置いておける場所があり、それをプロパティストアといいます。

そしてそこに置いておいた情報にアクセスしたりするGASの機能の事をプロパティサービス(ProperiiesService)といい、 上記のコードでは、それを使って予め保管しておいたGitHubトークンを呼び出しています。

今回は飛んできたプルリクURLをこのメソッドで使えるAPIURLに変換する部分の解説は割愛します。

3. 計算処理

f:id:hajimari_hamada:20200714162009p:plain
そのプルリクにどのメンバーがどれだけコメントしたかを計算するメソッド

上記のメソッドは、そのプルリクについたコメント数をカウントするいくつかのメソッドの中の一つです。 ここではコメントの通り、そのプルリクについたコメントを自分以外の誰が何回したかを算出しています。

引数について解説すると、このGASのプログラムではそもそもエンジニアチームメンバー全員の GitHubの名前とSlack のメンバーID を50音順で配列にして管理しています。 ここではGitHubの名前の配列を受け取っています。

また reviews は上記のGitHub API を叩いた戻りを受け取っています。 reviews にはそのプルリクについた全てのコメントが入っており、それぞれのコメントオブジェクトのuser.loginに入っています。 そして第3引数のuserGithubNameには、このプルリクをチャンネルで共有したメンバーのGitHub 上の名前を受け取っています。

上記のメソッドはそのプルリクに自分以外の人がどれだけコメントしているのかを集計しようとしていますが これらのGitHub の名前を使ってそれを実現しています。

ちなみに reviewCounts は配列で(名前どうにかするべきかも)、後々シートにデータを入れる際の事を考慮して用意しています。 それ専用のメソッドを読んで先にメンバー分の中身が入った配列を用意しています。

4. シートに書き込む

f:id:hajimari_hamada:20200714164605p:plain
今回書き込むシートを取得しています

f:id:hajimari_hamada:20200714164408p:plain
上記のメソッドを使って他のメンバーからもらったコメント数を使ってシートに書いています

1枚目の写真のように SpreadsheetAppクラスのopenByIdメソッドを使って操作したいシートを取得します。 openByIdメソッドではその名の通り、スプレッドシートのIDを渡してやる必要があるのですが、 今回も、先ほど出てきたようにプロパティサービスで、プロパティストアで管理してあるシートIDを取得して渡しています。

2枚目の写真では、 先ほど取得したシートの中で操作の対象にしたい範囲をgetRangeメソッドで指定したいます。(変数 pullRequestInfoRange)

また、シート上の書き込みたいセルを取得するために getCell メソッドを使ってそれぞれ具体的に書き込むセルの絞り込みまでしています。(変数 ~~Cell)

実際にこのプルリクで他のメンバーからもらったコメントの合計を取得するために 先ほどgiveCommentCount関数で集計して戻ってきた各メンバーのコメント数が入った配列をgiveCommentCountSum関数に渡しています。 こうして用意したもらったコメントの合計をothersCommentCellにsetValueメソッドで書き込んでいます。

5. Slack チャンネルにメッセージを送信

f:id:hajimari_hamada:20200714165751p:plain
メッセージ送信用関数の一部

f:id:hajimari_hamada:20200714170029p:plain
処理の結果で返すメッセージを切り替えている部分

最後に処理の結果を知らせるメッセージを対象のSlackチャンネルに返します。 とりあえず、sendMessageという受け取ったメッセージを返す関数を用意し、 処理の結果毎に異なったメッセージを返すようそれぞれのパターンに対してsendMessageを使う関数を用意しています。 2枚目の写真は実際にtry ~ catch でどのメッセージを返す関数を使うか切り分けている部分です。

Slack にメッセージを送るために必要な設定は後ほど説明しますが、 送信したいチャンネルにメッセージを送ることができるURLをまたプロパティサービスで取得しています。

ここまでがGAS で行われている処理の一連の流れです。

Slack App

1. slack app を作成

このページの画面上部のCreate New Appを押す。 名前と入れるworkspace を選ぶダイアログが表示されるので、それぞれ入力し次に進むとひとまずは作成できます。

アイコンや名前等の基本的は情報の設定はお好きにどうぞ。

2. bot の設定
  1. Incoming Webhook を設定

GASプログラムからbotを通じてチャンネルにメッセージを送るためにはIncoming Webhook を設定する必要があります。 Features/Incoming Webhook を選択し、Activate Incoming Webhooks を On にします。

f:id:hajimari_hamada:20200714175356p:plain
Features/Incoming Webhook の選択画面下部

f:id:hajimari_hamada:20200714175842p:plain
Add New Webhook to Workspace 押下後この画面に

そして、画面下部(上記の1枚目の写真)のAdd New Webhook to Workspace を押すと2枚目の写真の画面に遷移します。 追加したい チャンネルを選択し進むと、画面が戻りURLが発行されている事がわかります。

f:id:hajimari_hamada:20200714175903p:plain
追加された専用URL

このURLをGASのプロパティストアに設定して、上記のsendMessage 部分でプロパティサービスを使って取得して使っています。

  1. Event Subscriptions の設定

f:id:hajimari_hamada:20200714180027p:plain
Features/Event Subscriptions をOn にしています

Incoming Webhook と同じように Event Subscriptions の設定も On にします。 Request URL の部分にAPI公開されているGASのプログラムのURLを入力してテストします。 上で用意した通りにしていれば問題なく設定されます。

f:id:hajimari_hamada:20200714180129p:plain
ここでbotに関するイベントを設定することができます

そしてこの写真の部分で、bot に関係するイベントの設定ができます。 今回はbotにメンションをつけるイベントが発生すると、上で設定したURL(GAS)にデータを飛ばしてやりたいので app_mension を選択します。

以上で、今回botを用意したチャンネルでbotにメンションをつけた状態でプルリクのURLをメッセージとして送信すると、 GAS側で飛んできたURLを受け取り・集計しシートに反映・返信までできる部分をそれぞれ解説しました。

具体的にどういう計算をしたりや、どう言った文言(URL等)が来たら処理を行うのかはお好みでカスタマイズしてみてください。

ボットに関しては以上です。

また、僕の開発している Graspy は若手で活躍されている優秀な方々がキャリアアップできるようなプラットフォームを目指して日々成長しておりますので、ぜひ一度ご覧になってみてください(求人も沢山あります!)

graspy.jp

株式会社Hajimariでは、自社開発・受託開発を行っています。
一緒にLaravelやVue.jsを使って開発してくれるエンジニア・デザイナーを絶賛募集しています!

新卒・中途どちらも募集しておりますので、興味のある方は以下の記事をぜひ御覧ください!
みなさまとお会いできるのを心からお待ちしております。

www.wantedly.com

www.wantedly.com