golangで作ったツールをリリースするときにはだいたい以下のような作業をすることになります。
- 依存ライブラリをダウンロード(golang/depやMasterminds/glideなどが便利)
- 様々なプラットフォーム用にビルド(mitchellh/gox / laher/goxc / Songmu/goxz)
- ビルドしたバイナリを圧縮(laher/goxc / Songmu/goxz)
- バージョンをインクリメント(motemen/gobump)
- CHANGELOGをアップデート(Songmu/ghch)
- GitHub Releaseへバイナリをアップロード(tcnksm/ghr)
先人の様々なツールによってgolang製ツールのリリースが成り立っていることがわかりますね。
このような環境セットアップやリリースを誰でも簡単に行えるようにするため、多くのgolangプロジェクトではMakefileが書かれます。(と、みんなのGo言語に書かれていました)
また、最近のCIサービスではDocker Imageを利用することが多いため、一連の処理がコンテナ上で動くようになっていると、ローカルとCIで同じ環境を利用できて便利です。
そこで、既存のgolangプロジェクトに、コンテナ上でのビルド/リリース環境を簡単に準備するためのDocker Imageを作りました。
mpppk/gored: release engineering (via docker) tool for golang project
使い方
以下のコマンドを実行します。
$ cd gopath/src/github.com/yourname/yourrepo
$ docker run -v $(pwd):/init mpppk/gored # リリースに必要なファイル群を生成
$ docker-compose run bump-and-commit # バージョンとCHANGELOGを更新してgit push
$ docker-compose run release # ビルドしたバイナリをGitHub reelasesへアップロード
実行したあとにリポジトリを見てみると、releaseされていることがわかります。
すごい!かんたん!!
何が起きているのか
まず1行目のdocker run -v $(pwd):/init mpppk/gored
は、実行すると以下のファイルが生成されます。
docker-compose.yml
Makefile
.circleci/config.yml
(既にこれらのファイルが存在する場合はgored
と言うsuffix付きで生成します)
デフォルトではビルドパスやバージョン番号が含まれたgoファイルのパスはカレントディレクトリを参照します。変更する場合は--build-path
や--version-path
を利用してください。
$ docker run -v $(pwd):/init mpppk/gored gored init --build-path [build path] --version-path [version path]
毎回これを打つのがめんどくさい場合は、シングルバイナリ版をお使い頂くと多少マシになります。
$ go get github.com/mpppk/gored
$ gored init --build-path [build path] --version-path [version path]
次にdocker-compose run bump-and-commit
とrelease
です。
実際とは少し違いますが、生成されたdocker-compose.yml
のbump-and-commit
とrelease
はそれぞれ以下のような内容になっています。
bump-and-commit: &bump-and-commit
image: mpppk/gored
volumes:
- $PWD:/go/src/github.com/yourname/yourrepo
environment:
GITHUB_TOKEN: $GITHUB_TOKEN
working_dir: /go/src/github.com/yourname/yourrepo
command: make bump-and-commit -f Makefile
release:
<<: *bump-and-commit
command: make release -f Makefile
それぞれMakefile
の同名ターゲットを実行していますね。
ではMakefile
を見てみます。
(略)
deps:
dep ensure
bump-and-commit: deps test
gobump patch -w $(BUILD_PATH)
ghch -w -N v`gobump show -r $(BUILD_PATH)`
git add CHANGELOG.md
git commit -am "Checking in changes prior to tagging of version v`gobump show -r $(BUILD_PATH)` [skip ci]"
git tag `gobump show -r $(BUILD_PATH)`
git push "https://$(GITHUB_TOKEN)@github.com/$(REPO_OWNER)/$(REPO_NAME)" HEAD:master
crossbuild: deps test
goxz -pv=v`gobump show -r $(BUILD_PATH)` -d=./dist/v`gobump show -r $(BUILD_PATH)` $(BUILD_PATH)
release: crossbuild
ghr --username $(REPO_OWNER) `gobump show -r $(BUILD_PATH)` dist/v`gobump show -r $(BUILD_PATH)`
(略)
bump-and-commit
では、以下の処理が行われます。
-
deps
ターゲットで依存ライブラリをダウンロード - gobumpでバージョンをpatchインクリメントして
git add
- 例えばソースコード中の
const version = "0.0.1"
がconst version = "0.0.2"
に書き換わります。
- 例えばソースコード中の
- ghchでCHANGELOG.mdを更新して
git add
-
git commit
してバージョンタグを打ってgit push
release
では以下の処理が行われます。
-
crossbuild
ターゲットで、goxzによりwindows, mac, linux用のバイナリを生成 - ghrでreleaseにバイナリをアップロード
以上の処理がdocker-compose.yml
によりカレントディレクトリをマウントした状態でmpppk/gored
コンテナ上で実行されます。
mpppk/gored
イメージには既にgobump
やghr
などのツールがインストール済みなので、別途インストールする必要はありません。
CI
上記まででコンテナ上でのリリースができるようになっているため、Docker Imageを利用するCIサービスだと大体自動リリースもシュッと実現できると思います。
goredではCircle CIを特に優遇しており、設定ファイルである.circleci/config.yml
を一緒に生成するので、これをコミットしておくと次からはPRのマージ時に自動でリリースされます。
version: 2
jobs:
build: &build
docker:
- image: mpppk/gored
working_directory: /go/src/github.com/yourname/yourproject
steps:
- checkout
- run: make test
release:
<<: *build
steps:
- checkout
- run: make bump-and-commit
- run: make release
workflows:
version: 2
build_and_release:
jobs:
- build
- release:
requires:
- build
filters:
branches:
only: master
こんな感じで、masterにpushされた時だけrelease jobが走ります。
注意点として、release時のcommit messageの末尾には必ず[skip ci]
という文字列を含めておいてください。
これがないとrelease時のpushをtriggerにまたCircle CIが走り始めるので、無限にリリースが行われ続けます。(これに気付かずうっかりv0.0.1
からv0.0.804
まで一瞬でリリースされました)
workflowの変更
このようにリリース作業に必要なファイルを自動生成してくれるgoredですが、実際にはworkflowを一部変更したいことがあると思います。この場合は生成されたMakefileを編集してください。
例えばデフォルトのMakefileでは依存ライブラリの解決にdepを使いますが、代わりにglideを使いたい場合は、deps
ターゲットを以下のように変更してください。
(略)
deps:
glide install
(略)
その他、mpppk/gored
イメージに含まれていないツールを使いたい場合、とりあえずMakefileに書いちゃってもいいですが、毎回go get
するのが気になる場合は以下のような自前のDockerfileを書いた方が良いかもしれません。
(略)
setup:
go get ${u} github.com/golang/dep/cmd/dep
...(追加したいpackageを書く)
(略)
FROM golang:1.9.2 AS builder
COPY Makefile /go/src/github.com/yourname/yourrepo/Makefile
WORKDIR /go/src/github.com/yourname/yourrepo
RUN make setup
FROM circleci/golang:1.9.2
COPY --from=builder /go/bin/* /go/bin/
RUN git config --global user.email "gored-bot@dammy.com"
RUN git config --global user.name "gored-bot"
というわけで、お手軽に自動リリース環境を構築するgoredの紹介でした。ご興味あれば使ってみてください!