なんで作ろうと思った?
私の最近ハマっているマンガ『スライムライフ』でお気に入りのセリフがあり、それのボットが欲しくなったから。
使った技術は?
・Node.js
前提
・Node.js インストール済
・Yarn インストール済
・Slack アカウント作成済
・Heroku アカウント作成済
どうやって作ったの?
1. 3種類のパッケージをインストールする
yarn global add yo@3.0.0
yarn global add generator-hubot
yarn global add coffeescript@1.12.7
2. ディレクトリ作成
mkdir -p ~/git/maiamea/slimelife-bot
cd ~/git/maiamea/slimelife-bot
3. bot作成
yo hubot
上記のコマンドを実行すると以下のメッセージが表示される
# Yo を改善するために利用者の匿名のデータを Yo の開発者へ送信してよいかと尋ねるメッセージ
# 特に送信しても問題ないので、 y と入力
"We're constantly looking for ways to make yo better !"
# Git で設定した名前、メールアドレスが表示される。
# Enter を押す
? Owner ( your name < your email > )
# ボット名はディレクトリ名になる。
# Enter を押す
? Bot name (slimelife-bot)
# Description(説明)もデフォルトのままでOK
# Enter を押す
? Description (A simple helpful robot for your Company)
次の質問は要注意
# ボットアダプターは、slack と入力して Enterを押す
# slack と入力し忘れると、slackと連携するときにエラーが出てしまうので注意
? Bot adapter (campfire) slack
"Done in 〇.〇〇s" と表示されていればインストール完了
4. セリフのデータをまとめた json ファイルを用意する
touch scripts/data.json
{
"slimelife": [
"たった一つのことで自分を過小評価しちゃダメ",
"「まだ出来ない」「まだ不可能」なんて、事を成し遂げた瞬間にその意味を失ういい加減な言葉さ。ゴーレムを直せないってのもそれは現状の話。未来の誰かが、あるいは君が成し遂げたものになるかも知れない",
"出来ないことが出来るようになるのはすごいことだよ",
"挑戦し続けることが一番大事だ。失敗してもそれはとても貴重な経験。経験は君を消して裏切らない",
"今回のダンジョンでなにをしたか思い出しなさい。まず美味しいカレーを作ったでしょ?お化けも倒して闇の試練も乗り越えてフェンリルとも友達になったでしょ。この経験が今後に活きない訳ないじゃん。近づいてるよなんでも技師",
"一行読めた!やったぁ!!",
"この前ちょっと難しい本を一行読めたから、この本も一行ずつ頑張って読みます!!ゴーレムが直るかも知れないから!!!"
]
}
5. bot の処理を書く js ファイルを用意する
touch scripts/hello.js
'use strict';
const data = require('./data.json');
const words = data.slimelife;
module.exports = (robot) => {
robot.hear(/スライム/i, (msg) => {
const user_id = msg.message.user.id;
const word = words[Math.floor(Math.random() * words.length)];
msg.send(`<@${user_id}> ${word}`);
});
};
6. ボットを Slack のアダプターなしで動かす (テスト用)
bin/hubot
コンソール上で、「スライム」と入力してdata.json内のセリフが返ってくれば成功
# hubot の終了
Ctrl + c
7. Slack App で Hubotの設定
以下のページにアクセスし、検索欄に「Hubot」と入力
アプリを Slack に追加する | アプリおよびインテグレーション | Slack App Directory
workspace名が複数ある場合は、Hubot を入れたい workspace名が選択されているか確認する
「Slack に追加」をクリック
ユーザー名に「slimelife_bot」を入力
「Hubot インテグレーションの追加」をクリック
クリック後に表示される HUBOT_SLACK_TOKEN の文字列を控えるのを忘れないように注意
「インテグレーションの保存」クリック
8. Slack のチャンネルに Hubot を追加 (このボットを反応させたいチャンネルに参加させる)
チャンネルを選択する
詳細 → その他 → アプリを追加する
作成したボットの名前(slimelife_bot) を入力する
9. Hubot の起動
env HUBOT_SLACK_TOKEN=控えておいた文字列 bin/hubot --adapter slack
Slack上で、以下の挙動をすれば成功 (画像は別に設定したものなのでデフォルト画像のままでOK)
10. Herokuにデプロイする (Herokuとの連携)
# heroku CLI で ログイン
heroku login -i
メアド、パスワードを入力する
# Heroku App 新規作成 (Heroku上にサーバーを用意)
heroku create maiamea-slimelife-bot
URLを控える
# GitHubにpush (git init から git commit までの操作はここでは省略する)
git push origin master
# Heroku へデプロイする
git push heroku master
# Heroku への設定 (Herokuからslackに接続するための環境変数設定)
heroku config:set HUBOT_SLACK_TOKEN=控えておいた文字列
Hubot は30分以上放置するとスリープ状態になってしまうので以下の手順でスリープ防止の設定をおこなった。
# hubot-heroku-keepalive インストール
npm install hubot-heroku-keepalive --save
# hubot-heroku-keepaliveを追加
[
" Hubot-heroku-keepalive "
]
# HUBOT_HEROKU_KEEPALIVE_URLの設定
# PASTE_WEB_URL_HERE には、控えておいた 手順10. で控えておいたURL を貼り付ける
heroku config:set HUBOT_HEROKU_KEEPALIVE_URL=PASTE_WEB_URL_HERE
# タイムゾーンの設定
heroku config:add TZ="Asia/Tokyo"
# スケジューラアドオンを追加
heroku addons:create scheduler:standard
# スケジューラーの設定
heroku addons:open scheduler
Herokuのサイトに自動で移動する
Create job
起動させたい時間)Every day at 10:00 PM UTC
スケジューラーは、Webインターフェースから手動で構成する必要がある
curl ${HUBOT_HEROKU_KEEPALIVE_URL}heroku/keepalive
をペーストする
# 起動開始時刻 (JST) の設定
heroku config:set HUBOT_HEROKU_WAKEUP_TIME=07:00
# スリープ開始時刻 (JST) の設定
heroku config:set HUBOT_HEROKU_SLEEP_TIME=20:00
アプリの稼働時間の確認方法
Heroku の自分のアイコンをクリック
Account settings
Billing
エラーとかあった?
herokuへのプッシュ時に以下のエラーメッセージが表示された
$ git push heroku master
Enumerating objects: 21, done.
Counting objects: 100% (21/21), done.
Delta compression using up to 8 threads
Compressing objects: 100% (18/18), done.
Writing objects: 100% (21/21), 19.40 KiB | 1.49 MiB/s, done.
Total 21 (delta 2), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Node.js app detected
remote:
remote: -----> Creating runtime environment
remote:
remote: NPM_CONFIG_LOGLEVEL=error
remote: NODE_ENV=production
remote: NODE_MODULES_CACHE=true
remote: NODE_VERBOSE=false
remote:
remote: -----> Installing binaries
remote: engines.node (package.json): 0.10.x
remote: engines.npm (package.json): unspecified (use default)
remote:
remote: Resolving node version 0.10.x...
remote: Downloading and installing node 0.10.48
remote: Detected package-lock.json: defaulting npm to version 5.x.x
remote: Bootstrapping npm 5.x.x (replacing 2.15.1)...
remote: npm 5.x.x installed
remote:
remote: /tmp/build_43d540a4/.heroku/node/lib/node_modules/npm/bin/npm-cli.js:79
remote: var notifier = require('update-notifier')({pkg})
remote: ^
remote: SyntaxError: Unexpected token }
remote: at Module._compile (module.js:439:25)
remote: at Object.Module._extensions..js (module.js:474:10)
remote: at Module.load (module.js:356:32)
remote: at Function.Module._load (module.js:312:12)
remote: at Function.Module.runMain (module.js:497:10)
remote: at startup (node.js:119:16)
remote: at node.js:945:3
remote:
remote: /tmp/build_43d540a4/.heroku/node/lib/node_modules/npm/bin/npm-cli.js:79
remote: var notifier = require('update-notifier')({pkg})
remote: ^
remote: SyntaxError: Unexpected token }
remote: at Module._compile (module.js:439:25)
remote: at Object.Module._extensions..js (module.js:474:10)
remote: at Module.load (module.js:356:32)
remote: at Function.Module._load (module.js:312:12)
remote: at Function.Module.runMain (module.js:497:10)
remote: at startup (node.js:119:16)
remote: at node.js:945:3
remote:
remote: /tmp/build_43d540a4/.heroku/node/lib/node_modules/npm/bin/npm-cli.js:79
remote: var notifier = require('update-notifier')({pkg})
remote: ^
remote: SyntaxError: Unexpected token }
remote: at Module._compile (module.js:439:25)
remote: at Object.Module._extensions..js (module.js:474:10)
remote: at Module.load (module.js:356:32)
remote: at Function.Module._load (module.js:312:12)
remote: at Function.Module.runMain (module.js:497:10)
remote: at startup (node.js:119:16)
remote: at node.js:945:3
remote:
remote: -----> Build failed
remote:
remote: We're sorry this build is failing! You can troubleshoot common issues here:
remote: https://devcenter.heroku.com/articles/troubleshooting-node-deploys
remote:
remote: If you're stuck, please submit a ticket so we can help:
remote: https://help.heroku.com/
remote:
remote: Love,
remote: Heroku
remote:
remote: ! Push rejected, failed to compile Node.js app.
remote:
remote: ! Push failed
remote: Verifying deploy...
remote:
remote: ! Push rejected to maiamea-slimelife-bot.
remote:
To https://git.heroku.com/maiamea-slimelife-bot.git
! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to 'https://git.heroku.com/maiamea-slimelife-bot.git'
調べたこと
# 現状のnodeのバージョンを確認
node -v
> v10.17.0
# コードでのバージョンは、0.10.x と古かったので現状のバージョンに変更。
"engines": {
"node": "0.10.x"
}
を10.17.0に書き換える
# package-lock.jsonの更新
npm install
package.json を書き換えたから package-lock.json も更新する必要がある
問題なくビルドできた!
参考資料
・N予備校 【2019年度】 プログラミング入門 Webアプリ第3章6節 Hubot と Slack アダプタ
・HubotをHerokuでSlackに繋げるまで - Qiita
・Deploying to Heroku | HUBOT
・GitHub - hubot-scripts/hubot-heroku-keepalive: A hubot script that keeps the hubot Heroko web dyno alive