背景
弊社では、エンジニアの進捗管理や情報共有なとを目的とした日次定例MTG
があります。
日次定例MTGでは、日ごとに日直を決めて司会進行と気になる記事(ニュース)を共有することになっているのですが、
「あ、やべ、今日は日直だった!なにも準備してない!」
ということが度々起きたので、日直リマインダーを作ることにしました。
前提
日次定例MTGで使っているツール
- 日報やニュースの共有:Slack
- MTG時刻の管理:Googleカレンダー
- 日直の管理:スプレッドシート
- ビデオ通話:Zoom
日直の管理方法
日次定例MTGではスプレッドシート上に簡単なカレンダーが作られていて、日毎に日直の名前を入れる。という方法で管理されていました。
後述しますが、このシートから日直リマインダーを作る場合、今日の日付から日直の名前を参照する必要があったので、少し複雑な処理ができるツールを利用することになりました。
スプレッドシート上のカレンダーは下記画像のような形式です。
ツールの選定
Slackはとても便利で、手軽にリマインダーを作れそうなツールがいくつかあったので、選定からはじめました。
-
Slackのリマインド機能
特別なツールやインストールを必要とせず、簡単に設定できる。
しかし、スプレッドシートと連携できないため、いつ、誰にリマインドするかを毎度設定しなければならない。
→ 不採用 -
Slackワークフロー
ワークフロービルダーにスプレッドシートアプリをインストールする必要があるが、ノーコードで設定が完結する。
スプレッドシートと連携できてCRUDの機能が一通り用意されているが、「日毎に参照するセルの値を変える」などの細かい操作はできなかった。
いまの日直管理シートの書き方では、うまく通知できなさそう。
→ 不採用 -
GAS(Google Apps Script)
Googleによって開発されたスクリプト言語で、JavaScriptでプログラムを記述して複雑な処理を実行できる。
スプレッドシートやカレンダーとも連携でき、SlackAPI経由でSlack側にメッセージ送信等も可能。
→ 採用
リマインダの作成
1. SlackAPIトークンを取得する
大まかに下記の3ステップで取得できます。
取得方法について、こちらの記事の説明が詳しくて分かりやすいです。
1. Slack Botを作成する
2. Slackのワークスペースに作ったSlack Botをインストールする
3. メッセージ送信用トークンを取得する
2. Apps Scriptのエディタを開く
ブラウザでスプレッドシートを開き、拡張機能 > Apps Script を選択すると、GASの編集画面が起動します。
3. コードを書く
②で開いたApp ScriptのエディタにJavaScriptでリマインド機能を実装します。
詳細は省きますが、大まかに下記の用件を満たす機能を作成しました。
・ 土日、祝祭日に通知をしないように、Googleカレンダーを参照して日次定例MTGの予定のある日だけ実行する
・ 当日に通知されても準備が間に合わないケースがあるため、日直がある日の2営業日前から毎日通知する
・ 日直にはメンションで通知する
実装したコードも載せておきます。
// 毎日の日直を通知する
function dailyFacilitatorReminder() {
const date = new Date();
// カレンダーを参照して定例がある日だけ実行
if (!hasDailyMeeting(date)) {
console.log('本日は定例がありません。');
return;
}
// スプレッドシード上にある日直カレンダーから最大10日先までの日程を参照し、
// 直近の最大3名に日直のリマインドメッセージを生成する。
let messages = [];
for (let i = 0; i < 10; i++) {
const facilitator_name = findFacilitatorNameFromSpreadsheet(date);
if (facilitator_name) {
if (messages.length == 0) {
messages.push('本日の日直は<@' + facilitator_name + '>さんです。');
} else if (messages.length == 1) {
messages.push('次の日直は<@' + facilitator_name + '>さんです。');
} else if (messages.length <= 2) {
messages.push('その次の日直は<@' + facilitator_name + '>さんです。');
break;
}
}
date.setDate(date.getDate() + 1);
}
// メッセージをSlackに送信する
sendSlackMessage(messages.join('\n'));
}
// 技術部日次定例があるか
function hasDailyMeeting(date) {
const calendar_id = 'foobar@gmail.com';
const event_name = '技術部日次定例';
const calendar = CalendarApp.getCalendarById(calendar_id);
const calendar_events = calendar.getEventsForDay(date, {search: event_name, max: 1});
return Boolean(calendar_events.length);
}
// スプレッドシート上に作成されたカレンダーから日直の名前を取得する
function findFacilitatorNameFromSpreadsheet(date)
{
const year = date.getFullYear() % 100;
const month = date.getMonth() + 1;
const day = date.getDate();
const sheet_name = year + '-' + month + '月';
const targeet_date = month + '/' + day;
const sheet_id = '/** シートID **/';
const ss = SpreadsheetApp.openById(sheet_id);
const sheet = ss.getSheetByName(sheet_name);
const text_finder = sheet.createTextFinder(targeet_date);
const cell = text_finder.findNext().getA1Notation();
const target_cell = cell.slice(0, -1) + (Number(cell.slice(-1)) + 2);
const facilitator_name = sheet.getRange(target_cell).getValue();
return getSlackName(facilitator_name);
}
// カレンダーに記載されている名前からSlackでの名前を取得する
function getSlackName(name) {
const user_name_map = {
'〇〇': 'U01A0DFSQ2Y',
'△△': 'ECGE22YGAHT',
'◇◇': 'P3E1ALVMEWD',
};
return user_name_map[name] ?? '';
}
// Slackにメッセージを送信
async function sendSlackMessage(message) {
const url = 'https://slack.com/api/chat.postMessage';
const method = 'post'
const payload = {
'token' : '/** SlackAPIのトークン **/',
'channel' : '/** チャンネル名 **/',
'text' : message,
};
const params = {
'method' : method,
'payload' : payload
};
UrlFetchApp.fetch(url, params);
}
4. スクリプトを自動で実行してくれるように、トリガーを設定する
- App Scriptのエディタ画面の左のタブメニューから[トリガー]を押下し、トリガー管理画面に遷移
今回作成したスクリプトの場合)
実行する関数:dailyFacilitatorReminder
イベントのソース:時間主導型
トリガーのタイプ:日付ベースのタイマー
時刻:午前9時〜10時
5. 動作テスト
ここまで来たら、リマインダーは一通り完成です。
トリガーが発火するのを待つか、エディタから直接実行することで動作を確認することができます。
うまくいくと下記画像のようになります。
最後に
今回初めてGASに触れましたが、GASでもっといろいろなことができそうでワクワクしました。
こんなに便利な機能をタダで提供してくれるGoogleさまには頭が上がりません。