【GAS】Googleスプレッドシートを更新したらSlackに通知させる仕組みを作ってみた

# はじめに

- スプレッドシートに起票を行った際に、都度手動でSlackに起票の旨を通知していたので、自動化出来ないかなと思い、調べてみました。
- すると、やりたい事にぴったりの記事を発見。

>Googleスプレッドシートに書き込まれたらSlackに通知する
>https://toranoana-lab.hatenablog.com/entry/2020/03/13/173949

- 本記事ではGoogle Apps Script （以降、GAS）を使って更新通知を発行する処理をご紹介します。

# 前提条件

- 次のようなレビュー記録表に対して、以下の条件で更新通知を送る。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/30ebe878-5207-ce7c-7ac3-e7803e3a38e2.png)

　　① 内容（D列）に起票があった場合は通知（変更・削除時は通知しない）
　　② 対策・処理（I列）に起票があった場合は通知（削除時は通知しない）
　　③ 確認（O列）に起票があった場合は通知


# 手順
1. 準備：Webhook設定
2. onEditの作成：変更前・変更後のセルの値によって処理を判断
3. sendSlackの作成：1のWebhook URL宛にAPIを送信
4. トリガーの作成

# 1. 準備

Slackへの投稿を行うには、事前にWebhookの設定が必要です。

① 次のURLにアクセスします。
https://my.slack.com/services/new/incoming-webhook/

② [チャンネルへの投稿]欄で、更新通知を送りたいチャンネルを選択し、[Incoming Webhook インテグレーションの追加]をクリック。
※ 今回はテスト用に自身のダイレクトを選択しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/d9e500fc-e9d1-b072-ef26-1cf88efb8be4.png)

③ インテグレーションが追加されたチャンネルには、次のようなメッセージが通知される。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/3313b5f5-19ca-a153-a88b-65449dd0e55e.png)

④ 先ほどのブラウザに戻ると、Webhook URLが発行されているので、こちらをコピーしておく。（以降の手順で使用します。）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/9441a7ce-ba63-bf50-63cb-51de39c2dab5.png)


# 2. onEditの作成

① GASのエディタは、スプレッドシートから[ツール]->[スクリプトエディタ]で開くことができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/9fdac0cf-e5e1-fe06-7e51-46e06337cd5b.png)

② こちらにonEdit(e)イベントで、変更セルの値を特定する処理を書いていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/1d7c8f10-72f1-67cd-56cb-33c282659e2e.png)

```
/////////////////////////////////////////////////
// onEdit(e)：slack更新通知                     //
////////////////////////////////////////////////

function onEdit(e) { 
  var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet(); // スプレッドシート(book)
  var activeSheet = activeSpreadsheet.getActiveSheet();          // アクティブシート(sheet)
    
  if(activeSheet.getName() != "レビュー記録表"){
    // 特定のシート以外の時は処理を中断する
    return;
  }
  
  
  var activeCell = activeSheet.getActiveCell();                   // アクティブセル
  var activeValue = activeCell.getValue();                        // アクティブセルの値
  var oldValue = e.oldValue;                                      // 変更前のアクティブセルの値
  var newInputRow = activeCell.getRow();                          // アクティブ行
  var taskNo = activeSheet.getRange(newInputRow, 1).getValues();  // レビューNo 
  var spreadsheetUrl = "https://docs.google.com/spreadsheets/d/xxxxxxx/edit#gid=0&range=A";  // スプレッドシートのURL
  
  
  if(activeCell.getColumn() == 4 && activeValue != "" && oldValue == null){
    // ①内容（D列）に起票があった場合は通知（変更・削除時は通知しない）    
    
    // 送信するSlackのテキスト
    var slackText = "【起票】No." + taskNo + " に課題が起票されました。　\n" + spreadsheetUrl + newInputRow;
    sendSlack(slackText);
  
 
  } else if (activeCell.getColumn() == 9 && activeValue != ""){
    // ②対策・処理（I列）に起票があった場合は通知（削除時は通知しない）
    
    // 送信するSlackのテキスト
    var slackText = "【回答】No." + taskNo + " の課題に回答が追記されました。　\n" + spreadsheetUrl + newInputRow;
    sendSlack(slackText);
   
    
  } else if (activeCell.getColumn() == 15){
    // ③確認（O列）に起票があった場合は通知
    
    if (activeValue == "OK"){
      // 送信するSlackのテキスト
      var slackText = "【確認】No." + taskNo + " の課題がクローズされました。　\n" + spreadsheetUrl + newInputRow;
      sendSlack(slackText);
      
    } else if (activeValue == "NG") {
      // 送信するSlackのテキスト
      var slackText = "【確認】No." + taskNo + " の課題が却下されました。　\n" + spreadsheetUrl + newInputRow;
      sendSlack(slackText);  
      
    }
     
      
  } else {
    // 条件に該当しない変更の場合は処理を中断
    return;
  }
    
  
}
```

- 書式はJava Scriptベース。
- getActiveSpreadsheet()、getActiveSheet()で、現在のスプレッドシートおよびシートを取得できる。
- getValue()で現在（変更後）のセルの値が取得できる。
- e.oldValueで変更前のセルの値が取得できる。
- スプレッドシートURLの末尾に「#gid=0&range=[セルの位置] 」を付与すると、指定のセルの位置にリンク先を指定することができる。（今回は変更セル行のA列にリンクするように設定しました。）
- 更新箇所によって通知するメッセージを変更。


# 3. sendSlackの作成

更新通知の判定処理が書けたら、次に通知内容をSlackに送信する処理を書きます。

```
/////////////////////////////////////////////////
// sendSlack：slackに更新通知を送信 　　　        //
////////////////////////////////////////////////

function sendSlack(slackText){
  // slackにて追加したWebhook URLを設定
  var webHookUrl = "https://hooks.slack.com/services/xxx/xxx/xxx";
  
  var jsonData =
      {
        // "channel": "#general",   // 通知したいチャンネル（自身にダイレクト送信する場合はコメントアウト）
        'icon_url': "https://entershare.jp/wp-content/uploads/2017/11/unnamed.png",
        "text": slackText,
        "link_names": 1,
        "username": "レビュー記録表"
      };
  
  var payload = JSON.stringify(jsonData);
  
  var options =
      {
        "method": "post",
        "contentType": "application/json",
        "payload": payload
      };
  
  // リクエスト
  UrlFetchApp.fetch(webHookUrl, options);
}
```

- Slack通知するための情報（チャンネルやアイコン、送信するテキスト）をJSON形式で作成し、JSON.stringify() でSlack送信用のリクエストパラメータを生成する。
- UrlFetchApp.fetch() を使って、1の手順で取得したWebhook URL宛にAPIのリクエストを送信する。
- "channel"には、更新通知を送るチャンネル名を入力する。（自身に送信する場合はコメントアウトでOK）


# 4. トリガーの作成
① GASエディタより、[編集]->[現在のプロジェクトのトリガー]でトリガー作成画面に遷移する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/e39951ba-df1f-51ff-9538-f05837ad311a.png)

② 右下の[トリガーの追加]をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/8093e372-961f-fefe-7523-81b40429ef38.png)

③ イベントソースを「スプレッドシートから」、イベントの種類を「編集時」にし、[保存]をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/0903e019-3b3a-91e3-c719-70adf25b226e.png)

# 結果
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/ee8459f4-b0a6-68d4-3390-05dea2dd964a.png)

起票時にSlackに更新通知が届くようになりました！

# 上手く実行ないとき

## 1.GASを実行できない

GASの設定画面にある「Google Apps Script API」がオフになっていないことを確認してください。
（筆者はここで詰まりました）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/137780/3f9c8214-0ea7-b310-bf67-e7cd489c805e.png)

## 2.イベントソースに「スプレッドシートから」が表示されない

端末にGoogleアカウントが複数紐づけられている場合に発生する不具合です。
使用するアカウント以外を全て削除し、キャッシュをクリアして再度トリガー設定してください。
（筆者はここでも詰まりました）

>参考：
>https://teratail.com/questions/256202