先日の goreleaserを使ってGoで書いたツールのバイナリをGithub Releasesで配布する - $shibayu36->blog; で、Goツールのバイナリ配布ができるようになった。しかし、アーカイブ周りの処理が少し期待と違い、作成したzipをunzipコマンドで取り出すとファイルのアクセス権がおかしくなり、バイナリに実行権限がつかなくなるという問題が起こった。これは困る。
goreleaserを深追いをしても良いけど、ひとまず別の方法も試してみようと思って、goxc + ghrを使うようにしてみた。これがうまくいったので、メモしておく。
今回のコードは以下のところで確認できる。
バイナリをリリースする作戦
バイナリをリリースする方法はいろいろあるが、今回はgoxc と ghr を使うことにした。
goxcはクロスコンパイル、アーカイブ、リリースなどなんでもできるツール。使い方はgoxc -help
と https://github.com/laher/goxc/wiki を見るのが良いだろう。ghrはGithub Releasesへのリリースを行うツール。使い方は 高速に自作パッケージをGithubにリリースするghrというツールをつくった | SOTA が詳しい。
goxcを使えばGithub Releasesにリリースするまで一気通貫で出来るはずなのだが、ghrが非常に便利なので、以下のような使い分けをすることにした。
こうしておけば、例えばGithub Releasesじゃないところにアップロードしたくなったとしても、ghrの部分を置き換えれば良いだけになる。
goxcとghrをインストールする
先にgo getでインストールしておく。
$ go get -v -u github.com/laher/goxc $ go get -v -u github.com/tcnksm/ghr
goxcで成果物を作成する
まずgoxcで成果物を作成する設定を行う。
作りたい成果物
作りたい成果物は以下のようなものとする。
.goxc.jsonで成果物作成ルールを作る
以上の成果物を作るには、.goxc.jsonを作り、成果物作成ルールを作っておくと良い。
まず、コマンドから雛形を作る。-wcコマンドを使うと、コマンド引数を考慮した.goxc.jsonを作ってくれる。
$ goxc -os="linux darwin windows" -arch="386 amd64" -d=dist -tasks="clean-destination,xc,archive-zip,rmbin" -wc # -osでビルドするOSを、-archでビルドするArchを設定 # -dで成果物配置場所を指定 # それぞれのタスクは # - clean-distinationは成果物を配置するディレクトリを先にrmするタスク # - xcはクロスコンパイルするタスク # - archive-zipは成果物をzip圧縮するタスク # - rmbinは成果物ディレクトリからバイナリを消すタスク # - zip内に既にバイナリが入っているため消して良い # 最後に-wcで引数の設定で設定ファイルに書き出し
すると以下のような設定ができる。
{ "ArtifactsDest": "dist", "Tasks": [ "clean-destination", "xc", "archive-zip", "rmbin" ], "Arch": "386 amd64", "Os": "linux darwin windows", "ConfigVersion": "0.9" }
しかし、archive-zipというタスクはデフォルトだとlinuxの成果物をzip圧縮してくれない。このままだとうまくいかない。
これをなんとかするために、goxc -help archive-zip
でarchive-zipのヘルプを見てみると、platformsというオプションでどのプラットフォームをzip圧縮するか設定できることが分かった。また、include-top-level-dirというオプションで、ディレクトリごとzipで固めるかを設定できた。そこで、.goxc.jsonを書き換えて以下のように変更する。
{ "ArtifactsDest": "dist", "Tasks": [ "clean-destination", "xc", "archive-zip", "rmbin" ], "TaskSettings": { "archive-zip": { "include-top-level-dir": "windows darwin linux", "platforms": "windows darwin linux" } }, "Arch": "386 amd64", "Os": "linux darwin windows", "ConfigVersion": "0.9" }
あとはREADME.mdとLICENSEファイルをzipに含める設定だが、goxcはデフォルトでINSTALL*,README*,LICENSE*
というルールのファイルをアーカイブに含めてくれるため、明示的に設定しなくても良い。
成果物を生成する
あとはgoxcコマンドを打つだけ。
$ goxc $ tree dist dist └── snapshot ├── shibayu36_darwin_386.zip ├── shibayu36_darwin_amd64.zip ├── shibayu36_linux_386.zip ├── shibayu36_linux_amd64.zip ├── shibayu36_windows_386.zip └── shibayu36_windows_amd64.zip $ unzip dist/snapshot/shibayu36_darwin_amd64.zip Archive: dist/snapshot/shibayu36_darwin_amd64.zip inflating: shibayu36_darwin_amd64/shibayu36 inflating: shibayu36_darwin_amd64/README.md inflating: shibayu36_darwin_amd64/LICENSE $ ls -l shibayu36_darwin_amd64 total 7120 -rw-r--r-- 1 shibayu36 staff 560 Oct 8 17:30 LICENSE -rw-r--r-- 1 shibayu36 staff 400 Oct 8 17:30 README.md -rwxr-xr-x 1 shibayu36 staff 3637000 Oct 9 01:11 shibayu36
期待通りに成果物が作成できた。
ghrでGithub Releasesに成果物をアップロードする
あとはこのdist/snapshot/以下に存在するファイルをすべてGithub Releasesにアップロードすれば良い。これはghrを使えば簡単に行える。
例えば、shibayu36ユーザのshibayu36レポジトリに、v0.0.7というリリースタグ名でdist/snapshot/以下のファイルをアップロードするには、以下のようなコマンドを発行するだけで良い。
$ GITHUB_TOKEN=... ghr -u shibayu36 -r shibayu36 v0.0.7 dist/snapshot/
あとは、goxcして、一番最新のgitのタグ名を使ってghrで上げるというスクリプトを用意しておけば、簡単にリリースができるようになる。次のとおり。
script/release
#!/bin/sh # Usage: GITHUB_TOKEN=... script/release set -e latest_tag=$(git describe --abbrev=0 --tags) goxc ghr -u shibayu36 -r shibayu36 $latest_tag dist/snapshot/
これで手元からクロスコンパイルしてGithub Releasesにアップロードするには、タグを打ってscript/releaseすれば良いだけとなった。
$ git tag vx.y.z
$ GITHUB_TOKEN=... script/release
TravisCIを使い自動で成果物をアップロードする
これまででとりあえずやりたいことはできた。しかし、やはりTravisCIで自動で成果物生成とアップロードを行えるようにしておきたい。
これまでの設定と簡単なMakefileさえあれば、非常に簡単に設定できる。
setup: go get -v -u \ github.com/Masterminds/glide \ github.com/laher/goxc \ github.com/tcnksm/ghr deps: setup glide install test: deps go test -v $$(glide novendor) .PHONY: setup deps test
.travis.yml
language: go go: - 1.9 script: - make test after_success: - test -n "$TRAVIS_TAG" && script/release
GITHUB_TOKEN環境変数も指定する必要はあるので、それは https://docs.travis-ci.com/user/environment-variables/#Defining-Variables-in-Repository-Settings あたりを見ながらTravisCI側で設定したら良い。
これでタグをpushした時にのみ、TravisCIでscript/releaseが動き、成果物生成からGithub Releasesへのアップロードまで自動で行われるようになった。自分がやるのはタグ付けだけとなる。
$ git tag vx.y.z
$ git push --tags
便利!!
まとめ
http://blog.shibayu36.org/entry/2017/10/04/193000 でgoreleaserを使ってみたのだけど、一部期待通りにならないことがあったので、今回はgoxc + ghrという作戦でGoツールのバイナリのリリースを試してみた。とりあえずこれでやりたいことは出来るようになったので満足。
参考
- goreleaserを使ってGoで書いたツールのバイナリをGithub Releasesで配布する - $shibayu36->blog;
- https://github.com/shibayu36/shibayu36/tree/v0.0.7
- https://github.com/shibayu36/shibayu36/pull/1
- https://github.com/laher/goxc
- https://github.com/tcnksm/ghr
- https://docs.travis-ci.com/user/environment-variables/#Defining-Variables-in-Repository-Settings