Martini(+Ginkgo)をWerckerでCIしてHerokuにデプロイ

Martini Demo from Martini on Vimeo.

#117: Go, Martini and Gophercasts with Jeremy Saenz - The Changelog

を聴いていて,Sinatra風のGoの軽量WebフレームワークであるMartiniというのを知った.上に貼ったデモを見るとほとんどSinatraで良い感じ.Goはしばらく触ってなかったし,最近のGo事情を知るためにMartiniを触りつついろいろ試してみた.

あとCIサービスのWerckerも良さそうだなと思いつつ触ってなかったので,この機会に使ってみた.

やってみたのは,

  • [Martini]()で簡単なGo Web Applicationの作成
  • Ginkgoを使ってBDDテスト
  • [Wercker]()でCI
  • Go Heroku buildpackでHerokuにデプロイ

今回のソースコードは全て以下にある

tcnksm/sample-martini

Martini

パッケージをインストールしておく

$ go get github.com/go-martini/martini

例えば,以下のように書ける.ものすごくシンプル.

// server.go
package main

import "github.com/go-martini/martini"

func main() {
    m := martini.Classic()
    m.Get("/", top)
    m.Run()
}

func top(params martini.Params) (int, string) {
    return 200, "Hello!"
}

以下で起動する.

$ go run server.go
$ curl http://localhost:3000
Hello !

codegangsta/ginを使うと更新の度に自動でビルドしなおしてくれるため,ブラウザを更新するだけでよくなる.

$ go get github.com/codegangsta/gin
$ gin run server.go

RackのMiddleware的な書き方もできる.OAuthやセッション機能などのMiddlewareはMartini Contribで別パッケージとして管理されている.

Go Heroku Buildpack

Go用のHerokuのBuildpackは既にある.

kr/heroku-buildpack-go

Herokuアプリを作成する際にこれを指定する.

$ heroku create -b https://github.com/kr/heroku-buildpack-go.git

HerokuでGo Web Applicationを動かすには,Procfileと依存パッケージの管理が必要になる.

Procfile

Herokuにwebプロセスがどのコマンドを叩くかを知らせるためにProcfileを準備する必要がある.

$ echo "web: $(basename `pwd`)" > Procfile

Godep

tools/godepを使うとパッケージの依存関係を管理できる.

$ go get github.com/kr/godep
$ godep save

これで依存関係のリストがGodeps/Godeps.jsonに書き込まれ,Godeps/_workspace以下にソースコードがぶっ込まれる.

デプロイ

あとはいつも通りにデプロイするだけ.

$ git push heroku master

HeokuへのGo Web Applicationのデプロイは“Getting Started with Go on Heroku”が詳しい.

Ginkgo

Ginkgoは,Go用のBDD Testingフレームワーク.MatcherライブラリにはGomegaを使う.

$ go get github.com/onsi/ginkgo/ginkgo
$ go get github.com/onsi/gomega

初期化する.

$ ginkgo bootstrap

例えば,上のMartiniのテストは以下のように書ける.

package main

import (
    . "github.com/onsi/ginkgo"
    . "github.com/onsi/gomega"
)

var _ = Describe("Sample", func() {
    Context("top()", func() {
        It("return 200 Status", func() {
            RequestToRoot("GET", top)
            Expect(recorder.Code).To(Equal(200))
            Expect(recorder.Body).To(ContainSubstring("Hello"))
         })
     })
})

ほとんどRSpecのように書ける.RSpecほどではないが,Matcherも基本的なものは揃っている.

MartiniとGinkgoとの連携は“Getting started with RethinkDB, Ginkgo and Martini on wercker”が詳しい.

Wercker

Werckerの使い方は,“Githubのプライベートリポジトリでも無料で使えるCI,Werckerを使ってrails newからHerokuのデプロイまでやってみる”が詳しい.基本はこの通りにやれば連携可能.

wercker.ymlはレポジトリを登録すると,自動でGo専用のものが生成され,そのまま使える.

テストが通ったらHerokuにデプロイするようにするには,HerokuのApp keyとApplicationを登録し,以下をwercker.ymlに追記するだけ.

...
deploy:
  steps:
      - heroku-deploy

ものすごく簡単.

まとめ

とりあえず,ざっとやりたいことをやってみた.いろいろな言語にあるツールがどんどんGoに移植されてるなーと感じた.また,あらゆる言語のバックグラウンドをもった開発者がGoを触っていて,各言語の良い部分が集約されそうで期待が高まってきた.

さっとつくるときはSinatra使うだろうけど,MartiniでWeb Applicationを書いてみるのは楽しかった.Martiniの作者も話してたけど,バグレポートの際にいろいろ言われつつも良いコメントをもらってるみたいで,多分そういうことなんだろうと思う.

DockerやSerfとかを触っていると,やっぱコードレベルで中身を理解したいので,これを機にもっとGoを書いていこうと思う.

参考