その手の平は尻もつかめるさ

ギジュツ的な事をメーンで書く予定です

GitHub Webhooksのpushイベントで重複しているcommitを判別したい

TL;DR

commitオブジェクトに生えているdistinctプロパティを見れば良い.
distinctが0の場合,それは重複しているcommitであることが分かる.
Ref; https://developer.github.com/v3/activity/events/types/#payload-18

本編

さて,GitHubのWebhooksのpushイベントを受け取って,それをIRCや他のチャットツール等にフォワードしたくなるようなことがままあると思います.

これをナイーブに実装しようとすると,pushイベントを受け取って,そのpayloadに乗ってくるcommitsをベロっと舐めてフォワードするような感じになるでしょう.
つまり,

2ac1745 commit3
26cecfa commit2
8ee5552 commit1

というcommit郡がpushされると,これらのcommitの情報がフォワードされるという感じですね.


で,例えばこの場合のpush先がfeatureブランチだったとして,そのfeatureブランチをmasterブランチにmergeするとどうなるかというと,webhookのpushイベントが発火して,merge commitと共に*1 上記のcommitsの情報が再びpayloadに乗ってやって来ることとなります.
このpayloadの情報をすべてフォワードすると,既にフォワードされた内容が再びフォワードされてしまうことになるので具合が悪いことがあります.


これをどう解決するかというと,冒頭に書いたとおりcommitのオブジェクトに生えているdistinctプロパティを見れば良くて,このプロパティが0の時は重複しているcommit (雑な言い方をすると,過去に1度でもpushイベントのpayloadに乗ったことのあるcommit) で,1の時は重複していないcommitであるということが分かります.
従って,既にフォワードした内容を再度フォワードしたくない場合は,distinctが1のcommitだけをフォワードすれば良いという事になります.
(Perlのコード例で恐縮ですが,つまりこんな感じです: https://github.com/moznion/App-GitHubWebhooks2Ikachan/blob/621e7ddef9d0d05a1396a8325a436f74de17e30a/lib/App/GitHubWebhooks2Ikachan/Events/Push.pm#L15)


かつてはHead Commitのcommit logを見て,「“Merge”から始まるcommitだから,これはmerge commit!」みたいな野蛮な方法で重複commitの判別を涙ぐましく行なっていたわけですが (しかもこの方法だとFast-Forwardの場合に対応できない!),distinctを見ればそんな無駄な努力をする必要はありませんでしたよ,という話でした.

*1:Fast-Forwardの時はmerge commitは無いでしょうが