はじめに
毎週行っている作業を自動化する Google Apps Script の、基本設計に示した4つ目のステップ「雛型ファイルのリンクを Slack に通知する」について説明します。
HTMLの雛型ファイル生成については、テンプレートを使って生成する方法を説明しました。サンプルコードのcreateHtmlTemplate()
関数は File 型のオブジェクトを返しますので、この記事では File オブジェクトの URL を Slack に通知する関数を作成します。
関数仕様
関数名: slackSendTemplate
- 引数
- file : URL を通知する対象 File
- 返り値: なし
- 振る舞い
- file の URL を Slack に通知する
シンプルですね。でも何か足りませんね。はい、一言に Slack と言いましても、どのワークスペースのどのチャネルに投稿するのかを示すパラメータが必要です。チャネルは開発中と本番運用で分けたいので、このパラメータはデプロイ時に決まると考えられます。こちらでも説明したように、このようなパラメータはプロジェクトのプロパティとして定義するのがよいです。
Slack の Webhook
外部アプリと連携して Slack にメッセージを送信する最も簡単なインターフェイスは Webhook です。Slack が提供するエンドポイントに対して、JSON 形式のデータをポストするだけで、Slack に通知を流すことができます。
Webhook の設定
こちらのドキュメントに簡単なチュートリアルがありますので、それを見て設定して下さい。英語がしんどいですか? では、簡単に手順を書いておきます。
-
上記リンク先の右上 "Your Apps" というリンクをクリックします
-
"Create New App" をクリックします
-
表示されたダイアログにアプリ名を入力し(この記事では AirBot とします)、Slack のワークスペースを選択します(サインインしているワークスペースを選択するか、ここでワークスペースにサインインします)
-
"Create App" をクリックします
-
開いた画面で投稿先のチャネルを選択して、"許可する" をクリックします
-
前の画面に戻りますが、Webhook URL の表示が増えていますので、"Copy" ボタンをクリックして URL をコピーします(必要な時にいつでもコピーできます)
-
サンプルコードもこの URL が挿入されたコードに変わっていますので、"Copy" ボタンをクリックしてコピーし、curlがインストールされた環境のターミナルに貼り付けて実行してみて下さい(感動の瞬間です!)
以上で完了です。Slack に投稿するのに必要なのはこの Webhook URL だけです。つまり、URL を知っていれば誰でも投稿できてしまいますので、URL をソースコードに埋め込むようなことはしないで下さいね。万一漏洩してしまった場合は、一旦ゴミ箱のアイコンをクリックして削除し、作り直して下さい。
プロパティ: SLACK_WEBHOOK
先にも書きましたように、Webhook URL はデプロイ時に決まるものと考えるとよいので、プロパティを作成します。プロパティ名は SLACK_WEBHOOK とします。
- Google Apps Script のスクリプトエディタで、メニューの「ファイル」→「プロジェクトのプロパティ」を選択します
- 開いたダイアログの「スクリプトのプロパティ」タブをクリックします
- 「+行を追加」をクリックします
- (名前)に SLACK_WEBHOOK を、(値)に Webhook URL を入力し、「保存」をクリックします
テストコード
マイドライブに HTML ファイルを作成して、その URL を Slack に通知するテストです。
function testSlackSendTemplate() {
const file = DriveApp.createFile('template.html', '<h1>This is a template file.</h1>', MimeType.HTML);
slackSendHtml(file);
}
関数コード
シンプルなメッセージ
まずは、何の飾り気もなく、ただ作成したファイルの URL を Slack に通知するコードです。Webhook URL に JSON形式のデータを POST するだけです。簡単ですね。
function slackSendTemplate(file) {
Logger.log('雛型ファイルのリンクを Slack に通知する');
//スクリプトプロパティを取得する
const url = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK');
const params = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify({ text: '雛型ファイルを生成しました ' + file.getUrl() })
}
UrlFetchApp.fetch(url, params);
}
初めてテストコードtestSlackSendTemplate
を実行した時に、Google ドライブ操作と、外部サービス接続のアクセス許可を求められます。アクセス許可については、こちらを参照して下さい。めでたく実行が完了すると、以下のように Slack にメッセージが表示されます!
リッチなメッセージ
Webhook の説明ページには、Attachment を使ってリッチなメッセージを作成するサンプルがあります。しかし、Attachment の説明ページを見ると、outmoded approach(時代遅れなやり方)なので Layout Blockを使いなさいと書かれています。以下は、Layout Block を使って、テキスト1、水平ライン、ファイルへのリンク、テキスト2 というメッセージを送るコードです。
function slackSendSimpleMessage(url, text) {
const message = { text: text };
slackSend(url, message);
}
function slackSendRichMessage(url, text1, fileName, fileUrl, text2) {
const message = {
blocks: [
{
type: 'section',
text: { type: 'mrkdwn', text: text1 }
},
{
type: 'divider'
},
{
type: 'section',
text: {
type: 'mrkdwn',
text: Utilities.formatString('<%s|_*%s*_>\n%s', fileUrl, fileName, text2)
}
}
]
};
slackSend(url, message);
}
function slackSend(url, message) {
const params = {
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(message)
};
Logger.log(JSON.stringify(message));
UrlFetchApp.fetch(url, params);
}
Slack 関連の関数は汎用性が高いので、別のスクリプトファイル slack.gs
に分けて定義しました。先ほどの例のシンプルなメッセージを送る関数slackSendSimpleMessage
と、リッチなメッセージを送る関数slackSendRichMessage
を定義しています。メッセージ送信部分は共通なので、関数slackSend
としてくくり出しました。
リッチなメッセージを送信するメインの関数は以下のようになります。
function slackSendTemplate(file) {
Logger.log('雛型ファイルのリンクを Slack に通知する');
const url = PropertiesService.getScriptProperties().getProperty('SLACK_WEBHOOK');
slackSendRichMessage(url,
':page_with_curl: <!channel> 今週の雛型ファイルを作成しました。',
file.getName(), file.getUrl(),
':stars:リンクを開いてダウンロードして下さい。');
}
テキストのフォーマットについては、こちらを参照して下さい。テストコードtestSlackSendTemplate
を実行すると、以下のようにリッチなメッセージが Slack に表示されます。
おわりに
実は記事を書いている途中に Attachment でなく Layout Block を使うべきだということに気づいてコードを書き直したので、随分書くのに時間がかかってしまいました。
おまけ
テキストのフォーマットに関する Slack のドキュメントには誤りがあります。問い合わせページから指摘しておいたので、いつか修正されると思いますが、念のためメモしておきます。ちなみに、問い合わせページが日本語のフォームだったので日本語で書いたら、英語でとんちんかんな返事が来ました。英語で説明したら理解して頂けたようでした。
Automatic parsingの説明に以下の記載がありますが、ここの true は false の誤りです。false がデフォルトです。
You can achieve this in different ways, depending on where the text is being placed:
- For text in layout blocks set a verbatim attribute of your text objects to true. This is actually the default method of processing these text objects.
同じく、少し下の記載の false は true の誤りです。verbatim は「文字どおりに」という意味ですので、true にすると自動パースしてくれなくなるのですね。
If you want to disable automatic parsing, you have a couple of options depending on the type of text:
- For text in layout blocks set a verbatim attribute of your text objects to false.