Perl Hackers Hub

第67回GitHub APIによるチーム開発の効率化 ―基本操作から、GitHub Webhooksの活用まで(2)

前回の(1)こちらから。

GitHub WebhooksによるSlackとの連携

前回の(1)まではPerlスクリプト単体でGitHub APIを実行する例でしたが、応用編として、GitHubが提供しているGitHub Webhooksを利用してSlackと連携するサンプルアプリケーションを紹介します。

GitHubを活用した開発ワークフロー

Pull Requestやissueなどの通知について、公式のSlack用GitHubアプリケーションを利用するなどして、Slackとの連携を行っているケースがあると思います。また、GitHub Actionsを利用できる環境であれば、GitHub MarketplaceにあるSlack連携などのツールを組み合わせて、任意のワークフローを構築することもできるでしょう。

しかし、GitHub Enterpriseのバージョンの問題でGitHub Actionsを利用できない環境や、既存のツールだけでは実現できない込み入った処理を自分で作成したい場合もあるでしょう。GitHub Webhooksは、そのような場合に活躍します。

GitHub Webhooksの設定

GitHub Webhooksは、GitHubリポジトリへの各種操作(コミットのPush、Pull Requestの作成、issueの作成など)を受けた際に、外部のWebサーバへイベントの通知を行うしくみです。このWebhookとGitHub APIを組み合わせることによって、Webhookの通知を受けたタイミングでSlackに通知したり、任意のリポジトリ操作を行ったりすることができます。

Webhookの設定方法については、公式ドキュメントを参照してください。

Webhookを受信するアプリケーションの作成

では、Webhookを受信するWebアプリケーションを作成しましょう。前回のPull Requestのレビュアーをランダムに設定する処理を組み込んだWebアプリケーションを作成します。

PerlとSlackの連携には、WebService::Slack::WebApiモジュールを用います[1]⁠。Webアプリケーションフレームワークには、Mojolicious::Liteを用います[2]⁠。

前回の例ではチーム内のメンバーを取得していましたが、今回はチームが存在しない場合の例として、リポジトリのコラボレータからランダムに1人を抽出するように変更します。また、レビュアーがアサインされた直後のタイミングでSlackにその旨を通知します。

use Mojolicious::Lite -signatures;
use JSON;
use Pithub;
use WebService::Slack::WebApi;

my $slack_token = 'my_slack_token_xxxxxxxx';
my $github_token = 'my_github_token_xxxxxxx';
# 連携したいSlackのチャンネルID
my $slack_channel_id = 'XXXXXXXX';
my $pit = Pithub->new(token => $github_token);

post '/:payload' => sub ($c) {
    # トリガしたイベント名
    my $method =
      $c->req->headers->header('X-GitHub-Event');
    # ペイロード(イベントデータ本体のJSON)
    my $payload = eval { decode_json $c->req->body };
    # イベントをトリガした際のアクション
    my $action = $payload->{action};

    # Pull Requestイベント受信時
    if ($method eq 'pull_request') {
        # Pull Request作成時にレビュアーが未設定の場合
        if ($action eq 'opened'
          && !$payload->{requested_reviewers}) {
            update_random_reviewer($payload);
        }
        # レビュアーが設定された場合
        if ($action eq 'review_requested') {
          # アサインされたユーザーをSlackに通知
          post_slack($payload->{requested_reviewer}
            ->{login} . " さんがアサインされました。\n"
            . $payload->{pull_request}->{html_url});
        }
    }

    # レビューコメント受信時
    if ($method eq 'pull_request_review_comment') {
        if ($action =~ /created|edited/) {
            # レビューコメントをSlackに通知
            post_slack($payload->{comment}->{body}
            . "\n" . $payload->{comment}->{html_url});
        }
    }

    $c->render(json => {success => 1});
};

sub update_random_reviewer {
    my $payload = shift;
    my $random_user = random_collaborator($payload);
    my $pull = $payload->{pull_request};

    # GitHub APIで取得したコラボレータをレビュアーに設定
    $pit->repos->pull_requests->reviewers->update(
        repo      => $pull->{base}->{repo}->{name},
        user      => $pull->{base}->{user}->{login},
        data      => { reviewers => [$random_user] },
        pull_request_id => $pull->{number},
    )->response;
}

sub random_collaborator {
    my $payload = shift;

    my $pull = $payload->{pull_request};
    # GitHub APIでリポジトリのコラボレータ一覧を取得
    my $res = $pit->repos->collaborators->list(
        user => $pull->{base}->{user}->{login},
        repo => $pull->{base}->{repo}->{name},
    )->response;
    my $json = decode_json($res->content);
    my @users = ();
    for my $user (@{$json}) {
        # Pull Request作成者以外を対象にする
        if ($user->{login} ne $pull->{user}->{login}) {
            push @users, $user->{login};
        }
    }
    # ランダムに1人抽出
    my $randomized_user = $users[int(rand(@users))];
    return $randomized_user;
}

sub post_slack {
    my $message = shift;
    my $slack_api =
      WebService::Slack::WebApi->new(
        token => $slack_token
      );
    # Slackにメッセージを通知
    $slack_api->chat->post_message(
        channel => $slack_channel_id,
        text    => $message,
    );
}

app->start;

このアプリケーションを、Webhookが受信できる場所に設置します。動作確認は、ローカルホストやNATNetwork Address Translationの内側で動作しているサーバを外部公開することが可能なngrokを利用して行うのが簡単でよいでしょう[3]⁠。WebhookのPayload URLには、https://xxxxxxx.ngrok.io/payloadのように/payloadを付けてください。

このように、Webhookを受信するイベントとGitHub APIを組み合わせて追加していくことで、任意の操作の自動化や、好きなタイミングでのSlackなどの外部ツールとの連携が可能となります。前回で解説したように公開リポジトリが作成されたタイミングで通知したり、リポジトリ内のWikiが更新されたら通知したりといったこともできます。

まとめ

駆け足になりましたが、GitHub APIを使用してチーム開発をスムーズに進めるためのアイデアを紹介しました。みなさんのプロジェクトに合わせて、これまで手動で行っていた操作を自動化したり、外部ツールとうまく連携させたりすることで、本来のタスクに集中しやすい環境を作っていけるでしょう。

さて、次回の執筆者はutgwkkさんで、テーマは「他言語のライブラリをPerlに移植する」です。お楽しみに。

WEB+DB PRESS

本誌最新号をチェック!
WEB+DB PRESS Vol.130

2022年8月24日発売
B5判/168ページ
定価1,628円
(本体1,480円+税10%)
ISBN978-4-297-13000-8

  • 特集1
    イミュータブルデータモデルで始める
    実践データモデリング

    業務の複雑さをシンプルに表現!
  • 特集2
    いまはじめるFlutter
    iOS/Android両対応アプリを開発してみよう
  • 特集3
    作って学ぶWeb3
    ブロックチェーン、スマートコントラクト、NFT

おすすめ記事

記事・ニュース一覧