Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
11
Help us understand the problem. What is going on with this article?
@ryosukes

前日に登録されたissueをGASで定期的にSlackにまとめて流す

More than 3 years have passed since last update.

先日、「昨日登録されたissueをまとめて引っ張ってきてSlackに流したい!」
という声があり、Google Apps Scriptを使って対応しました。

最初はIFTTTやZapier使って簡単にできないものかと試してみたんですがうまくいかず。。
じゃあどこかのサーバでcron用意するか、とも思いましたが少々面倒です。

そこで、Google Apps Scriptでissueデータひっぱることができるし、定期実行できるし、
cronぽく動かせるんじゃないかと思い、実行してみたところさくっとできたので順にポイントを記載します。

トークンなどのコンフィグを事前に登録しておく

Class PropertiesServiceを参考にコンフィグを設定しておきます。

save.gs
function saveConfig() {
  PropertiesService.getScriptProperties().setProperty("slackToken",   "soysource");
  PropertiesService.getScriptProperties().setProperty("slackChannel", "#shari");
  PropertiesService.getScriptProperties().setProperty("githubToken",  "osu");
  PropertiesService.getScriptProperties().setProperty("githubOwner",  "sushi");
  PropertiesService.getScriptProperties().setProperty("repositry",    "maguro");
}

Githubからデータを取得する

以下のようにすればデータが取得できます。

function findIssues() {
    //取得したいissueページ数。
    var page_count = 1;

    var data = [];

    var base = 'https://api.github.com/repos/' + prop.githubOwner + '/' + prop.repositry + '/issues';
    var url  = base + '?page=' + page_count + '&state=all&sort=created&direction=desc&access_token=' + prop.githubToken;

    var response = UrlFetchApp.fetch(url);
    var json     = response.getContentText();
    Array.prototype.push.apply(data,JSON.parse(json));

    // プルリクエストのデータを排除
    data = data.filter(function(issue, index, array) {
      return issue.html_url.match(/issue/g);
    });

    return data;
  }

prop.githubOwnerなど突然出てきていますが、
先程設定したコンフィグの値は以下の記述で引っ張ってくることができます。

// save.gsで保存した定数を取得
var prop = PropertiesService.getScriptProperties().getProperties();

Githubから取得したデータを整形

昨日登録されたデータだけが必要なので、APIで返ってきたcreated_at パラメータの値を利用します。
そして created_at >= 昨日の00:00:00 のように比較すれば、必要なデータだけに絞れます。

var yesterdayIssues = issues.filter(function(issue) {
    var now        = new Date();
    var yesterday  = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
    var created_at = convertDate(issue["created_at"]);

    // dateのオブジェクトで比較
    if (created_at >= yesterday) {
      return issue;
    }
});

ただし、取得した値の形式は 2017-02-03T10:00:00Z のような文字列で返ってきます。
昨日の00:00:00を Dateでオブジェクト生成した場合、単純に比較することはできません。
そこで、new Date(created_at) のような形でDatecreated_atのDateオブジェクトを生成してあげる必要があります。
このとき、ハイフンをスラッシュに、Tを半角スペースに、Zを消去してあげます。
これでcreated_atのオブジェクトとyesterdayのオブジェクトが出来上がり、比較することができるようになります。

function convertDate(date) {
      date = date.replace( /-/g , "/" );
      date = date.replace( /T/g , " " );
      date = date.replace( /Z/g , " " );
      return new Date(date);  
}

Slackに通知

Slack BotをGASでいい感じで書くためのライブラリを作った という記事を参考に、ライブラリを利用しました。
これで非常に簡単にSlackへ通知することが可能に。

var messageTitle = '好きだ';
var message = '寿司が';
var slackApp = SlackApp.create(prop.slackToken);
slackApp.postMessage(prop.slackChannel, messageTitle + message, {username: "sushi bot", icon_emoji: ":cactus:"});

定期的に実行

開いているプロジェクトの上の方から リソース > 現在のプロジェクトのトリガー と進み、

gas_resource.png

その後、以下のように新しいトリガーを追加すれば完了です。

project_trigger.png

最終的なコード

save.gs
function saveConfig() {
  PropertiesService.getScriptProperties().setProperty("slackToken",   "soysource");
  PropertiesService.getScriptProperties().setProperty("slackChannel", "#shari");
  PropertiesService.getScriptProperties().setProperty("githubToken",  "osu");
  PropertiesService.getScriptProperties().setProperty("githubOwner",  "sushi");
  PropertiesService.getScriptProperties().setProperty("repositry",    "maguro");
}
postMessage.gs
function postMessage() {
  // save.gsで保存した定数を取得
  var prop = PropertiesService.getScriptProperties().getProperties();

  var issues  = findIssues();
  var message = createMessage(issues);

  if (message) {
    // slackApp インスタンスの取得
    var slackApp = SlackApp.create(prop.slackToken);
    var messageTitle = '昨日リポジトリに登録されたissueをお届けするンゴ。\n\n';

    slackApp.postMessage(prop.slackChannel, messageTitle + message, {username: "sushi bot", icon_emoji: ":cactus:"});
  }

  function findIssues() {
    //取得したいissueページ数。更新頻度が少なそうなのでとりあえず1
    var page_count = 1;

    var data = [];

    var base = 'https://api.github.com/repos/' + prop.githubOwner + '/' + prop.repositry + '/issues';
    var url  = base + '?page=1&state=all&sort=created&direction=desc&access_token=' + prop.githubToken;

    var response = UrlFetchApp.fetch(url);
    var json     = response.getContentText();
    Array.prototype.push.apply(data,JSON.parse(json));

    // プルリクエストのデータを排除
    data = data.filter(function(issue, index, array) {
      return issue.html_url.match(/issue/g);
    });

    return data;
  }

  function createMessage(issues) {
    var messeges;

    var yesterdayIssues = issues.filter(function(issue) {
      var now        = new Date();
      var yesterday  = new Date(now.getFullYear(), now.getMonth(), now.getDate() - 1);
      var created_at = convertDate(issue["created_at"]);

      // dateのオブジェクトで比較
      if (created_at >= yesterday) {
        return issue;
      }
    });

    if (yesterdayIssues.length > 0) {
      return modifyMessage(yesterdayIssues);
    }
    return '';
  }

  function convertDate(date) {
      date = date.replace( /-/g , "/" );
      date = date.replace( /T/g , " " );
      date = date.replace( /Z/g , " " );
      return new Date(date);  
  }

  function modifyMessage(issues) {
    var issueLines = issues.map(function(issue) {
      return "" + issue["title"] + "(" + issue["user"]["login"] + ")" + " " + issue["html_url"];
    });

    var message = issueLines.reduce(function(prev, current, index, array) {
      return prev + "\n" + current;
    })
    return message;
  }
}

これでissueが登録された次の日はSlackに通知が来ます。
GAS便利だな。

11
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  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
kurashicom
「北欧、暮らしの道具店」を運営するクラシコムのエンジニアチーム。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
11
Help us understand the problem. What is going on with this article?