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

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

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

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

## トークンなどのコンフィグを事前に登録しておく
[Class PropertiesService](https://developers.google.com/apps-script/reference/properties/properties-service)を参考にコンフィグを設定しておきます。

```js: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からデータを取得する
以下のようにすればデータが取得できます。

```js
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など突然出てきていますが、
先程設定したコンフィグの値は以下の記述で引っ張ってくることができます。

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

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

```js
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のオブジェクトが出来上がり、比較することができるようになります。

```js
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でいい感じで書くためのライブラリを作った](http://qiita.com/soundTricker/items/43267609a870fc9c7453) という記事を参考に、ライブラリを利用しました。
これで非常に簡単にSlackへ通知することが可能に。

```js
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](https://qiita-image-store.s3.amazonaws.com/0/37036/bceca703-11a4-fc0d-ce6e-8f74399bcc71.png)


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

![project_trigger.png](https://qiita-image-store.s3.amazonaws.com/0/37036/e5151149-01c6-23c7-62a4-f4ef31817ae6.png)


## 最終的なコード

```js: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");
}
```

```js: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便利だな。