GitHub issueとSlackスレッドを同期する仕組みと「issit」での実装例

こんにちは、エンジニアの @koga です。
今回は開発でよく使うGitHubとSlackのスレッドを同期する仕組みの取り組みと実装例を紹介します。プレイドでは、社内開発した Slack App 「issit」を使って、SlackメッセージからGitHub issueを作成し日々のタスク管理などに活用しています。

「issit」とは、Slack上で流れていってしまうやりとりをGitHub issueにすることで、フロー情報をストック情報に変換するためのアプリです。このアプリにより、SlackからGitHub Issueへストックする流れができました。
issit-1.png

2022年8月のPLAIDのデータを確認すると、作成されたissueの約5.8%が「issit」からの作成であることが分かりました。
しかし、やっていくうちに課題も出てきました。

見えてきた課題

GitHub issueのコメントに気付けないことがある。ということが見えてきました。

issueはclosedにしているけれど、Slackで終わったか確認している会話を見かけたり、issueにコメントを書いた後、Slackで「issueにコメントしました!」という会話も見かけることがありました。
Slackでコメントしている理由は簡単で、GitHubへのコメントでは気づかれないからです。

解決した方法

この課題を解決するために、GitHub issueのコメントやステータスをSlackに反映する仕組みをGitHub webhookを使って実装しました。
これによって “新しいissitの図” のように、SlackとGitHubで双方向の流れができ、issueのコメントに気づけるような仕組みにすることができます。
issit-2.png

解決した実例紹介

「issit」はSlackのメッセージショートカットからGitHub issueを作成することができます。
メッセージショートカットを実行するとモーダルが表示され、GitHub webhookの設定もモーダルでおこなえます。

GitHub webhookの設定項目は2つあります。

  • issueのcloseをSlackのスレッドへ通知する設定
  • issueコメントをSlackスレッドへSyncする設定

issit-example-1.png

issue作成したあとにGitHub webhook設定を変更することも可能です。
「issit」の投稿で、Slackのメッセージショートカット「issitのGitHub webhook設定」を実行するとモーダルが表示されます。
issit-example-2.png

そのモーダル内で各項目を変更し保存することでGitHub wobhook設定を変更することができます。
issit-example-3.png

defaultのGitHub webhookを設定しておくことも可能です。
設定したいチャンネルで /issitとコマンドを実行するとチャンネルで設定したリポジトリ一覧が表示されます。
issit-example-4.png

リポジトリの「Settings」を押すと、issue作成時のdefault値を設定できるモーダルが表示され設定することができます。
issit-example-5.png

実装の紹介

「issit」はslack/boltを使用して実装しているため、GitHub webhookを受け付ける実装もboltに対応している必要があります。Expressを使用したサンプルはよく見かけますが、slack/boltでのサンプルはなかなかありませんでした。

ただ、slack/boltには receiver という機能があり、外部からのアクセスを受け取ることができます。このreceiver機能を使用することでGitHub webhookを受け取るようにしました。

// Bolt.ts
const receiver = new ExpressReceiver({
  signingSecret: credentials.SLACK_SIGNING_SECRET,
})

export const app = new App({
  authorize: SlackInstaller.authorize,
  signingSecret: credentials.SLACK_SIGNING_SECRET,
  endpoints: '/slack/events',
  receiver,
})
// index.ts
import { app } from "./Bolt"
// express router
import github from "./routes/GitHub"

// express routerのように使用できます
app.receiver.app.use('/github', github)

GitHub webhookの実装には、octokit/webhooksを使用することにしました。
octokit/webhooksは、受け付けるwebhookのイベントとアクションごとに指定できるためとても便利です。
参考: GitHub Webhook のイベントとペイロード

// index.ts
import { createMiddlewareGitHubWebhooks } from './routes/github'

const middlewareGitHubWebhooks = await createMiddlewareGitHubWebhooks()
app.receiver.app.use(middlewareGitHubWebhooks)
// routes/github.ts
import { Webhooks, createNodeMiddleware } from '@octokit/webhooks'

import { IssueClosedUseCase } from './IssueClosedUseCase'
import { IssueCommentCreatedUseCase } from './IssueCommentCreatedUseCase'
import { IssueCommentEditdUseCase } from './IssueCommentEditdUseCase'
import { IssueCommentDeletedUseCase } from './IssueCommentDeletedUseCase'

export const createMiddlewareGitHubWebhooks = async () => {
  const webhooks = new Webhooks({
    secret: credentials.GITHUB_WEBHOOK_SECRET_TOKEN,
  })

  webhooks.on('issues.closed', IssueClosedUseCase)
  webhooks.on('issue_comment.created', IssueCommentCreatedUseCase)
  webhooks.on('issue_comment.edited', IssueCommentEditdUseCase)
  webhooks.on('issue_comment.deleted', IssueCommentDeletedUseCase)

  return createNodeMiddleware(webhooks, { path: '/github-webhooks' })
}

GitHub App の設定

「Issit」のGitHub連携は、GitHub App を作成しGitHub Organizationへインストールすることで実現しています。

GitHub webhookを使用するためにはGitHub Appの設定でwebhookを有効にする必要があります。設定する項目は以下の3つです。

  • App settings画面 「General」でWebhookをActiveにし受け付けるURL を指定する。
    github-app-setting-1.png
  • App settings画面 「Permissions & events」にて、webhookで受け取りたいイベントの権限を付与する
    • Issue: Read and write - Issueの作成、Issueのコメントを取得するため
  • App settings画面 「Permissions & events」の Subscribe to events で、受け取りたいイベントにチェックを入れる
    • Issues: Issueの変更内容やCloseされたことを検知するため
    • Issues comment: Issueのコメントの作成・変更・削除を検知するため
      github-app-setting-2.png

Permissionsを指定した状態でGitHub Marketplaceへ公開した場合、Subscribe to eventsの変更はリリース申請なしに変更することができました。「issit」の場合も、issueの作成と読み込みの権限を指定しGitHub Marketplaceへ公開していたため、Subscribe to eventsの変更は申請なしに使用することができました。

「issit」での動作確認

Slack App「Issit」をSlackワークスペースへインストールし、GitHub Appの「issit-app」をGitHub Organizationへインストールすることで、SlackとGitHub間で相互に連携できるようになりました。

issit-comment-sync-3.png

まとめ

SlackからGitHubへの一方向ではなく、GitHubからSlackの双方向にすることで、issueの状態をSlackでも確認しやすくすることができました。GitHubやSlackはAPIやwebhookが充実していますので、職場やプロジェクトの運用にあったAppを実装してみるのも良いのではないでしょうか。

実装が難しい場合は、 「issit」 の導入も検討していただけたら嬉しいです。