claspを使ったSlackとGoogle Spreadsheetの連携


今や、slackは情報共有のために広く使われるツールとなり、バグや要望などもslack上で共有されるようになりました。しかし、メッセージツールである以上、投稿を一覧として見ようとすると視覚的にわかりにくかったりするわけです。そこで今回、便利なslackをより有効に活用するため、Google Spreadsheetとの連携について書きたいと思います!

対象

  • slack上のメッセージを整理したい人

  • slackとGoogleのサービスと連携させたい人

  • GASのプロジェクトをローカルで開発したい人

  • こっそり業務改善ツールを作り、評価を上げたい人

技術的な内容

基本的に、文法や具体的な実装については書いていません。slackのメッセージを抽出し、GASで扱え、その結果としてGoogle Spreadsheetに出力ができるという流れを説明しています。

バージョン

私が作った時のバージョンを明記します。最新のバージョンはリンク先を参考にしてください。

環境構築について

今回使うのは、TypeScriptclaspです。Googleのサービスと連携するのであれば、GASを使うのが一般的ですが、GASはES6以上に対応しておらず、クラスの記述や変数の宣言が割と不便でした(個人差があります)。なので、今回はTypeScriptをコンパイルし、ES6以上の文法をほとんど有しての開発を行えるようにします!

現在は、GASがV8ランタイムをサポートしたことで、最新のECMAScriptが使えるようになりました。よって、TypeScriptを使う必要もなく、直接スクリプトエディタに書く場合はclaspは必要ありません。その場合は、Slack APIの使い方やスクリプトエディタの使い方だけ参考にしてください。

私はエディタとしてVSCodeを使っていますが、好きなものを使っていただいて大丈夫です。

祝!Google Apps Scriptが「V8ランタイム」をサポート!モダンなECMAScript構文が使えるようになった

V8 Runtime Overview | Apps Script | Google Developers

claspについて

claspとは、コマンドライン上でGASのプロジェクトを開発・管理できるツールです。

clasp is an open-source tool, separate from the Apps Script platform, that lets you develop and manage Apps Script projects from your terminal rather than the Apps Script editor.

参考:Command Line Interface using clasp

では早速構築していきましょう。

構築手順

npmやtslintについて分かる人は、claspgoogle-apps-scriptを入れるんだな、と思っていただければ十分です。

1. npmをインストールする (参考 Get npm!)
2. npmでプロジェクトを作り、必要なものをインストールする
terminal
 $ cd PROJECT_LOCATION
 $ npm init $ npm install @google/clasp tslint -D
 $ npm install @types/google-apps-script (-S)
 $ npx tslint --init
  • npm initでプロジェクトを作ります。いろいろ聞かれるので、適宜入力してください。特になければデフォルトでも良いです。

  • claspとtslintをインストールします。-Dとは、--save-devと同義で、package.json (npm init時に作られる)のdevDependencies欄にパッケージ名が記入されます。つまり、開発用にインストールしているということです。
    (参考:npmよく使うコマンドまとめ | Qiita)

  • google-apps-scriptをインストールします。-Sとは、--saveと同義で、package.jsonのdependencies欄にパッケージ名が記入されます。npm 5.0.0から、install時にデフォルトでsaveしてくれるので、オプションに指定する必要はありません。
    (参考:npm-install)

  • tslintの基本的な設定をいれます。

この手順では、claspをローカルにインストールしています。お好みでグローバルにしてもらっても構いません(ここではローカルにインストールしているものとします)。そこで、npm 5.2.0から、ローカルにインストールしたnpmパッケージをnpxコマンドだけで実行できるようになったので、これを使います。npxについて

3. claspプロジェクトを作る

まず、claspでGoogleアカウントにログインし、それからclaspプロジェクトを作ります。その際に、Google Apps Scriptの設定画面を開き、Google Apps Script APIをオンにします。

terminal
$ npx clasp login
$ npx clasp create  --rootDir ./src
? Create which script? (Use arrow keys)
❯ standalone 
docs
sheets
slides
forms
webapp
api

このような画面になり、自分が連携したいサービスを選びます。ちなみに、--rootDir ./srcと設定することで、clasp push実行時に余計なものを読み込まなくてすみます。

参考:clasp が Typescript をサポートした! | Qiita (大変わかりやすいのでこちらも合わせて)

--rootDirを付けずに作成した場合は手動で付け加えることができます。clasp createしたときに、.clasp.jsonというファイルができているので、ここにrootDirを付け加えます。scriptIdは、作られたスクリプトエディタ上で、ファイル → プロジェクトのプロパティでもみることができます。

.clasp.json
{ 
    "scriptId":"XXXX-XXXXXXXXXXXXXXXXX", 
    "rootDir": "./src"
}

ここまでで開発をする準備は完了しました。この辺の環境構築がいまいちうまく行かない場合は、GAS のGoogle謹製CLIツール clasp | Qiita こちらの記事を見ていただくと解決するかもしれません(この記事ではclaspをグローバルでインストールしています)

Slack APIを使う

ここで、SlackAPIを使ってメッセージを取得する方法について記述します。流れとしては、tokenを取得し、UrlFetchApp.fetchを使いGoogleAppsScript.URL_Fetch.UrlFetchApp型としてメッセージを取得します。基本的にはJSON形式です。

tokenの発行と取得

slack上のチャンネルやメッセージを扱うためには、それ専用のslackアプリを作り、そこでアクセストークンを取得する必要があります。

  1. slackアプリを作る
    • slack api このページへ行き、右上のYour Appsをクリックします
    • そこで、Create New Appで新しいslackアプリを作成します
    • その際、Workspaceによっては権限がない場合があるので、その時は管理者に同意をとってください
  2. scopeを指定し、アクセストークンを発行する
    OAuth & Permissionsのページにて、必要なOAuth scopeを追加します。
    特定のチャンネルのメッセージを取得するなら、

    この二つで十分です。プロジェクトによってはいろいろ追加してください。

  3. アプリをWorkspaceにインストールし、アクセストークンを発行する

    • 上の方にある、Install Appをクリックし、指示に従って進めます
    • アクセストークンを取得します

このトークンは、slackAPIを使う際に必要になります。

メッセージを取得する

tokenを取得したので、これでslack上のメッセージを取得する準備が整いました。基本的には、Slack api このサイトを参考にしていただければ様々なAPIの使い方が書いてあります。ここでは、一例としてconversations.listconversations.historychat.getPermalinkの使い方を書きます。

conversations.list

const conversationsList = UrlFetchApp.fetch(`https://slack.com/api/conversations.list?token=${TOKEN}&limit=${LIMIT}`);    

公式ページからも分かる通り、必須な引数はトークンだけです。他の引数も必要に応じて、&limit=20のように付け足していきます。

This Conversations API method returns a list of all channel-like conversations in a workspace. The "channels" returned depend on what the calling token has access to and the directives placed in the types parameter.

意訳
このAPIはワークスペースにあるチャンネルについていろいろ情報が詰まったオブジェクトのリストを返します。どんなチャンネルを返すかは、tokenや引数にいれるtype パラメータに依存します。

よって、このAPIを使えば、特定のチャンネルのIDが得られます。

conversations.history

const conversationsHistory = UrlFetchApp.fetch(`https://slack.com/api/conversations.history?token=${TOKEN}&limit=${LIMIT}&channel=${CHANNEL_ID}`);

必須な引数はトークンとチャンネルIDです。チャンネルIDはconversations.listで取得できるので、これを使います(別にlimitはなくてもいいです)。

This method returns a portion of message events from the specified conversation.
To read the entire history for a conversation, call the method with no latest or oldest arguments, and then continue paging using the instructions below.

意訳
このメソッドは特定の会話からメッセージの一部を返します。
全ての会話を読み込むには、latestoldestといった引数をデフォルトにしておき、下で説明しているページングを使います。

基本的に、historyは量が多く、pagingを使う機会が多いので、

const conversationsHistory = UrlFetchApp.fetch(`https://slack.com/api/conversations.history?token=${TOKEN}&limit=${LIMIT}&channel=${CHANNEL_ID}&cursor=${CURSOR}`); 

というように、cursorを指定することで次のページを表示できます。CURSORに入るのは、一つ前のconversations.historyで取得したデータのうち、response_metadataブロックのnext_cursorの値です。つまり、全ての会話を読み込むには、連鎖的にconversations.historyメソッドを呼び出す必要があります。

  • 注意:UrlFetchApp.fetchで返されるデータ型はGoogleAppsScript.URL_Fetch.UrlFetchApp型であり、内部のデータにアクセスするにはparseする必要があります。
JSON.parse(CONVERSATIONS_HISTORY)

chat.getPermalink

補足として、メッセージのリンクを取得するメソッドを紹介します。

const permalink = UrlFetchApp.fetch(`https://slack.com/api/chat.getPermalink?token=${TOKEN}&channel=${CHANNEL_ID}&message_ts=${MESSAGE_TS}`);

このメソッドは、トークンとチャンネルIDとそのメッセージのタイムスタンプが引数として必須です。OAuth scopeは必要ありません。conversations.historyメソッドでタイムスタンプを取得できるので、合わせて使うと便利になります。

スクリプトエディタを使う

pushから実行まで

ローカルでTypeScriptを使い開発した後、スクリプトエディタに出力して関数を実行します。これから流れを書いていきます。

  1. npx clasp push

    ローカルのコードをスクリプトエディタに出力します。この時、自動的にTypeScriptからGASへコンパイルしてくれます。ちなみに、npx clasp push --watchコマンドを入力すると、コードの変更と共にpushしてくれるので、一回一回コマンドを入力する手間が省けます。

  2. 関数を実行します

    関数を選択し、実行します。ブラウザによっては違うかもしれませんが、macでfirefoxを使っている場合、command + Rで実行できます。ちなみに、ログはcommand + enterで見ることができます。

スクリプトエディタ上での環境変数

github等でコードを共有する場合、tokenは隠しておきたいと思うはずです。そんな時のために、スクリプトエディタは環境変数を用意しています。

ファイル → プロジェクトのプロパティ → スクリプトのプロパティで、プロパティと値を指定します。使い方は、

PropertiesService.getScriptProperties().getProperty("property_name");

となります。

ライブラリの使用

GASのプロジェクトで、なんらかのライブラリを使いたい場合は、リソース → ライブラリで、ライブラリのIDを入力します。例えば、日時をうまく扱ってくれるmoment.jsを入れたい場合、MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48を入れ、追加します。そして、エディタ上で、Moment.moment()といったように使います。moment.jsをGASで書いてくれた人には感謝しかありません。一般的に、LibraryName.method()のように使います。

この方法だと、ローカルからpushするたびに再設定する必要があるので、より良い方法は、appsscript.jsondependenciesに書き込むことです。以下のように書くことで、MomentがGASで使えるようになります。

appscript.json
"dependencies": {
    "libraries": [
        {
            "userSymbol": "Moment",
            "libraryId": "MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48",
            "version": "9"
        }    
    ]  
},

トリガーについて

GASのプロジェクトでは、Googleのサーバー上で動かすことができるので、様々なトリガーを使って定期実行や時間指定での実行が可能です。

プロジェクトページにて、プロジェクトの詳細から、新しいトリガーを追加することができます。条件をある程度柔軟に決められるので、非常に便利です。

Google Spreadsheetへ

ここまできたら、あとは好きなようにできます。Google Spreadsheetと連携している場合、Spreadsheet Serviceを参照して、シートやセルを扱うことができます。そして、抽出したメッセージを綺麗に並べたり、日付を付けたり、リンクを貼ったりすることができます。

【保存版】初心者向け実務で使えるGoogle Apps Script完全マニュアルこの記事を見ていただくと、Spreadsheet Serviceのオブジェクトの使い方だけでなく、他のGoogleのサービスとの連携に関しても書いてありますので、slackのメッセージをGoogle Calendarに追加するなどさらに応用ができると思います。もちろん、公式リファレンスも参照してください。

ぜひいろいろなアプリを作ってみてください!