Travis-CIで最強のデプロイ環境を構築する

  • 39
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

※この記事はTSG Advent Calendarの1日目の記事です。

こんにちは。知らない人は知らないhakatashiです。今年もAdvent Calendarギリギリ投稿となりました。申し訳ねぇ申し訳ねぇ。

よく知られている通り、怠惰はプログラマの三大美徳のうちの一つと言われています(ギリギリ投稿の言い訳ではない)。つい先日もあらゆる行動を自動化したというハッカーの実話に基づいたHacker Scriptsが話題を博しましたが、この手のオートメーションはあらゆるプログラマの魂の源泉であるはずです。OSSにおける自動化といえばTravis-CI。今回はTravis-CIを百二十分に活用するテクニックを紹介します。

あらまし

きっかけはGitHub上でsugoi-converterというプロジェクトをオープンソースで開発し始めたことです。

これはGitHub Pages上でホストされるオンラインツールで、あらゆるオンライン変換ツールを過去にするためのコンバーターです。百聞は一見に如かず。12月1日現在のサイトの見た目は次のようになっています。

Screen Shot 2015-12-01 at 22.36.39.png

これでだいたい分かると思いますが、これはテキストエリアに文字列を入力するだけで、メジャーどころからイロモノまで、あらゆるデータ変換を行ってくれるツールです。最大の特徴は、キーを叩くそばから全てのフォーマットに全自動で変換してくれること。怠惰なプログラマに変換ボタンを押す体力なんてありません。あらゆる無駄を省いたエコロジカルな設計が売りです。あとレスポンシブです(いまどき自慢にもならない)。「それシェル芸でできるよ」と言われてもめげません。スマホで使えることはあらゆる機能に優先すると思います。

メインの開発はmasterブランチ、サイトはGitHub Pagesでホストしているので、gh-pagesブランチにビルドされたファイルが置かれています。

さて、僕は最近のOSS開発ではもれなくTravis-CIを導入しているので、このプロジェクトでもTravis-CIをセットアップしました。するとどうなったか。

hakatashiがこのプロジェクトのmasterにpushしたら何が起きるか

  1. 複数のnode.jsバージョンでJS, CSS, HTMLのビルドを実行する
  2. 複数のnode.jsバージョンでPhantomJSを用いたユニットテストを実行する
  3. テストのカバレッジを測定し、Coverallsに投げる
  4. 以上が通ったら、masterブランチをgh-pagesブランチにマージする
  5. リリース用にminifyしたJSとCSSとHTMLをビルドする
  6. パッケージのバージョンを上げる(同時にgh-pagesブランチにビルドしたファイルがコミットされる)
  7. gh-pagesブランチをGitHubにpushする
  8. ビルドされたファイルのサイズを測り、Googleスプレッドシートに記録する(ファイルサイズの履歴がグラフ化される)
  9. ビルド結果を専用のTwitterアカウントからツイートする

ただの変換ツールに対して明らかにやり過ぎです。しかしどれもやろうと思えばできることばかりなので、そんなに難しくはありません。自動化しようと思えばこれだけ便利になるよという参考になればありがたいです。

ただ、これを実装する上でいくつかつまづいた点があるので、1つ1つ解説していきます。

複数のnode.jsバージョンでビルド/ユニットテストを実行する

難しくありません。Travis-CIを活用するJSerなら日常茶飯事です。解説した記事はいくらでもあるので探してみてください。

読んでないけど↓みたいなブログ記事が参考になると思います。

テストのカバレッジを測定し、Coverallsに投げる

ちょっと厄介です。個人的な印象ですがnode.jsのカバレッジツールはこれというものがなくて、今回はたまたま見つけたMochify.jsというツールを使ってユニットテストと同じコードで行っています。

しかし、生成されたカバレッジを見てみると、何やらSourceMapがずれているような……機会を見て直します。

これ以降の作業はデプロイ用のシェルスクリプトから実行されます。

masterブランチをgh-pagesブランチにマージする

大きな落とし穴です。Travis-CIでcloneされるリポジトリは、--depthオプションをつけてcloneされたsingle branchのshallow repositoryになっています。実質masterブランチしか存在しないので、当然mergeなどできません。これをfull cloneのリポジトリにするには、以下のコマンドを実行する必要があります。(git 1.8.3以降)

git config remote.origin.fetch "+refs/heads/*:refs/remotes/origin/*"
git fetch --unshallow

参考: git - Convert shallow clone to full clone - Stack Overflow

また、可能な限りconflictが起きないように以下のようなコマンドオプションでマージを実行します。

git merge -X theirs "$TRAVIS_COMMIT" --no-edit

リリース用にminifyしたJSとCSSとHTMLをビルドする

特に難しくありません。僕の場合、前述のユニットテストも含めてGulpでビルドしているので、このコマンドを叩くだけです。

一つ注意しておくと、シェルスクリプトから叩く場合はnpm run scriptのようにローカルでインストールしたnpmモジュールのコマンドは使えないので、以下のようにしましょう。

`npm bin`/gulp

パッケージのバージョンを上げる

npmにはnpm versionという便利なコマンドがあり、このコマンド一発で、

  • package.jsonのバージョンを1つ上げ、(major, minor, patchでどの番号を上げるか指定できる)
  • npm run versionコマンドを実行し、
  • リポジトリにコミットして、
  • 該当のバージョン名でタグ付けしてくれる

という至れり尽くせりのコマンドで、まさしくこれを実行するだけです。

gh-pagesブランチをGitHubにpushする

外部からGitHubのリポジトリにpushするためには、アクセストークンを発行する必要があります。やり方はググってください。

万が一にもトークンが漏れないよう、出力はリダイレクトして/dev/null送りの刑にしましょう。

git push "https://${GH_TOKEN}@github.com/hakatashi/sugoi-converter.git" gh-pages:gh-pages --follow-tags > /dev/null 2>&1

ビルドされたファイルのサイズを測り、Googleスプレッドシートに記録する

ファイルサイズを測るのはまさしくシェル芸でやれば済むことです。今回はawkで処理しました。

問題はGoogleスプレッドシートへのアクセスです。本来は滅茶苦茶面倒くさい作業ですが、大丈夫です。それIFTTTでできるよ。

IFTTT Makerをトリガーとして使えば、簡単なPOSTリクエストを送るだけであらゆるDIYなIFTTTレシピを作成することができます。もちろんGoogleスプレッドシートも例に漏れません。

↓こんなレシピを作って……

2015-12-01 23_40_57-MouseGestureL.ahk.png

以下のようにcurlコマンドを叩けば、これだけでGoogleスプレッドシートに1行ずつ記録されます。GoogleのAPI Docとにらめっこしないといけなかった時代とは大違いです。

curl -X POST -H "Content-Type: application/json" -k -s \
-d "{\"value1\":\"${TRAVIS_BUILD_NUMBER}\",\"value2\":\"${FILE_SIZE}\",\"value3\":\"${JS_SIZE}\"}" \
"https://maker.ifttt.com/trigger/travis-sugoi-converter/with/key/${IFTTT_TOKEN}"

2015-12-01 23_48_26-MouseGestureL.ahk.png

jQueryからより軽量なZepto.jsに移行した段階で大きくファイルサイズが削減されているのがわかります。

ビルド結果を専用のTwitterアカウントからツイートする

Travis-CIから自前の通知用nodeアプリにwebhookを投げています。愚直にやってるだけなので特にセンセーショナルな部分はありません。

まとめ

どうでしょうか。1つ1つの手順は大したことがないかもしれませんが、このように発想次第でTravis-CIは思ったより自由に遊べます。これをきっかけにあなたもTravis-CIを最大限に活用してみましょう。