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

Google Apps ScriptでGitHubのプルリクエスト作成時に自動的にレビュアーをアサインする

More than 1 year has passed since last update.

概要

Githubでプルリクエストが作成されたらwebhookでGoogle Apps Scriptを実装し、レビュアーをランダムアサインします。

Githubのアクセストークン作成

GithubのPersonal access tokensから作成します。

  1. Generate new tokenから新規作成
  2. Full control of private repositoriesの権限を許可

スプレッドシートを準備

新規でスプレッドシートを作成します。
リポジトリ名とレビューチーム名を入力します。

No.(A列) リポジトリ名(B列) チーム名(C列)
1 hoge1 team_hoge1
2 hoge2 team_hoge2
3 hoge3 team_hoge3
4 hoge4 team_hoge4
5 hoge5 team_hoge5

Google Apps Scriptを実装

スプレッドシートのメニューから「ツール -> スクリプトエディタ」を開いて以下のファイルを配置する。
以下の設定値は変更する。

スクリプトファイル名 定数名
Spreadsheet.gs SHEET_NAME
Github.gs OWNER
Github.gs ACCESS_TOKEN
Main.gs
/*
 * プルリク作成時にレビュアーをアサインする
 * @param request HttpRequest
 */
function doPost(request) {

  // JSON形式に変換
  var jsonData = JSON.parse(request.postData.getDataAsString());

  // プルリク作成時のみ実行する
  if ("opened" == jsonData["action"] && jsonData["assignees"] != null) {
    // リポジトリ名
    var repository = jsonData["repository"]["name"];
    // プルリク番号
    var number = jsonData["pull_request"]["number"];
    // プルリク作成者
    var sender = jsonData["pull_request"]["user"]["login"];

    // レビューするチーム名を取得
    var teamName = fetchTeamName_(repository);
    if (teamName != null) {
      reviewAssign_(repository, teamName, sender, number);
    }
  }
}
Spreadsheet.gs
// シート名
var SHEET_NAME = "シート名";

/*
 * スプレッドシートからチーム名を返却する
 * @param repository リポジトリ名
 * @return チーム名
 */
function fetchTeamName_(repository) {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
  // B列を全て取得する(ヘッダー行を考慮して-1をする)
  var values = sheet.getRange(2, 2, sheet.getRange("B:B").getLastRow() - 1, 3).getValues();

  for(var index = 0; index < values.length; index++) {
    if (repository == values[index][0]) {
      // リポジトリ名が一致したらチーム名を返却する
      return values[index][1];
    }
  }
}
Github.gs
// OWNER
var OWNER = "xxxxxxxx";
// ACCESS_TOKEN
var ACCESS_TOKEN = "xxxxxxxxxxxxxxxxxxxxxxxx";

/*
 * スプレッドシートからチーム名を返却する
 * @param repository リポジトリ名
 * @param teamName チーム名
 * @param sender プルリク作成者
 * @param number プルリク番号
 */
function reviewAssign_(repository, teamName, sender, number) {
  // チームIDを取得する
  var teamId =  fetchTeamId_(repository, teamName);

  if (teamId != null) {
    // プルリク作成者を除いたチームメンバーを取得
    var members = fetchReviewAssignMembers_(teamId, sender);
    // レビュアーをランダムで選抜
    var reviewer = members[Math.floor(Math.random() * members.length)];
    reviewAssignRegistration_(repository, number, reviewer);
  } 
}

/*
 * GithubAPIを作成する
 * @param url URL
 * @return GithubAPI
 */
function createGithubAPI_(url, repository) {
  url = "https://api.github.com" + url;
  url = url.replace(":owner",OWNER);
  url = url.replace(":org",OWNER);
  url = url.replace(":repo",repository);
  return url;
}

/*
 * リクエストパラメータを作成する
 * @param method method
 * @return リクエストパラメーター
 */
function params_(method) {
  return params_(method,"");
}

/*
 * リクエストパラメータを作成する
 * @param method method
 * @param payload payload
 * @return リクエストパラメーター
 */
function params_(method, payload) {
  var params =
      {
        "method": method,
        "Content-Type": "application/json",
        "muteHttpExceptions": true,
        "payload": payload,
        "headers": {
          "Authorization":" token " + ACCESS_TOKEN
        }
      };
  return params;
}

/*
 * GithubAPIにアクセスしてチームIDを返却する
 * @param repository リポジトリ名
 * @param teamName チーム名
 * @return チームID
 */
function fetchTeamId_(repository, teamName) {
  // https://developer.github.com/v3/orgs/teams/#list-teams
  var url = createGithubAPI_("/orgs/:org/teams", repository);
  var params = params_("GET");
  var response = JSON.parse(UrlFetchApp.fetch(url, params));

  for(var index = 0; index < response.length; index++) {
    if (response[index]["name"] == teamName) {
      return response[index]["id"];
    }
  }
}

/*
 * チームメンバーを取得してプルリク作成者を除外した一覧を返却する
 * @param repository リポジトリ名
 * @param teamName チーム名
 * @param sender プルリク作成者
 * @param number プルリク番号
 * @return プルリク作成者以外のメンバー一覧
 */
function fetchReviewAssignMembers_(teamId, sender) {
  // https://developer.github.com/v3/orgs/teams/#list-team-members
  var url = createGithubAPI_("/teams/:id/members", "");
  url = url.replace(":id",teamId);
  var params = params_("GET");
  var response = JSON.parse(UrlFetchApp.fetch(url, params));

  var members = [];
  for(var index = 0; index < response.length; index++) {
    // プルリク作成者はレビュアーから除外
    if (sender != response[index]["login"]) {
      members[index] = response[index]["login"];
    }
  }
  return members;
}

/*
 * プルリクにレビュアーをアサインする
 * @param repository リポジトリ名
 * @param number プルリク番号
 * @param reviewer レビュアー
 */
function reviewAssignRegistration_(repository, number, reviewer) {
  // https://developer.github.com/v3/issues/assignees/#add-assignees-to-an-issue
  var url = createGithubAPI_("/repos/:owner/:repo/issues/:number/assignees", repository);
  url = url.replace(":number",number);
  var payload = JSON.stringify({ 
    "assignees" : reviewer
  });
  var params = params_("POST", payload);
  var response = JSON.parse(UrlFetchApp.fetch(url, params));
}

スプレッドシートのAPIを公開

スクリプトエディタのメニューバーから公開できます。
1. 公開 > ウェブアプリケーションとして公開
2. プロジェクト バージョンを入力(例:v.1.0)
3. 次のユーザーとしてアプリケーションを実行は自分を選択
4. アプリケーションにアクセスできるユーザーは全員を選択
5. 現在のウェブ アプリケーションの URLをGithubのWebhooksに設定

GithubのWebhooksを設定

Githubで自動レビュアーアサインを設定したいリポジトリのSettingsを開きます。
Webhooksでadd webhookを追加します。

Why do not you register as a user and use Qiita more conveniently?
  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
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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