LoginSignup
55
51

More than 5 years have passed since last update.

SlackとスプレッドシートとHubotで非エンジニア向けの運用ツールとして使ってみる

Last updated at Posted at 2016-06-23

非エンジニアのオペレーターの人のために管理画面を作るのが面倒で、
Slack + Googleスプレッドシートでデータを更新作業をしてくれるHubotを作ったら結構良かった

例えば、こんな感じのランキングモジュールがありました。

スクリーンショット 2016-06-23 19.26.50.png

システムや運用の都合で自動化せずに、非エンジニアの人が手動で毎週更新するという仕様です。

更新の流れ

1.データをGoogleスプレッドシートに記入する。

スクリーンショット 2016-06-24 0.20.17.png

表示させたいコンテンツに対応するIDを記入してもらう

2.SlackからHubotで更新させる。

スクリーンショット 2016-06-23 19.31.52.png

Hubotへメンションを送るだけ

3.おわり

オペレーターの作業はこれだけ
普段使っているツールなので馴染みやすいです

仕組み

SlackのメンションをHubotで受け付け、GASでスプレッドシートの内容からJSONを生成、そのJSONをStaticサーバーにアップロードし、そのデータをサービス側のサーバーから取得するという流れになります。

文字で説明するとわけわからんので下図
Artboard 1.png

1.Slackのメンションを受け取る

hubot-slackのライブラリを読み込む

package.json
{
  "dependencies": {
    "hubot-slack": "^3.4.2",
    "hubot-slack-attachment": "^1.0.0",
  }
}

Slackのトークンを設定

$ HUBOT_SLACK_TOKEN="xxxxxxxxxxx"

Slackからメンションを受け取るにはこれだけ

update.coffee
module.exports = (robot) ->
  robot.respond /ランキングデータ更新/i, (msg) ->
    console.log "更新依頼受付"

これでランキングデータ更新の文字列が含まれるときに実行されるようになります。

2.GASでスプレッドシートのデータを取得するAPIを作る

こんなかんじの構成のシートがあったとします

monthly weekly
11111 66666
22222 77777
33333 88888
44444 99999
55555 12345

取得生成コード

getRanking.gas
function doGet(e) {
  var url = "https://docs.google.com/spreadsheets/d/xxxxxx/edit#gid=0"; // 取得ファイルのURL
  var sheetName = "sheet1"; // 取得するシート名

  var book = SpreadsheetApp.openByUrl(url);
  var sheet = book.getSheetByName(sheetName);

  var json = getData(sheet);
  var res = ContentService.createTextOutput(JSON.stringify(json));

  return res.setMimeType(ContentService.MimeType.JSON);
}

function getData(sheet) {
  var monthly = [];
  var weekly = [];

  var lastRow = sheet.getLastRow();
  for(var rowIndex=2; rowIndex<=lastRow; rowIndex++) {
    var month = sheet.getRange(rowIndex, 1);
    var week  = sheet.getRange(rowIndex, 2);

    if (month.getValue()) {
      monthly.push(month.getValue());
    }
    if (week.getValue()) {
      weekly.push(week.getValue());
    }
  }

  return {"monthy":monthly, "weekly":weekly};
}

公開ウェブアプリケーションとして導入 でAPI化

スクリーンショット 2016-06-24 1.11.24.png
Hubotからのアクセスが面倒なのでとりあえず、全員(匿名ユーザー含む)にします。

できあがったAPIを叩くと、こんなJSONが返却されるはず

{
  "monthy": [
    11111,
    22222,
    33333,
    44444,
    55555
  ],
  "weekly": [
    66666,
    77777,
    88888,
    99999,
    12345
  ]
}

3.HubotからGAS APIを取得してファイルを保存

npmのrequestfsを読み込む

update.coffee
request = require 'request'
fs = require('fs')

取得保存のコード

update.coffee
sheetApi = "https://script.google.com/macros/s/xxxxx-/exec" # GASで生成したAPI
tmpFile = "/tmp/ranking_" + new Date().getTime() + ".json" # 仮保存用ファイルのパス

request {
  url: sheetApi
}, (err, response, body) ->
  if err
    console.error err
    return

  # json形式が正しいかチェック
  JSON.parse(body)

  # ファイルとして保存
  fs.writeFileSync(tmpFile, body)

4.HubotからSCPでStaticサーバーへアップロード

NginxでStaticサーバーを用意し、もしGoogle側で何かあったとしても吸収できる構造にします。

npmのscp2を読み込む

update.coffee
client = require("scp2")

アップロードして、成功したらSlackへ成功通知

update.coffee
client.scp(
  tmpFile,
  {
    host: "127.0.0.1",
    username: "username",
    password: "password",
    path: "/var/www/nginx/public/ranking.json"
  },
  (err) ->
    if err
      console.error err
      return

    data = {
      text: "ランキングデータを更新いたしました!"
      channel: "test" #通知するチャンネル名
    }
    robot.emit "slack.attachment", data
)

この部分はGit+capistranoとかにすれば、もっと良い感じになるかなと思います。

5.サービス側からStaticサーバーのranking.jsonを取得

普段と同じように、APIを取得する感じで書いて、クライアントに表示する

おわり

Slackをインターフェイスにしたら、使い方を教えやすいし、わかりやすい、
オペレーター業務がSlack上に流れるので更新されたタイミングが残るのも良かったです。
ただフォーマットがズレるとエラーになったりするため(上記の例だとIDの数値ではなく、文字列が入ってしまったなど)、エラーチェックなどのオペレーションミスを防ぐ仕組みはなにかしら必要です。

手順は多いですが、ローテクの寄せ集めなので作るのは結構簡単です。
どっちもHubotもGASもECMAScript仕様なので覚えなきゃいけないことは少なく
なにより、この機能のために管理画面のUIやDBを用意しなくても良いのが楽。

55
51
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
55
51