Slackの発言をEmoji reactionでカンタンにGitHub Issue化する

こんにちは yoshitsugu です。

普段Slackを使っていると、「この発言は流れてほしくない」というものがあると思います。

通常であればSlackのpin機能などで事足りると思いますが、バグの報告などはそのままGitHub Issue化できると便利です。

そこで、今回はSlackの発言にreactionをつけることでGitHub Issue化するSlack botを作ってみました。

今回のゴール

  • Slack上で発言にEmoji reactionをつけるとそのままGitHub Issueとして登録される
  • 1チャンネル1リポジトリとしてSlackチャンネルとGitHubリポジトリとの紐付けができる

手順

hubotの下準備

  1. hubotの準備をします。
  2. Slackにhubot integrationを追加します。

スクリプトの作成

hubotディレクトリのscripts/ 以下に以下のようなスクリプトをおきます。

octonode = require('octonode')
Slack = require('slack-node')
truncate = require('truncate')
_ = require('lodash')
slack = new Slack(process.env.HUBOT_SLACK_TOKEN)
github = octonode.client(process.env.HUBOT_GITHUB_TOKEN)

module.exports = (robot) ->
  robot.brain.data.repos = {} unless robot.brain.data.repos
  
  getMsgFromTs = (channel_id, ts) ->
    new Promise (resolve) ->
      options = {
        channel: channel_id,
        latest: ts,
        oldest: ts,
        inclusive: true,
        count: 1
      }
      slack.api 'channels.history', options, (err, res) ->
        resolve res
        
  getTeamInfo = ->
    new Promise (resolve) ->
      slack.api 'team.info', {}, (err, res) ->
        resolve res

  getChannels = (channel_id) ->
    new Promise (resolve) ->
      slack.api 'channels.list', {channel: channel_id}, (err, res) ->
        resolve res

  registerGitHubIssue = (ghrepo, title, body) ->
    new Promise (resolve) ->
        ghrepo.issue
          "title": title,
          "body": body,
        , (err, issue, h) -> 
          resolve issue

  slackMsgToPlainText = (msg, channels) ->
    while result = (/<(.*?)>/g).exec(msg)
      action = result[1].substr(0,1)
      replaced = result[0]
      switch action
        when "#"
          channel_id = /#(.*)/.exec(result[1].split("|")[0])[1]
          channel_name = channels[channel_id]?.name
          replaced = "##{channel_name}"
        when "!"
          replaced = ""
        when "@"
          user_id = /@(.*)/.exec(result[1].split("|")[0])[1]
          user_name = robot.adapter.client.rtm.dataStore.getUserById(user_id)?.name
          replaced = "@#{user_name}"
        else
          replaced = result[1]
      msg = msg.replace(result[0], replaced)
    return msg
  
  registerIssue = (msg) ->
    channel_id = msg.item.channel
    ts = msg.item.ts
    emoji = msg.reaction
    if emoji == process.env.GITHUB_ISSUE_EMOJI
      repo = robot.brain.data.repos[channel_id]
      unless repo
        robot.send {room: channel_id}, "リポジトリが設定されていません。@gh-bot set sikmi/xxx のような形式で設定してください"
        return
      msg = null
      channels = null
      getChannels().then( (d) ->
        channels = _.keyBy(d.channels, (x) -> x.id)
        return getMsgFromTs(channel_id, ts)
      ).then( (d) ->
        msg = d.messages[0]
        return getTeamInfo()
      ).then( (d) ->
        text = slackMsgToPlainText(msg.text, channels)
        url = "https://" + d.team.domain + ".slack.com/archives/" + channel_id + "/p" + ts.replace(/\./, "")
        ghrepo = github.repo(repo);
        return registerGitHubIssue(ghrepo, truncate(text, 50), url + "\n" + text)
      ).then( (issue) ->
        robot.send {room: channel_id}, "Issue作成完了!\n" + issue.html_url
      ).catch( (e) ->
        robot.logger.error e
        robot.send {room: channel_id}, e
      )
  
  robot.respond /set (.+)$/i, (res) ->
    r = res.match[1]
    github.repo(r).info (err, s) ->
      if err
        res.send "リポジトリ設定に問題があります: #{err.message}"
      else
        robot.brain.data.repos[res.message.room] = r
        res.send "リポジトリを設定しました: #{r}"

  robot.respond /get/i, (res) ->
    res.send "次のリポジトリが設定されています: " + robot.brain.data.repos[res.message.room]

  robot.adapter.client?.rtm?.on? 'reaction_added', registerIssue

今回は、GitHub APIの操作に

、hubot外のSlack APIの操作に

を使いました。

hubotデプロイ

あとはherokuなどにhubotをデプロイして動くようにすれば完了です。

環境変数として、HUBOT_SLACK_TOKEN にSlackのアクセストークン、HUBOT_GITHUB_TOKENにGitHubのアクセストークン、GITHUB_ISSUE_EMOJIにIssue化するときに使うSlack Emoji名の設定が必要ですので、それだけ注意してください。

結果

set (リポジトリ名) で対象のリポジトリ名を設定します。

image

get で今設定されているリポジトリ名を確認できます

image

GITHUB_ISSUE_EMOJIのEmoji名で設定したEmoji reactionをつけることでIssueを作成できます。

image

まとめ

今回はSlackの発言をGitHub Issue化できるhubotの拡張スクリプトを紹介しました。

弊社でも議事録、バグ報告などいくつかの利用例で活用されています。

何かの参考になれば幸いです。