Fluct+Backlog webhook+Chatwork APIでバックログのイベントをチャットワークに通知してメール確認作業から解放される(少しだけ)
はじめに
ランチェスターではタスク管理ツールとしてバックログを使っていて非常に便利なのですが、新規課題やコメントなど更新があったときに確認する手段が目視だったりメールで通知だったりで結構大変な感があります。そこで普段使っているチャットワークに通知させてメール確認という苦行から(少し)解放されたいと思います。
バックログにはイベントに対してwebhookが用意してあり、URLを設定することでそのURLに対してイベントに関するパラメータをPOSTで送信します。ここにチャットワークのAPIのURLを設定してお手軽通知したいところですがヘッダー等を指定できないのでそのままではAPIを利用できません。
そこでAWSのAPI GatewayとLambdaを利用して通知を実装してみたいと思います。
実装
実装にはFluctというツールを使います。
FluctはAmazon API GatewayとAWS Lambdaを組み合わせて1つのWebアプリをつくるのを支援するためのツールです。AWS Lambdaを使う場合はNode.jsかJava 8の環境で動くコードを書くことになるので、これに合わせてFluctはNode.jsで実装されています。Webアプリの開発者は、開発に使う環境にFluctをインストールし、fluct というコマンドを利用しながら開発を進めていくことになります。
http://qiita.com/r7kamura/items/80e5e9b2f5c9d1b3497e
Fluctのインストール
Fluctはnpmでインストールします。動作にはnode.js 0.12以上が必要とのことなのでない場合は入れておきます。
$ brew install node $ npm install fluct --global
インストール出来たらfluctコマンドで通知用アプリを作成します。apiのエンドポイントはchatwork_notificationsとします。
$ fluct new backlog_webhook
これで以下のファイルが作成されます。
Created ./backlog_webhook Created ./backlog_webhook/README.md Created ./backlog_webhook/.gitignore Created ./backlog_webhook/actions Created ./backlog_webhook/actions/.keep Created ./backlog_webhook/package.json
$ cd backlog_webhook $ fluct generate chatwork_notifications
以下のファイルが作成されます。
Created ./actions/chatwork_notifications Created ./actions/chatwork_notifications/index.js Created ./actions/chatwork_notifications/package.json
IAMロールの設定
Fluctのインストールが出来たら実装の前にAWS上でFluctで必要になるIAMロールの設定をします。
[IAM] -> [ロール] -> [新しいロールの作成]と進みFluct用のロールを作ります。
次にロールタイプの選択でAWS Lambdaを選択します。
次にポリシーのアタッチでAWSLambdaBasicExecutionRoleを選択します。
これでロールを作成します。
aws-cliのインストール・設定
githubのREADME等には特に書いてなかったのですが、どうやらFluctは内部でAWS CLIを使ってるようですので、無ければインストールする必要があります。その際接続するためのIAMユーザも一緒に作っておきます。
[IAM] -> [ユーザー] -> [ユーザーを追加]から新しくユーザーを作成します。
AWS CLIからアクセスするユーザなのでプログラムによるアクセスにチェックします。
ポリシーはAWSLambdaFullAccessとAmazonAPIGatewayAdministratorをアタッチします。
ユーザを作成したらそのユーザのアクセスキーIDとシークレットアクセスキーが書いてあるcsvをダウンロードしておきます。
このIDとキーをAWS CLIの認証に使います。
$ pip install awscli $ aws configure AWS Access Key ID [None]: 作成したユーザのAccessKeyID AWS Secret Access Key [None]: 作成したユーザのSecretAccessKey Default region name [None]: ap-northeast-1 Default output format [None]: json
Fluctの実装
AWS CLIの設定が完了したらいよいよFluctアプリ内にメインのコードを実装します。
まずbacklog_webhook/package.jsonを以下のように修正します。
{ "name": "backlog_webhook", "private": true, "fluct": { "accountId": 作成したロールのARNにある数字, "restapiId": null, "roleName": "fluct-role", "region": "ap-northeast-1" }, "dependencies": { "aws-sdk": "^2.2.3" } }
backlog_webhook/chatwork_notifications/package.jsonを以下のように修正します。
{ "name": "chatwork_notifications", "private": true, "fluct": { "contentType": "application/json", "httpMethod": "POST", "path": "/chatwork_notifications", "statusCode": 200 } }
次にメインとなるjsコードを実装します。
backlog_webhook/actions/chatwork_notifications/index.js
var https = require('https'); var querystring = require('querystring'); // backlogユーザID: チャットワークユーザIDのオブジェクト var bl_cw_ids = { 123456789: '[To:12345] ほげ山さん', 234567890: '[To:67890] ふが森さん' } // backlogプロジェクトID: チャットワークroom idのオブジェクト var project_room_ids = { 1234567890: '1234567', }; // チャットワークAPI key var CHATWORK_API_KEY = チャットワークAPIkey; var DEFAULT_ROOM_ID = チャットルームIDが指定されていない場合のデフォルトルームID; var ROOM_ID; var BACKLOG_URL = 'https://xxx.backlog.jp/'; function set_chatwork_room_id(event) { ROOM_ID = project_room_ids[event.project.id]; } function create_link(event, content) { var url = BACKLOG_URL + "view/" + event.project.projectKey + "-" + content.key_id; if (content.comment && content.comment.id) { url += "#comment-" + content.comment.id; } return url; } function create_links(event, link) { var urls = []; link.forEach(function(content) { urls.push(create_link(event, content)); }); return urls; } function create_message(event) { var notice_labels = []; if(event.notifications.length > 0) { event.notifications.forEach(function(ntf){ notice_labels.push(bl_cw_ids[ntf.user.id]); }); } notice_labels = notice_labels.filter(function (x, i, self) { return self.indexOf(x) === i; }); var message = ''; notice_labels.forEach(function(val){ message += val + "\n"; }); switch(event.type) { case 1: return message + "[info][title]" + event.createdUser.name + "が「" + event.content.summary + "」を追加しました。[/title]" + create_link(event, event.content) + "[/info]"; case 2: case 3: return message + "[info][title]" + event.createdUser.name + "が「" + event.content.summary + "」を更新しました。[/title]" + create_link(event, event.content) + "\n" + event.content.comment.content + "[/info]"; case 4: return message + "[info][title]" + event.createdUser.name + "が課題を削除しました。[/title]" + create_link(event, event.content) + "[/info]"; case 6: return message + "[info][title]" + event.createdUser.name + "がWikiを更新しました。[/title]" + create_link(event, event.content) + "[/info]"; case 14: return message + "[info][title]" + event.createdUser.name + "が課題をまとめて更新しました。[/title]" + create_links(event, event.content.link).join("\n") + "[/info]"; } return "unknown event type: " + event.type; } function post_to_chatwork(message, context) { var postData = querystring.stringify({ body: message }); var options = { host: 'api.chatwork.com', port: 443, method: 'POST', path: '/v1/rooms/' + ROOM_ID + '/messages', headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': postData.length, 'X-ChatWorkToken': CHATWORK_API_KEY } }; var req = https.request(options, function (res) { res.on('data', function (d) { process.stdout.write(d); }); res.on('end', function () { context.done(); }); }); req.on('error', function (err) { console.log(err); }); req.write(postData); req.end(); } exports.handler = function(event, context) { console.log('start event'); console.info('event', event); set_chatwork_room_id(event.requestParameters); console.info('context', context); var message = create_message(event.requestParameters); console.log('send message: ' + message); // ROOM_IDが設定されていない場合は警告メッセージを表示 if(!ROOM_ID) { ROOM_ID = DEFAULT_ROOM_ID; message = "チャットワークルームIDが設定されていません。\nバックログのプロジェクトID「" + event.project.id + "」とチャットワークのルームIDを対応付けてください。"; } post_to_chatwork(message, context); };
メインのコードは参考にしたページのコードそのままなのもアレなので通知ユーザがいる場合はチャットワークでもTOをつけるようにしてみました。
また複数プロジェクトと複数チャットルームにも対応してみました。(プロジェクトやルームやメンバーのID等は事前にCloudWatchのログなどから調べておく必要はありますが…)
デプロイ
実装が終わったらAPI GatewayとLambdaにデプロイします。
$ fluct deploy
これだけでデプロイすることが出来ます。
正常にデプロイ出来るとLambdaに関数が登録され、以下のようにAPI Gatewayにエンドポイントが作成されます。
このURLの末尾に/chatwork_notificationsをつけたURLがwebhook用のURLになります。これをバックログに設定します。
バックログwebhook設定
webhookを設定したいプロジェクトに移動して、[プロジェクト設定] -> [webhook] -> [webhookを追加する]を選択します。
webhook名、説明は適当に入力し、Webhook URLには先程のURLを入力、通知するイベントはすべてを選択しWebhookを追加します。
テスト
これでバックログを更新するとこんな感じのチャットが投稿されます。
便利ですね
おわりに
というわけでチャットワークにバックログのイベントを通知してみました。
最初はバックログのパラメータから名前を使ってチャットワークのユーザやルームをAPI経由で検索して取得できないかと頑張ってみましたが、名前の表記ゆれやそもそも結婚して名字が変わってる人などいてしんどかったので結局紐付けをコード内に埋め込みました。
ともあれこれでメール確認作業から(ほんの少し)解放されました。めでたし!
参考にしたページ
http://qiita.com/r7kamura/items/80e5e9b2f5c9d1b3497e
http://qiita.com/noboru_i/items/7255fe225854a4876b0d
http://qiita.com/zaru/items/bab992b9438f07740eb9
TAG
基本的にRuby on Railsで開発してます。最近はvue.jsも。好きな塔は円城です。
TAG
- Android
- AWS
- Bitrise
- CodePipeline
- Firebase
- HTML
- iOS
- IoT
- JavaScript
- KPI
- Linux
- Mac
- Memcached
- MGRe
- MGReのゆるガチエンジニアブログ
- MySQL
- PHP
- PICK UP
- PR
- Python
- Ruby
- Ruby on Rails
- SEO
- Swift
- TIPS
- UI/UX
- VirtualBox
- Wantedly
- Windows
- アクセス解析
- イベントレポート
- エンジニアブログ
- ガジェット
- カスタマーサクセス
- サーバ技術
- サービス
- セキュリティ
- セミナー・展示会
- テクノロジー
- デザイン
- プレスリリース
- マーケティング施策
- マネジメント
- ラボ
- リーンスタートアップ
- 企画
- 会社紹介
- 会社紹介資料
- 勉強会
- 実績紹介
- 拡張性
- 採用
- 日常
- 書籍紹介
- 歓迎会
- 社内イベント
- 社員インタビュー
- 社長ブログ
- 視察
- 開発環境