2017年7月からGMOアドマーケティングのSSP開発チームにJoinしたKA.Mです。
先日、試用期間も無事終え落ち着きました。
GMOアドパートナーズグループには、住宅補助手当という
オフィスビル近隣に住んでいる人が対象となる福利厚生があるので、
そろそろオフィスビル近くに引越かと考えています。
早速本題です。
Webhookってなに?
Webhookとは特定の条件を満たした際に他のアプリケーション/URLへリクエストする仕組みとなります。
SSP開発チームでは今回紹介するGitHubの他にSlackのWebhookも活用しています。
活用事例
SSP開発チームはGitHubのレビュー機能を利用したGitHubフローで開発しています。
Pull Request = レビュー依頼ではないため、レビュー依頼はラベル機能を利用していますが、
レビューNGとなった場合、主に3つ問題がありました。
- Pull Requestの一覧上のレビュー結果が見辛い
- ラベルが放置され、レビュー依頼中なのか、修正中なのかの判断がつかない
- ラベルが放置されガチだったため、”[WIP]”とタイトルに付けるPRが散見された
上記のような問題を抱えていたため、
GitHubのWebhookを利用し、レビュー結果を元にラベルの張替を実現しました。
ラベル張替をWebhookに任せる事で、以下のメリットがありました。
- ラベルがついていない = 開発/修正中
- ラベルがついている = レビュー依頼中/レビュー完了
- “[WIP]”が消えました
実装コード例
Webhook設定
去年の10月に追加されたPullRequestReviewEventを利用します。
まず、GitHub側のWebhook設定を行います。
Webhookを適用したいリポジトリのページから Settings > Webhooks
と遷移し、 Add webhook
から新規にWebhookを追加します。
今回は Let me select individual events.
を選択し、 Pull request review
のみにチェックを入れます。
Access Token取得
ラベル張替用のAccess Tokenを生成します。
アカウント情報の Settings > Developer settings > Personal access tokens
にアクセスし、 Generate new token
から新規にトークンを発行します。
利用しているリポジトリに応じ public_repo
か repo
にチェックを入れます。
リクエスト先の設定例
SSP開発チームではPHP、JavaScript、Ruby、Goで開発を行っていますが、
今回はPHPでの実装例となります。
GitHubのdeveloperガイドに記載ありますが、GitHubからみたPull Requestはissueと大差ありません。
1 2 3 4 |
Every pull request is an issue, but not every issue is a pull request. For this reason, "shared" actions for both features, like manipulating assignees, labels and milestones, are provided within the Issues API. |
Labels, assignees, and milestones
その事を踏まえた上で、下記実装を行いました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 |
<?php $secret = '**** Webhookに登録したSecret情報 ****'; $accessToken = '**** Access Token情報 ****'; $useragent = '**** 任意のUA ****'; $commonCurlSetoptArray = [ CURLOPT_RETURNTRANSFER => true, CURLOPT_HEADER => false, CURLOPT_HTTPHEADER => [ "Authorization: token {$accessToken}", 'Content-type: application/json', ], CURLOPT_USERAGENT => $useragent, ]; $removeLabl = '**** 剥がすラベル(ex: review) ****'; $addLabel = '**** 付けるラベル(ex: LGTM) ****'; $header = getallheaders(); $postJson = file_get_contents('php://input'); $hmac = hash_hmac('sha1', $postJson, $secret); if (isset($header['X-Hub-Signature']) && $header['X-Hub-Signature'] === "sha1={$hmac}") { $postArray = json_decode($postJson, true); try { // PRに紐付いているラベルの情報を取得しています。設定されていないラベルを削除、 // 既に設定されているラベルを再度設定するとエラーとなります。 // https://developer.github.com/v3/issues/labels/#list-labels-on-an-issue $ch = curl_init("{$postArray['pull_request']['issue_url']}/labels"); curl_setopt_array($ch, $commonCurlSetoptArray); $body = curl_exec($ch); $info = curl_getinfo($ch); curl_close($ch); if ($info['http_code'] !== 200) { throw new RuntimeException($body, $info['http_code']); } $existsLabelArray = json_decode($body, true); // PRに紐付いているラベル情報を元にラベルの削除を行っています。 // また、ラベルの設定済みかどうかの判定も行っています。 // https://developer.github.com/v3/issues/labels/#remove-a-label-from-an-issue $existsAddLabel = false; foreach ($existsLabelArray as $existsLabelRow) { if ($existsLabelRow['name'] === $removeLabl) { $ch = curl_init("{$postArray['pull_request']['issue_url']}/labels/" . urlencode($removeLabl)); curl_setopt_array($ch, $commonCurlSetoptArray + [ CURLOPT_CUSTOMREQUEST => 'DELETE', ]); $body = curl_exec($ch); $info = curl_getinfo($ch); curl_close($ch); if ($info['http_code'] !== 200) { throw new RuntimeException($body, $info['http_code']); } } elseif ($existsLabelRow['name'] === $addLabel) { $existsAddLabel = true; } } // ラベルが設定されていない場合にはラベルを設定します。 // https://developer.github.com/v3/issues/labels/#add-labels-to-an-issue if (!$existsAddLabel && 'approved' === $postArray['review']['state']) { $ch = curl_init("{$postArray['pull_request']['issue_url']}/labels"); curl_setopt_array($ch, $commonCurlSetoptArray + [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => json_encode([ $addLabel, ]), ]); $body = curl_exec($ch); $info = curl_getinfo($ch); curl_close($ch); if ($info['http_code'] !== 200) { throw new RuntimeException($body, $info['http_code']); } } } catch (RuntimeException $re) { } catch (Exception $e) { } } |
まとめ
ラベルの張替は対応時間としては微々たるものですが、日々の業務で開発者全員にちょっとした気遣いを強いるものでした。
そのちょっとした気遣いを自動化する事で意識せずに済むようになったためチーム内で好評でした。
リクルーティング
GMOアドマーケティングではBigQuery、機械学習など新しい技術に興味のあるエンジニアに限らず、
開発効率の向上に積極的なエンジニアを募集しています。