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

PerlでGitHub webhookを受けるbotを作ってみた話

こちらはPerl Advent Calendar 2020の20日目の記事になります。
昨日は、utgwkkさんによる、現状の癖を反映した .perltidyrc でした。

今年も軽い気持ちでPerl Advent Calendarに投稿してみようと思ったのですが、
何か流行り物をやってみようと思いつつ例によって前日までネタが浮かばなかったので、
以前作成したGitHub のwebhookを受けるbotを若干作り直してみたので紹介してみることにしました。

何を作ったのか?

https://github.com/teckl/p5-GitHub-Webhook-Bot

こういうやつです。

GitHubのwebhookイベントに応じて、Slack, Chatworkにクロスポストする感じのbotになります。

GitHub webhook botを作った経緯

弊社ではGitHub Enterpriseを使っているのですが、
プルリクエスト時のレビュー依頼やissueでのやり取りなどを円滑にするために3年前くらいにbotによる運用で楽がしたいということになりました。

例えばGitHubとSlackを連携させるのは、普通であれば
GitHub と Slack を連携させる
SlackとGitHubを連携してissueコメントやプルリク通知をチャンネルに流す方法(2020年版)

↑この公式のSlack 用 GitHub アプリを使う方法が一番初めに浮かぶと思います。

が、ある深遠な理由により、当時はChatworkをメインにしており、Slackのbotなどを使うことが出来ませんでした。。

また、公式のSlack 用 GitHub アプリだと、GitHubのイベントをチャットに流すことは出来ますが、
複数のリポジトリ・複数のチャンネルが入れ乱れている場合は流量が大量になり、
いちいち流れを追うのも非効率ということもありました。
自分に関係あるissue, PullRequestだけを見逃さないようにしたいというのがあり、
公式botとかでもそういった事はできなさそうだったのでPerlで作ってみることにしました。

やりたかったこと

@記法

@記法でコールされた人や、issueやPRにアサインされている人だけにメンション(TO)を飛ばしたい。
(皆様のところではissue時のコメントや、プルリクエスト時のレビュー依頼などはどうされているのでしょうか…?)

リポジトリとチャンネル毎に出し分けしたい

リポジトリ単位で、関係のある案件ごとのチャンネルだけにwebhookを流したいと考えました。

コード記法

調査した際のログやスニペットなどを気軽にissueなどに貼りたいが、チャットログがあまり汚れないようにしたい

画像付きLGTMしたい

当時流行っていた 仕事にあそびごころを、LGTMコメントに使いたいGif画像 みたいな、
LGTM画像を貼ってワイワイしたい。

Slackにも移れるようにしておきたい

深遠な理由が状況によって変わる可能性もあったため、場合によってChatworkからSlackに移動しても同じように使えるようにしておきたいと思っていました。


Chatwork 特有の事情

Chatwork絵文字のタグが独特

これはPerl使いにとってなかなか辛い感じで、
:D -> 😄 になってしまうのを防ぐために置換リストを用意するなどしました。
https://github.com/teckl/p5-GitHub-Webhook-Bot/blob/main/etc/chatwork_emoticon_list.txt

LGTM画像の実装

Slackしか使ってない方はご存知ないと思いますので説明させていただきますと、
当時のChatworkでは画像URLなどを貼ってもプレビュー(インライン展開)してくれず、人力で画像をアップロードするしか方法がありませんでした。
無いのであれば、Perlの得意分野である正規表現を使って、画像URLっぽいものを抜いてきて、
自前で別途チャンネルにアップロードするような感じにしました。
https://github.com/teckl/p5-GitHub-Webhook-Bot/blob/main/lib/GitHub/Webhook/Bot/Web.pm#L200

(※この機能はChatwork公式で今年春から使えるようになったようです…!:「リンクプレビュー」機能をリリースしました!


というわけでその後

このbotを作ってから、いい感じにChatworkで運用して平和に暮らしていたのですが、
その後深遠な理由が無くなり、ChatworkからSlackに移行する事になりました。
当時Slackになっても使えるようにということで中身空っぽのSlack用分岐だけを用意していましたが、
中身をちょろっと書き換えてSlack移行ができました。
(ベタベタな分岐が汚いものの)Chatwork専用のロジックはせっかくなのでそのまま残しております。

今もChatworkとGitHubを使われている方は普通に使えるのではないかと思いますので、
もしよろしければお試しいただけるとありがたいです。。


技術的な事

ウェブアプリケーションフレームワーク:Kossy

今回初めて試してみましたが、使用しているフレームワークはkazeburoさんのKossyになります。
https://github.com/kazeburo/Kossy
sinatra風のとても軽量なWAFで、今回のような単機能のWEBアプリを作るにはとてもいい感じです。

作った当時、Kossyが使われているisucon 6のアプリをいろいろと参考にさせていただきました。。
https://github.com/isucon/isucon6-final/tree/master/webapp/perl

Githubのwebhookについて

GitHubのwebhookについては、
GithubのHookについてのまとめとソリューション | おそらくはそれさえも平凡な日々
がとても参考になりました。
こちらの記事をもとに肉付けした感じのが今回のbotになります。

webhookのバリデーションについては、
GithubのWebhookのバリデーションとPlack::Middleware::HubSignature
Plack::Middleware::HubSignature を利用させていただいています。

webhookのテスト環境について

ペイロードを受信するようサーバーを設定する - GitHub Docs
↑のGitHub公式ページに書いてありますが、このwebhookをテストするには ngrok を使うのが超便利でした。
外部のリクエストを受ける環境で毎回デプロイとかするのは面倒だったりするので、テスト中はローカルのアプリケーションをngrokで一時的に公開すると楽にデバッグできました。

yamlの読み込み

もともとはjsonで作っていたのですが、人間が手動で編集するにはケツカンマ問題などが辛かったので今回yamlに変更しました。

環境変数の読み込み

ハードコードしちゃってましたが、 .env を使って読み込むようにしてみました。


感想

今回、Perlネタを考えるにあたってネタが無かったのもありますが、
このまま社内に埋もれさせるのももったいなと思ってこの機会に公開できるようにしてみました。。

特にLGTM画像のあたりなど、不便だからこそ、なんとかして頑張ってみよう、的なモチベーションになったのを覚えています。
正直なところ、元からSlackを使っていたらわざわざこれを作るようなモチベーションは出なかっただろうなぁ、と今になって思ったりもしますが、いい勉強になりました。

明日は、kolukuさんによる Perlでズンドコ問題を短くしてみる - koluku's blog です!

teckl
好きなものは、 Perl🐫, ゆるキャン🏕, Ingress, Pokémon GO, らーめん🍜, ダイエット🐷, モバイル💻, TK, globe, TM Network, 稲川淳二, 忌野清志郎, Fishmans, 斉藤和義, フジファブリック, etc(そういうところではないという噂も)
https://twitter.com/teckl
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