概要
会社のBacklogがSlack連携を利用できなかったので、WebhookとGoogle Cloud Functionsを利用して、Slackへ通知する仕組みを作成した。
流れ
- SlackのAppを作成する。
- Cloud Functionsにコードを設置する。その際、SlackのAppのURLを作成したAppのURLに置き換える。
- Backlogの管理画面から、Webhookの通知先にCloud FunctionsのURLを登録する。
Cloud Functionsのコード
以下のコードをCloud Functionsに設置します。
適当に作っただけなので、改善の余地が多いにあります。
改善案があれば、コメント頂けると助かります。
index.js
const { IncomingWebhook } = require("@slack/client");
/**
* Responds to any HTTP request.
*
* @param {!express:Request} req HTTP request context.
* @param {!express:Response} res HTTP response context.
*/
exports.helloWorld = async (req, res) => {
console.log('Do helloWorld')
if (req.method !== 'POST') {
console.log('Method Not Allowed')
res.status(405).send('Method Not Allowed');
return;
}
if (!req.body) {
console.log('Request Body Not Found')
res.status(400).send('Request Body Not Found');
return;
}
// メッセージ生成
const message = makeMessage(req);
// Slack 通知部分
// Slack の Webhooks URL を代入
const slack_webhook = "https://hooks.slack.com/services/hoge/fuga/hogehoge"
// こちらのURLを、各自のIncoming webhookのURLに置き換えてください。
const webhook = new IncomingWebhook(slack_webhook);
await webhook.send(message);
res.send(200);
};
// メッセージ生成部分
// 通知タイプ
// 1:課題追加
// 2:課題更新
// 3:コメントのみ追加
// 5:Wikiの追加
// 6:Wikiの更新
// 7:Wikiの削除
function makeMessage(req) {
const projectKey = req.body["project"]["projectKey"];
const type = req.body["type"];
const id = req.body["id"];
const notifications = req.body["notifications"];
const createdUser = req.body["createdUser"];
const createdUserName = createdUser['name'];
const summary = req.body['content']['summary'];
const content_id = req.body['content']['id'];
const key_id = req.body['content']['key_id'];
const dueDate = req.body['content']['dueDate'];
const description = req.body['content']['description'];
const content = {
'type': type,
'id': id,
'summary': summary,
'key_id': key_id,
'dueDate': dueDate,
'description': description
'createdUserName' : createdUserName
};
console.log(JSON.stringify(content))
// リンク先URLに必要な要素、BacklogのURLとプロジェクトキーと課題idを取得する
const projectBaseURL = "https://bklg.xxxx.com/backlog/view/";
const projectBaseURLwiki = "https://bklg.xxxx.com/backlog/wiki/";
const slack_user_map = new Map([["hoge", "@hogehoge"], ["fuga", "fugafuga"]]);
const slack_user = slack_user_map.get(createdUserName);
if (type == 1) { //1:課題の登録の場合
//課題の詳細から情報を取得する
const issueType = req.body['content']['issueType']['name'];
const status = req.body['content']['status']['name'];
//URLにプロジェクトKeyと課題Keyをセットし、課題にアクセスできるURLを生成する
const projectURL = projectBaseURL + projectKey + "-" + key_id;
//Slackに通知するメッセージの作成
return [
createdUserName + ' さんが「' + summary + '」を登録しました',
'',
':date: 期限日: ' + dueDate || 'なし',
':memo: 詳細: ' + description,
':earth_asia: 課題URL: ' + projectURL,
':label: 種別: ' + issueType,
'',
].join('\n');
} else if(type == 2 || type == 3){ //2:課題更新+3:コメント追加の場合
//課題更新とコメント追加共通で取得するコメント内容とコメントKeyを取得する
const comment = req.body["content"]["comment"]["content"];
const commentKey = req.body["content"]["comment"]["id"];
//URLにプロジェクトKeyと課題KeyとコメントKeyをセットし、課題にアクセスできるURLを生成する
const projectURL = projectBaseURL + projectKey + "-" + key_id + "#comment-" +commentKey;
if (type == 2){ //2:課題更新のみ、更新された情報を取得する
//Slackに通知するメッセージの作成
return [
createdUserName + ' さんが「' + summary + '」を更新しました',
'',
':date: 期限日: ' + dueDate || 'なし',
':email: コメント: ' + comment,
':earth_asia: 課題URL: ' + projectURL,
'',
].join('\n');
} else { //3:コメント追加の場合のみの更新情報を取得する
//Slackに通知するメッセージの作成
return [
createdUserName + ' さんが「' + summary + '」にコメントしました',
'',
':date: 期限日: ' + dueDate || 'なし',
':email: コメント: ' + comment,
':earth_asia: 課題URL: ' + projectURL,
'',
].join('\n');
}
} else if(type == 4){ //4:課題の削除
//URLにプロジェクトKeyと課題KeyとコメントKeyをセットし、課題にアクセスできるURLを生成する
const projectURL = projectBaseURL + projectKey + "-" + key_id;
//Slackに通知するメッセージの作成
return [
createdUserName + ' さんが課題を削除しました',
'',
':earth_asia: 課題URL: ' + projectURL,
'',
].join('\n');
} else if (type == 5 || type == 6 || type == 7){ //5:Wikiの追加, 6:Wikiの更新, 7:Wikiの削除
const wiki_name = req.body["content"]["name"];
// const wiki_content = req.body["content"]["content"];
//URLにプロジェクトKeyと課題KeyとコメントKeyをセットし、課題にアクセスできるURLを生成する
const projectURL = projectBaseURL + projectKey + "-" + key_id + "#comment-" +commentKey;
return [
createdUserName + ' さんが「' + wiki_name + '」に追加/更新/削除しました',
'',
].join('\n');
} else if (type == 8 || type == 9 || type == 10){ //8:ファイルの追加, 9:ファイルの更新, 10:ファイルの削除
const actions_map = new Map([
[8, "ファイルの追加"],
[9, "ファイルの更新"],
[10, "ファイルの削除"]
]);
const action_message = actions_map.get(type);
const content_name = req.body["content"]["name"];
const content_dir = req.body["content"]["dir"];
return [
createdUserName + ' さんが' + action_message + 'しました。',
'',
'ファイル名: ' + content_name,
'場所: ' + content_dir,
'',
].join('\n');
} else {
const actions_map = new Map([[14, "課題をまとめて更新"],
[17, "お知らせの追加"],
[11, "Subversionコミット"],
[12, "Gitプッシュ"],
[13, "Gitリポジトリの作成"],
[15, "プロジェクトに参加"],
[16, "プロジェクトから脱退"],
[18, "プルリクエストの追加"],
[19, "プルリクエストの更新"],
[20, "プルリクエストにコメント"],
[22, "発生バージョン/マイルストーンの追加"],
[23, "発生バージョン/マイルストーンの更新"],
[24, "発生バージョン/マイルストーンの削除"]
]);
const action_message = actions_map.get(type);
return [
createdUserName + ' さんが' + action_message + 'しました。',
'',
'summary: ' + summary || 'なし',
'',
].join('\n');
}
}
終わりに
リモートで会社のメールを見る機会が少なくなったので、Slackに通知を飛ばせることができて、大変助かっている。