読者です 読者をやめる 読者になる 読者になる

定期的に GitHub API を叩いて Slack にポストしたい (1)

発端

  • GitHub でレビューコメントきたら Slack に通知ほしい
  • かといって全部のコメント通知されてもウザい
  • 定期的に GitHub をみにいってコメントが増えてたら Slack に投げる、みたいなの bot を作ろう
  • 全3回の予定。

調べた

  • GitHub Slack」で検索すると大体「Node.js + Hubot 安定」みたいな記事ばっかりヒットする。でもサーバー立てたりダルい
  • Google Apps Script って手があるらしい
  • Google Spreadsheet でマクロ書くときに使うアレ
  • ほぼ js
  • 単体でも組めて cron 的に使える
  • Google Drive -> 新規 -> その他 -> Google Apps Script (初回は「アプリを追加」で追加する必要あり)

GitHub API をたたく

  • 今回は GitHub から PR を取得するだけ
  • ラベルの絞り込み、コメントの取得、 Slack に投げるところは次回以降
  • ラベルは何に使ってるかっていうと、投げるチャンネルを決めるため。チーム内の PR には特定のラベルをつける、という運用をしていて、拾った PR はチームのチャンネルに投げる想定。
function getPulls() {
  var owner = "owner";
  var repo = "repo";
  var token = "accessToken" // GitHub で発行
  
  var options =
  {
    "method" : "get",
    "headers" : {
      "Authorization": "token " + token 
    }
  };
  
  // open な PR を全て取得して、そのあとラベルで絞り込む。
  // per_page を指定しないと 30 件しか取れない。
  var url = "https://api.github.com/repos/" + owner + "/" + repo + "/pulls?per_page=100";
  var response = UrlFetchApp.fetch(url, options);
  var json = JSON.parse(response.getContentText());

  var results = [];
  for (var i = 0; i < json.length; i++) {
    var hash = json[i];
    
    // ラベルの絞込をここでやる
    var labels = getLabels(hash["number"], owner, repo, options);
      if (hash && labels.indexOf(targetLabel) >= 0) {
      var commentCount = countComments(hash["number"], owner, repo, options);
      
      // 新しく追加された、またはコメントが追加されたもののみ対象とする。
      var updatedInfo = getUpdatedInfo(hash["number"], commentCount);
      var isUpdated = updatedInfo.isCreated || updatedInfo.newCommentCount > 0
      if (!isUpdated) {
        continue;
      }
      
      // reviewer requests の API は preview なのでまだ使わない
      //var reviewers = getReviewers(hash["number"], owner, repo, options);
      
      results.push({
        "url": hash["html_url"],
        "title": hash["title"],
        "user": hash["user"]["login"],
        "createdAt": hash["created_at"],
        "avatar_url": hash["user"]["avatar_url"],
        "number": hash["number"],
        "commentCount": commentCount,
        "newCommentCount": updatedInfo.newCommentCount
      });
    }
  }
  
  return results;
}

解説とか注意点とか