Hexo で PubSubHubbub 通知をする

Hexo の フィード出力を設定した際に、設定項目で気になったものがありました. “hub - URL of the PubSubHubbub hubs (Leave it empty if you don’t use it) – hexo-generator-feed“ です.

そもそも PubSubHubbub 自体を知らなかったのですが、”パブサブハバブ – Wikipedia“ と 読むそうで、データの変更(ここでは、ブログの更新情報) を リアルタイムに通知するためのプロトコルなのだそうです.

この仕組みを使うことで、Google などの検索エンジンにブログの更新を効率よく通知することができ、インデックス化を早めることができるとのことで、早速導入したいと思います.

作業環境

  • Windows 7
  • Hexo 3.2
  • hexo-generator-feed 1.2.0
  • GitHub (GitHub Pages / Webhook)

PubSubHubbub とは?

PubSubHubbub は、分散型 の パブリッシュ(発行)/サブスクライブ(購読) コミュニケーション を 行うためのオープンなプロトコルで、仕様は https://github.com/pubsubhubbub/PubSubHubbub で 公開されています. 2017年1月現在のバージョン は 0.4 です.

ざっくり言うと、情報の提供者と利用者の間にハブを置くことで、それぞれが分離した作業ができるようにし、またプッシュ型にすることで情報の利用者が提供者のサーバへ定期的なポーリングせず不要な負荷を下げることができるようになります.
利用例として気象庁の電文公開があります.

今回は、この仕組みを使い Google PubSubHubbub Hub へ ブログの更新情報をプッシュし、Google の クローラー へ ブログの更新に関する情報を購読してもらいます. これによって Google の クローラー が 定期的にブログの更新を確認しに来てくれていたのを、こちらからクローラーへ来てもらうことができるようになります.

これまでは Google の クローラーが来てくれるのを ただ待っていただけですが、PubSubHubbub を 使うことでクローラーを呼び込むことができ、検索エンジンのインデックス化を格段に早めることができるようになります.

Hexo に PubSubHubbub を 設定

PubSubHubbub は RSS や Atom フィード で 情報を提供します. hexo-generator-feed が PubSubHubbub の 情報生成に対応しているので、まずは hexo-generator-feed の 設定を行います.

config.yml の hexo-generator-feed に 関する設定に hub: http://pubsubhubbub.appspot.com を 追加します.

1
2
3
4
5
feed:
type: atom
path: atom.xml
limit: 20
hub: http://pubsubhubbub.appspot.com

hexo generate で サイトを再生成してローカルサーバ http://localhost:4000/atom.xml でフィードを確認してみると、<link href="http://pubsubhubbub.appspot.com" rel="hub"/> が 増えているのが分かります.

GitHub の Webhook で PubSubHubbub 通知設定

hexo-generator-feed の 設定はフィードの出力設定で、PubSubHubbub の ハブ (Google PubSubHubbub Hub) への通知は別途行う必要があります.
GitHub Pages で ウェブサイトを公開しているので、今回は GitHub の Webhook を 使って更新時にハブへ通知するようにしたいと思います.

GitHub リポジトリ の Setting ページ から、Webhooks を 表示し、右側の [Add webhook] ボタンをクリックします.

以下の情報を入力し、[Add webhook] ボタンをクリックします.

設定項目 設定内容
Payload URL [PubSubHubbub 通知 URL(※)]
Content type application/x-www-form-urlencoded を 選択
Secret [空欄]
Which events… Let me select individual events.Page build に チェック

[PubSubHubbub 通知 URL] は https://pubsubhubbub.appspot.com/publish?hub.mode=publish&hub.url=https://[username].github.io/atom.xml で、[username] を 自分のユーザ名に置き換える、もしくは hub.url= 以降に自分のサイトのフィード の URL にします.
心配な場合は https://pubsubhubbub.appspot.com/publish で 正しいか検証することができます.

また [Which events…] は Page build だけにし、GitHub Pages の ページがビルドされた時だけ通知するようにします. Push だと、ドラフトの記事を GitHub に 上げた際にも通知されてしまい、不要な通知がハブへ行ってしまいます.

Webhook が 追加されました. タイミングによっては通知のテストが行われておらずチェックがついてません. URL 部分をクリックし設定から通知テストを確認するかリロードして確認します.

通知テストの結果は Wehbook の 設定画面の一番下にあり、Response が 204 に なっていれば成功です.
実動作の確認としては CircleCI から再ビルドするか、hexo deploy で サイトを更新します. 正しくデプロイできると、この画面 の Recent Deliveries が増えます.


ブログ に PubSubHubbub の 通知を追加できました. これにより、より早く記事が検索できるようになるといいですね. また読んでいただけるような、しっかりした記事をかけるようにしていきたいと思います. どうぞ 今後ともよろしくお願いいたします.

Slack の ボットによる代理ポストで、簡易匿名化

ようやく常時稼働するボットを Slack に 常駐できるようになりました. 今回は Slack で 匿名発言する方法について考えたいと思います.

作業環境

  • Slack
  • Node.js 6.9.1 LTS
  • Botkit 0.4.2

Slack で 匿名発言

そもそもチャットなのに、なんで匿名で発言する必要があるのか、といった話もありますが、チームや組織の改善などを忌憚なくディスカスするには匿名はある程度意味があるようです.
行き過ぎると匿名のネット掲示板のように荒れるというケースもあるようですが、Slack は 招待性のチームで作られるので、ある程度は自制・自浄されることは期待できそうです.

Slack で 匿名発言する方法ですが、公式でその機能はありません. したがって何らかの仕掛けを作る必要があります.
API を 使って発言する方法なども考えられますが、せっかくボットを常駐させたので代理で発言してもらって、匿名化してみたいと思います.

ボット で 代理発言

Slack の ボットは、以前に設置したボット を 使うことにします.
ボットへの代理発言依頼は、ダイレクト・メッセージを使うことにします.

匿名で発言する先のチャンネルを選択(or 作成) します. 今回は sandbox に しました.
続いて チャンネル の ID を 調べるために、以下の URL へ アクセスします. [API_TOKEN] は ボットの起動に使用している API トークンです.
https://slack.com/api/channels.list?token=[API_TOKEN]

ページへアクセスすると JSON 形式 の チャンネル・リストが表示されるので、目的のチャンネルの ID を コピーします. 以下に今回使用する sandbox の 部分を抜粋します. "id": "C3ADKXXXX",C3ADKXXXX に 当たる部分になります.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"ok": true,
"channels": [{
"id": "C3ADKXXXX",
"name": "sandbox",
"is_channel": true,
"created": 1481422490,
"creator": "U3A3DXXXX",
"is_archived": false,
"is_general": false,
"is_member": false,
"members": [ "U3A3DXXXX", U3AQBXXXX ],
"topic": { "value": "", "creator": "", "last_set": 0 },
"purpose": { "value": "", "creator": "", "last_set": 0 },
"num_members": 2
}]
}

ボットの代理発言を実装します.
以下のコードをボットの実装に追加します. [CHANNEL_ID] は 上記で取得した発言先チャンネル の ID です.

1
2
3
4
5
6
controller.on('direct_message', (bot, message) => {
bot.reply(message, '匿名でポストしました.');
bot.startConversation({ channel : '[CHANNEL_ID]' }, (err, convo) => {
convo.say(message);
});
});

実装の内容としては以下となります.

  • controller.on()direct_message イベント に 反応するようにします.
  • bot.reply() で ダイレクト・メッセージに返事をします.
  • bot.startConversation() で ID 指定したチャンネルで会話を開始します.
  • convo.say(message); で 指定チャンネルへ message、ユーザから入力された内容を そのままに指定チャンネルへ発言します.

匿名で発言!

DIRECT MESSAGES の ボット名をクリックし、発言したい内容を入力します. (つまりボットに対してダイレクト・メッセージを送ります)

ダイレクト・メッセージを送るとボットから返事があり、すぐに匿名発言先のチャンネル (ここでは sandbox) に 発言があるハイライトがされます.

チャンネルを開くと、先ほどボットにダイレクト・メッセージした内容を、ボットが発言しています.
匿名発言ができるようになりました.


ボットを使って匿名発言ができるようになりました. Botkit が いろいろやってくれるので簡単ですね.

ただし匿名とはいえ単にボットで代理発言をさせているだけなので、ボット・プログラムでデバッグログなりを出すことで発言を残すことはできますので、完全匿名とまではいかないですが、自由な発言から議論が広がるといいですね.

Slack の ボット を 自動停止させない

2017年3月10日 更新
Botkit 0.5.1 から自動切断されなくなったようです.
本ポストのコードは不要ですが、記録のために残しておきます.

Slack に 設置したボット. しばらくするといつの間にかオフラインになっている場合があります…
せっかく作ったボット機能をいつでも簡単に使うというわけにいかないので対策を考えたいと思います.

作業環境

  • Slack
  • Node.js 6.9.1 LTS
  • Botkit 0.4.2

いつの間にかオフライン?

設置したボットに翌日話しかけてみたところ、応答がありませんでした. 残念…
よく見るとオフラインになっています.

ログを確認したところ notice: RTM close event: 1006 : なる出力があり、その後の再接続に失敗しているようです.
起動時と停止時に時間を出力するようにしたところ、約8時間ぐらいで止まっている感じでした. (もしかしたら途中でボットを呼んだから、なんとなく切りよくと考えると6時間?)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
c:\Develop\repos\slack-bot> set token=[API_TOKEN]
c:\Develop\repos\slack-bot> node index.js
Mon Dec 19 2016 15:49:08 GMT+0900 (東京 (標準時))
info: ** No persistent storage method specified! Data may be lost when process shuts down.
info: ** Setting up custom handlers for processing Slack messages
info: ** API CALL: https://slack.com/api/rtm.start
notice: ** BOT ID: bot ...attempting to connect to RTM!
notice: RTM websocket opened
info: ** API CALL: https://slack.com/api/chat.postMessage
notice: RTM close event: 1006 :
Mon Dec 20 2016 07:29:10 GMT+0900 (東京 (標準時))
error: Abnormal websocket close event, attempting to reconnect
notice: ** BOT ID: bot ...reconnect attempt #1 of 3 being made after 1000ms
info: ** API CALL: https://slack.com/api/rtm.start
notice: ** BOT ID: bot ...reconnect attempt #2 of 3 being made after 6297ms
info: ** API CALL: https://slack.com/api/rtm.start
notice: ** BOT ID: bot ...reconnect attempt #3 of 3 being made after 9096ms
info: ** API CALL: https://slack.com/api/rtm.start
error: ** BOT ID: bot ...reconnect failed after #4 attempts and 9096ms

何が起こった?

ログに RTM close event と あるように、RTM が クローズされたとのこと. これは日付を出力するために rtm_close イベントをフックしているのでわかっている部分で、では何故イベントが発生したのでしょうか.
rtm_close イベント を 発生させているのは、ログその後のメッセージから Slack_web_api.js の 以下の部分と思われます.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
bot.rtm.on('close', function(code, message) {
botkit.log.notice('RTM close event: ' + code + ' : ' + message);
if (pingTimeoutId) {
clearTimeout(pingTimeoutId);
}
botkit.trigger('rtm_close', [bot]);
/**
* CLOSE_ABNORMAL error
* wasn't closed explicitly, should attempt to reconnect
*/
if (code === 1006) {
botkit.log.error('Abnormal websocket close event, attempting to reconnect');
reconnect();
}
});

そうなると、今度は bot.rtmclose イベントを発火した部分を確認する必要があります.
この bot.rtmbot.rtm = new Ws(res.url, null, {agent: agent}); で、var Ws = require('ws'); です.
Node.js の WebSocket ライブラリ ws です. ちょっと深くなってきました…
そして、残念ながらクローズの条件となる部分を特定することができませんでした… (技術力足りてない orz)

では、エラー・コード 1006 とは?

6~8時間放置したら止まったのできっとタイムアウトしたのでしょう. と 思い込むことにして、気を取り直しエラー・コードの 1006 について調べたいと思います.

1
2
3
4
if (code === 1006) {
botkit.log.error('Abnormal websocket close event, attempting to reconnect');
reconnect();
}

Abnormal websocket close event と メッセージが出力されている通り、異常終了した感があります.
こちらもコードを追いかけたところ、先の ws の ファイル WebSocket.js に 以下のようなコードがあります.
なんか、デフォルト で 1006 を セットしてメッセージは出さない気がします. ログでも ~: 1006 :1006 の 後にメッセージが付きそうなのに何も出てなかったのは、このことなのでしょう. メッセージをつぶすなんて…

1
2
3
4
5
6
7
// If the connection was closed abnormally (with an error), or if
// the close control frame was not received then the close code
// must default to 1006.
if (error || !this._closeReceived) {
this._closeCode = 1006;
}
this.emit('close', this._closeCode || 1000, this._closeMessage || '');

しかし、この 1006 ハードコードもされ、デフォルトで使われ不思議な感じがします.
この 1006 の 謎をたどると getting the reason why websockets closed - Stack Overflow で 以下のように書かれています.

Close Code 1006 is a special code that means the connection was closed abnormally (locally) by the browser implementation
getting the reason why websockets closed - Stack Overflow

Close Code 1006 だそうで、リンク先を見ると以下のように書かれています.

7.4.1. Defined Status Codes
1006 is a reserved value and MUST NOT be set as a status code in a
Close control frame by an endpoint. It is designated for use in
applications expecting a status code to indicate that the
connection was closed abnormally, e.g., without sending or
receiving a Close control frame.
RFC 6455 - The WebSocket Protocol

ちょっと解りにくいので W3C の WebSocket も あたりました.
“In all of these cases, the the WebSocket connection close code would be 1006”、全部 1006 と 行ってますね… そして上記の RFC 6455 を 見ろと. うーんなるほど.

User agents must not convey any failure information to scripts in a way that would allow a script to distinguish the following situations:

  • A server whose host name could not be resolved.
  • A server to which packets could not successfully be routed.
  • A server that refused the connection on the specified port.
  • A server that failed to correctly perform a TLS handshake (e.g., the server certificate can’t be verified).
  • A server that did not complete the opening handshake (e.g. because it was not a WebSocket server).
  • A WebSocket server that sent a correct opening handshake, but that specified options that caused the client to drop the connection (e.g. the server specified a subprotocol that the client did not offer).
  • A WebSocket server that abruptly closed the connection after successfully completing the opening handshake.
    In all of these cases, the the WebSocket connection close code would be 1006, as required by the WebSocket Protocol specification. [WSP]

Allowing a script to distinguish these cases would allow a script to probe the user’s local network in preparation for an attack.
The WebSocket API

攻撃者から守るために全部 1006 にしてメッセージも出さないということなのだそうで、詳細を知るにはデバッグしていくしかないので、いったん諦めます…

暫定の対策

とりあえず止まらないようにワークアラウンドを設定したいと思います.
Botkit の GitHub Issues Slack RTM retry/reconnect not working #261に 同じような話がありワークアラウンドがありました.
議論の流れからすると reconnect に 関する Pull Request #532 が 上がっておりマージはされているようですが、そのリリースは 0.4.2 には含まれていないので、将来のバージョンアップに期待しつつ、今は @garymoon の コードを 使わせていただきます. ありがとうございます!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const controller = ...;
const bot = ...;
function start_rtm() {
bot.startRTM((err,bot,payload) => {
if (err) {
console.log('Failed to start RTM')
return setTimeout(start_rtm, 60000);
}
console.log("RTM started!");
});
};
controller.on('rtm_close', (bot, err) => {
start_rtm();
});
start_rtm();


これによりノンストップで稼働することができるようになりました. なぜリトライに失敗するのかはデバッグしてかないとわからないので、いずれ確認したいと思いますが、まずはボットに機能を足してボットライフを楽しみましょう♪

Hexo に Google Analytics を 設置する

ブログを設置するからにはアクセス数などが見れるようにしたくなるものです.
よく アクセスカウンタ を 設置して訪問していただいた数を表示することをしていましたが、現在では Google Analytics などを使って詳細な分析をするのが定番ですね.
ということで、Google Analytics を 設置したいと思います.

作業環境

  • Windows 7
  • Hexo 3.2
  • Hexo Theme Landscape
  • Google Analytics

Google Analytics の アカウント作成

Google Analytics を 使うには、Google の アカウントがっ必要ですが Gmail で よいので、ここでは持っているものとして、Google Analytics の アカウント作成に入りたいと思います.
Google Analytics の ウェブサイトへアクセスし、[アカウントを作成] ボタンをクリックします.

Google アカウント の メールアドレスを入力し、[次へ] ボタンをクリックします.
GoogleApps で 独自ドメインを設定しているメールアドレスでも利用できました.

Google アカウントのパスワードを入力し、[ログイン] ボタンをクリックします.

アカウント作成のステップが表示されるので、画面右の [お申込み] ボタンをクリックします.

アカウントの設定情報を入力する画面が表示されます. 自分のウェブサイトに合わせた情報を入力していきます.
今回は、アカウント名を GitHub Pages の リポジトリに合わせました.
サイト名 や URL は ウェブサイトに合せます.
業種は特に選択する必要はないですが、設定してないと後で設定するようにアラートがでます.
タイムゾーンは日本に合わせ、データ共有設定は初期値のままにしました.

利用規約の確認画面が表示されます. 同意しないと始まりませんが問題があるようでしたら同意せず利用しないという選択になります.
“お住まいの国または地域の利用規約に同意” と あるように、英語で表示されているものを [日本] に 選択しなおし、内容を確認し問題ないようでしたら [同意する] ボタンをクリックします.

Google Analytics の アカウントが作成され、トラッキング ID が 発行されます.
この ID を コピーしておきます.

Hexo Theme Landscape に 設定

Hexo の デフォルト・テーマ Landscape は Google Analytics に 対応しています.
テーマの設定ファイル /[username].github.io/themes/landscape/_config.yml に Google Analytics の トラッキング ID を 設定します.
google_analytics は すでに用意されているので、トラッキング ID を 書くだけの簡単設定です. たすかります!

1
2
# Miscellaneous
google_analytics: UA-7153XXXX-4

※ Hexo の 設定ファイル /[username].github.io/_config.yml と 異なることに注意. ファイル名が同じですがテーマのフォルダの中になります.

いざ確認!

hexo generate して ローカルサーバで動作確認すると、<head> に Google Analytics のためのコードが追加されています.

トラック ID が 正しいことを確認し、hexo deploy で GitHub Pages へ アップします.
Google Analytics の リアルタイム・レポートを見ながら、もう一つのブラウザで本サイトへアクセスすると、アクセス数が表示されます.
うん、自分以外居ない… orz


無事、Google Analytics を 設置することができました.
トラッキング ID の 設定だけで追加してくれるので簡単ですね. 今後テーマを変えることもあるかと思いますが、できるだけ自動でやってくれるものを使いたいものです.

Slack に ボット を 設置する

Slack を CircleCI に 連携した ように、Slack は さまざまなサービスと連携できます. またボットを設置して会話への応答やアクションを実行することも可能です. 最近は Slack の ような チャット・ツールからインフラのオペレーションを実行する ChatOps というキーワードも登場しています.
今回は Slack に 簡単なボットを設置したいと思います.

作業環境

  • Windows 7
  • Node.js 6.9.1 LTS
  • Botkit 0.4.2

Slack の Bots を 作成

まずは Slack に Bots の カスタム連携 を 追加します.
Slack へ ログインし、ボットの追加画面 https://my.slack.com/services/new/bot へ アクセスします.
ボットの名前を入力し、[Add bot integration] ボタンをクリックします. 今回は bot と しました. (ちゃんと名前を付けてあげよう… orz)

ボットが作成されました. 各種設定が行える画面が表示されるので、通知名やアイコンなどを必要に応じて変更します. せっかくのボットなので、ちゃんと名前とアイコンを付けてかわいがりましょう. 変更した際には画面下の [Save Integration] を クリックします.
最後に、API Token を コピーしておきます.

Slack の チャット画面に戻り、ボットが参加するチャンネルを表示し、/invite @[BOT_NAME] と コマンドを実行します. 今回は sandbox チャンネル で /invite @bot と しました.

無事、ボットがチャンネルに参加しました.

Botkit で ボットのプログラムを作成

ボットのプログラムを作成します. Slack の ボット というと、GitHub の Hubot が 有名ですが、開発が止まってしまったようです. 残念…
今回は Slack から 発表 された Howdy の Botkit を 使いたいと思います.

作業ディレクトリを c:\Develop\repos、プロジェクト名 を slack-bot とします. まずは npm init で プロジェクト作成を行います. 基本的にはエンターを押していくだけで問題ありません. license は 公開するならライセンス設定をしますし、今回は特に公開しないので UNLICENSED に しました.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
c:\Develop\repos> mkdir slack-bot
c:\Develop\repos> cd slack-bot
c:\Develop\repos\slack-bot> npm init
name: (slack-bot)
version: (1.0.0)
description:
entry point: (index.js)
test command:
git repository:
keywords:
author:
license: (ISC) UNLICENSED
About to write to c:\Develop\repos\slack-bot\package.json:
{
"name": "test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "UNLICENSED"
}
Is this ok? (yes)

プロジェクト作成後、Botkit を インストールします.

1
c:\Develop\repos\slack-bot> npm install botkit --save

ボットのプログラムを作成します. プロジェクト直下に index.js ファイルを作成します.
まずは基本動作の確認からなので、Botkit の readme.md #Basic Usage になります.

1
2
3
4
5
6
7
8
9
10
const Botkit = require('botkit');
const controller = Botkit.slackbot();
controller.spawn({
token : process.env.token
}).startRTM();
controller.hears('hello', [ 'direct_message', 'direct_mention', 'mention' ], (bot, message) => {
bot.reply(message, 'Hello yourself.');
});

ボットのプログラムができたら起動します.
[API_TOKEN] は Slack からコピーした、ボットの API Token に なります.

1
2
3
4
5
6
7
c:\Develop\repos\slack-bot> set token=[API_TOKEN]
c:\Develop\repos\slack-bot> node index.js
info: ** No persistent storage method specified! Data may be lost when process shuts down.
info: ** Setting up custom handlers for processing Slack messages
info: ** API CALL: https://slack.com/api/rtm.start
notice: ** BOT ID: bot ...attempting to connect to RTM!
notice: RTM websocket opened

Hello ボット!

ボットのプログラムが起動すると、DIRECT MESSAGES の ボットのユーザ名(ここでは bot) の 左のアイコンに色がつき ● になります. 色がない ○ の 場合は接続できていないのでプログラムのログなどを確認し接続できるようにします.
接続できたら @bot hello と、メンション で hello を ボットに送ります.

ボット が Helllo yourself. と 返してくれました!

先ほどのプログラムの以下の部分が会話の処理になります.

1
2
3
controller.hears('hello', [ 'direct_message', 'direct_mention', 'mention' ], (bot, message) => {
bot.reply(message, 'Hello yourself.');
});

controller.hears() の 第1引数で反応するメッセージ、第2引数で聞く(反応する)イベントを指定しています.
今回は hello という 文字列を以下のイベントで待っているという処理になります.

  • direct_message: ダイレクト・メッセージ
  • direct_mention: 名前で始まるメンションのメッセージ (e.g. @bot hello)
  • mention: メンションのメッセージ (e.g. hello @bot)

第3引数 に イベントに対する反応の処理を渡します. bot.reply() なので、今回はメッセージに対して Hello yourself. と 返事をする処理になります.


Botkit を 使うことで、簡単にボットを実装することができました. メッセージ対して返事をするだけでなく、さまざまな処理ができますので、このボットを育てていきたいともいます.

CircleCI の 通知 を Slack へ 送る

CircleCI で ビルドが失敗した際にメールで通知されます. この通知をチャットの Slack へ 流れるようにしたいと思います. 今回は、これまで作成してきた Hexo の 自動ビルドとデプロイが失敗した場合に Slack へ 通知するようにします.

作業環境

  • CircleCI
  • Slack

Slack 側 の 設定

Slack へ ログインし、こちら https://my.slack.com/apps/A0F7VRE7N-circleci から [Install] ボタンをクリックして CircleCI の 連携 を 追加します.
https://my.slack.commy は、それぞれ 自分の Slack へ 行ける 特殊なキーワードなので置き換え不要です. これ便利な機能ですよね!

CircleCI の 通知をポストするチャンネルを選択します. チーム開発などを行っている場合は、開発用のチャンネルへポストするようにします. 今回はブログのビルドとデプロイなので自分のプライベート・チャンネル(DM) へ ポストするようにしました. [Add CircleCI Integration] ボタンをクリックします.

無事、Slack に CircleCI 連携が追加されました. 各種設定が行える画面が表示されるので、通知名やアイコンなどを必要に応じて変更します. 変更した際には画面下の [Save Integration] を クリックします.
最後に、Step 2 に ある Webhook URL を コピーしておきます.

CircleCI 側 の 設定

CircleCI へ ログインし、連携するプロジェクトの設定ボタンをクリックします.

プロジェクトの設定画面の左メニューから [Chat Notifications] を クリックし、右の詳細から [Slack] の [Webhook URL] へ Slack の 設定からコピーした Integration の Webhook URL を 貼り付けます.
必要に応じてオプションを選択し、[& Test Hook] ボタンをクリックします.
今回はチャンネルの上書きは必要ないので [Override room?] を [OFF] にし、ビルドに失敗したときと復旧したときの通知に限りたいので [Fixed/Failed Only] を [ON] に しました.

Slack へ 通知を送るようになったので、メールの通知を止めます.
画面左の全体メニューから 歯車アイコン の [Account Settings] を クリックします.
アカウント設定画面の左メニューから [Notifications] を クリックし、右の詳細から [Don’t send me emails] を クリックします.

Slack に テストの通知が来てる!


これで CircleCI からの通知は、ビルドに失敗&復旧したときだけ Slack の DM へ 流れてくるようになりました.
Slack は いろいろな連携ができるので、引き続きいろいろな挑戦をしたいと思います.

Slack の アカウント作成

これまでのコミュニケーション・ツールはメールが中心でしたが、これからはチャットの時代と言われており、その起爆剤となったのが Slack とも言われています.
Slack を 使って様々なサービスを連携してコミュニケーション基盤を構築したいと思います.

作業環境

  • Slack

Slack とは?

IT 関連企業を中心に流行っているチャット・ツールです.
チャット・ツールはインターネット初期からあり人気を博してきたツールで、ウェブでのコミュニケーションから、企業でのビジネス・ツールとしても様々なツールがありました. 特別新しいものではないのですが、Slack は 登場してから “公開から24時間以内に8000の顧客にサインアップされた - Wikipedia“ とも言われるほどの人気を誇っています.

ソースコードのスニペット(断片)を貼り付けた際にハイライトされることや、マークダウンが使えるなどのエンジニア・フレンドリーであったことや、豊富な外部サービスとの連携が提供されていること、ボットなどで自由にカスタマイズできることなどが人気を得たとも言われています.

長い物には巻かれろ、ではないですが 人気/流行りのツールは情報も多いし、さらなる機能拡張なども期待できることから、しっかり流れに乗っておきたいと思います.

アカウントの作成

Slack の ウェブサイト https://slack.com へ アクセスします.
画面中央 の [Email address] へ サインアップするアカウントのメールアドレスを入力し、[Create New Team] ボタンをクリックします.
ここから入力することは後から変更可能なので思い切ってどんどん進めましょう.

コンファメーション・コードの確認画面が表示されます.
先に入力したメールアドレスへコンファメーション・コードが届いているので入力します.

ユーザ名とアカウントの姓名の入力画面が表示されます. Slack の 利用用途によりニックネームにしておくか本名かなどのルールがあるかと思います. 用途に合わせて入力します.

パスワードの入力画面が表示されます.
珍しく一発勝負のパスワード入力欄です. 間違えてしまったらメールによる再設定ができるので、二回入力させる必要がないのかもしれませんね. とは言え、一発勝負となると途中で間違えてないか、意味もなくドキドキします.

Slack チーム の 用途 と 規模 を 聞かれます. いくつかのチームを作ったことがあり、パターンも異なったのですが、ここでの選択が何かに影響している様子はないのでアンケートでしょうか. 選ばないと進めないので選択します.

グループ名を入力します. Slack では、基本的にチームで呼ばれていますが、なぜかここだけはグループなので気になりますが、チーム名を入力します.

チームのドメイン名の入力画面が表示されます. team.slack.com の スタイルで slack.com の サブドメインになるため、世界で一意になる必要があります. つまり早い者勝ちです. このサブドメインすら後から変更可能です. 自由だ!

サブドメインまで設定できると、最後に利用規約の確認があるので内容を確認し、同意する場合は [I Agree] ボタンをクリックして進めます.

メンバーの招待画面が表示されます. 後で招待もできるので [Skip For Now] ボタンをクリックします.

無事 Slack アカウント と チーム が できました!


Slack は いろいろなサービスと連携できるので、様々な通知を Slack に 集約できるようにしたいですね. またボットを使っていろいろな事もできるので、そちらにも挑戦したいと思います.
まずは、CircleCI の ビルド失敗時に Slack へ 通知できるようにしたいと思います.

CircleCI の 自動ビルド で Hexo の master ブランチをビルドさせない

前回 CircleCI で Hexo の 自動ビルド と デプロイ設定 で GitHub の source ブランチ に プッシュすると CircleCI が 自動的にビルドしてデプロイするようにしました.
これで記事が自動的に公開できるようになったのですが、CircleCI が 記事に使っている master ブランチもビルドしようとしてエラーが発生します. 今回はこのエラーの原因と対策をします. (止めないと記事を公開するたびに、ビルドエラーの通知が来てしまう…)

作業環境

  • CircleCI
  • Hexo 3.2

エラー の 原因

CircleCI の ビルド画面 や、エラー通知のメールを見るとわかりますが [NO TESTS] と なっています. 前回の記事の通り、CircleCI は テストがないとエラーとして扱うためです.
では このエラーはどこから来たのか、これは [master] と 書かれているように、master ブランチをビルドして、テストがないためにエラーとなったものになります.

はて、以下に抜粋した通り circle.yml で ビルドするのは source ブランチに限っているはずです. なぜ master ブランチでビルドが走ってしまったのでしょうか?

1
2
3
4
general:
branches:
only:
- source

原因は、Hexo と GitHub Pages で ブログ環境の構築 で ウェブサイトのソースをコミットする source ブランチを git checkout --orphan source コマンドで作成しているとことにあります.

git checkout --orphan は 親を持たない空のブランチを作成するオプション指定です. これにより mastersource は 関連を持たないブランチとなっています.
その関連のない source ブランチに circle.yml は あるので、mastercircle.yml を 持たない状態になっています. そのため、いくらビルドするブランチから master を 外してもビルドは行われる状況になっていたということになります.

master ブランチをビルドさせない対策検討

原因が分かったので対策に入りたいと思います.

まず浮かぶのは master ブランチ に circle.yml を 置く方法です. この方法だと公開されるウェブサイトにも circle.yml が 配置され公開されることになります. う~ん、いまひとつ…

ではどうするか、Skip a build - CircleCI に 書かれている、コミット・メッセージ に [ci skip] もしくは [skip ci] を 含めるというやり方があります.

この方法だと毎回のコミット・メッセージに [ci skip] を 入れることになりますが、ここのコミット・メッセージは Hexo が 自動で行っているため手間はかかりません.

また コミット・メッセージ に 毎回入れてよいかという観点では、master ブランチは GitHub Pages の ウェブサイト公開用で Hexo で 上書きされ更新履歴のトラックも使っていません.

以上の事から、コミット・メッセージに [ci skip] を いれても問題ないと考えられます.

コミット・メッセージ に [ci skip] を 入れる

Hexo の 設定ファイルである _config.ymldeploy セクション に message を 追加します.
今回はデフォルトのコメントの最後に [ci skip] を 追加する形にしました.
設定の詳細は、こちら Deployment | Hexo に なります.

1
2
3
4
5
deploy:
type: git
repo: git@github.com:[username]/[username].github.io.git
branch: master
message: "Site updated: {{ now('YYYY-MM-DD HH:mm:ss') }} [ci skip]"


以上で master ブランチのビルドを止めることができました.
CircleCI の ビルド・ログ にはスキップしたことが残ってしまいますが、基本的にエラーが発生しない限りは CI の 画面は見ないですし、不要な設定ファイルをウェブサイトのツリーに配置するよりはよいと思うので、まずは形で行こうかなと.
とはいえ、もっと良い方法があるといいのだけど.

CircleCI で Hexo の 自動ビルド と デプロイ設定

CircleCI の アカウント作成 が できたので、ブログ生成に使っている Hexo の 自動ビルドとデプロイができるようします.

作業環境

  • CircleCI
  • Node.js 6.9.1 LTS
  • Hexo 3.2

CircleCI の 設定を追加

ソース・ルート直下に circle.yml を 配置することで CircleCI の 設定を行います.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
general:
branches:
only:
- source
machine:
timezone: Asia/Tokyo
node:
version: 6.9.1
test:
override:
- echo "skip test"
deployment:
deploy:
branch: source
commands:
- git config --global user.name "CircleCI"
- git config --global user.email [your e-mail]
- hexo clean
- hexo generate
- hexo deploy

general - branches - onlysource ブランチだけビルドするようにしています.
指定方法の詳細は、こちらの Specifying branches to build に なります. ビルドするブランチを指定する以外に、特定のブランチを無視したり、正規表現で指定できます.

test - override - echo "skip test" は、CircleCI が テストしないとビルドに失敗するようになっているので、テストがないことをコンソール出力するために設定しています.

git config --global で Git の ユーザ設定を追加します. user.name は CircleCI の ビルドであることが分かるようにしました. user.email は GitHub に 登録している自分のメールアドレスを指定しました.

circle.yml ファイルができたら、GitHub へ コミットしておきます.

CircleCI に リポジトリを追加

CircleCI の プロジェクト追加 ページ へ 行きます.
自分の GitHub アカウントが表示されているのでクリックし、右側のプロジェクト一覧から GitHub Pages の [username].github.io プロジェクト 右 の [Build project] ボタンをクリックします.

自動的にビルドが始まり、ビルド画面へ遷移します. しばらく待っているとビルドが失敗し、レッド の [FAILED] 表示がされます.
これは Hexo の デプロイ で GitHub へのアクセス権がなかったために起こるものなので、SSH キー を 追加します. このあたりの設定は GitHub security and SSH keys - CircleCI に 説明があります.
画面の上部中央にある [Project Settings] を クリックします.

プロジェクト設定画面が表示されるので、左側のメニューを下へスクロールし [Checkout SSH Keys] を クリックします. 右側に設定内容が出てくるので、[Authorize with GitHub] ボタンをクリックします.

GitHub の 画面が表示され、CircleCI へ Public SSH keys の 権限を許可するかを確認されます. 許可しないと始まらないのですが、問題ある場合は ここで止めて CircleCI の 自動デプロイをあきらめます.

上記画面で [Authorize application] ボタンをクリックすると CircleCI の 画面に戻ります.
右側の設定から [Create and add [username] user key] ボタンをクリックし、SSH キー を GitHub へ 追加します.

ボタンをクリックすると設定画面に [[username] user key] が 追加されているのを確認し、画面上部 の [View [username].github.io] リンクをクリックします.

前回のビルドが失敗している履歴が表示されるので、[rebuild] を クリックします.

自動的にビルドが始まり、ビルド画面へ遷移します. しばらく待っていると今度はビルドが成功し、グリーン の [FIXED] が 表示されます.


これで、無事に自動ビルドとデプロイができるようになりました. 以降は source ブランチ へ プッシュするたびに自動でビルドが行われ、デプロイもされるようになります.
ローカルでの確認は必要ですが hexo deploy 無しで、自動的に記事が公開できるので便利ですね.

CircleCI の アカウント作成

継続的インテグレーション(CI: Continuous Integration) の プラットフォームである CircleCI を 使って、GitHub に ある 様々リポジトリをビルドできるようにしたいと思います.
うまく流れるようになると GitHub の 特定のブランチにマージされると、ソースコードのビルと、テスト、パッケージング、デプロイ までの一連の作業が自動的に行われるようになります!
まずはビルドを行う前に、アカウントの作成をします.

作業環境

  • CircleCI

CircleCI とは?

こちらのスライド、はじめての CircleCI が しっかり まとめてくださっており、改めて書くことがないどころか、勉強になりました. 素晴らしいスライドありがとうございます!
ということで、やりたいことに特化してアカウント作成部分だけの記事にしたいと思います.

アカウントの作成

CircleCI の Signup ページ https://circleci.com/signup へ アクセスします.
GitHub と Bitbucket の どちらで認証するか聞かれます. 今回は GitHub を 選択しました.

GitHub の サイトへリダイレクトされますので、GitHub へ サインインします.

CircleCI へ 渡す権限の確認画面が表示されます.
ここで許可しないと次へ進めないのもありますが、CircleCI で Private Repository の ビルドなども行うので妥当な権限と思いますので [Authorize application] を クリックして許可します.
問題がある場合は [Authorize application] を クリックせず、CircleCI の 利用は断念します.

CircleCI へ 戻されます. 無事ログインできました.


GitHub と 連携するだけなので、アカウント作成は簡単にできますね.
この後、まずは Circle CI で Hexo を 動かせるようにして、投稿の編集を GitHub の draft-xxx ブランチで行い、source ブランチ へ マージされたら CircleCI が 回って、自動的にデプロイされるようにしたいと思います.