Goツールのリリースにおけるバージョニングについて
Goのツールをリリースする時、個人的には以下のような手順を踏んでいる。もちろんスクリプトで一撃でできるようにはしている。今回は1.の話。セマンティックバージョニングの話は出てきません。
- versionをbumpする
- CHANGELOGを更新する
- 1,2での変更をgitに反映してタグを打つ
- ビルドする
- ビルドをアップロードする
versionは -ldflags
を使って動的に埋め込む方法があるが、最近は明示的にソースコードに書いた方が良いと思うようになってそうしている。
理由としては、ユーザーが go get/build
で実行ファイルを取得した場合でもバージョンは表示されて欲しいというのが一つ。 -ldflags
で実行ファイルに色々な値を埋めることはできますが、基本原則として、それらを埋めてない状態でもちゃんと実行ファイルが正常に動くようにすることを意識した方が良い。
もう一つの理由として、バージョン埋め込み手法として git describe --abbrev=0 --tags
で最新のタグを取得する方法がよく取られるが、これだと「最新のタグ」なので、意図しないタグ(テスト用途で雑に付けたタグとか)で埋められてしまう可能性があるのも困る。
で、最近は実際にどうやっているかというと、 version.go
というファイルを用意して、そこにバージョン関連の情報が記載されるようにしている。ghg だと以下のような具合。
package ghg
const version = "0.1.1"
var revision = "Devel"
version
定数の更新は、 gobump
をリリーススクリプトの中で使っている。例えば、 0.2.0
に更新したい場合は以下のようなコマンドを実行すれば良い。そうすれば自動的に version.go
ファイルが書き換えられる。
% gobump set 0.2.0 -w
gobump
に関しては、作者であるmotemenの gobump で Go プロジェクトのバージョニングをおこなう を参照のこと。
revision
変数はビルド時点のgitのコミットハッシュを埋めるためのものだが、これをきちんと埋めたい場合は -ldflags
で埋める形になる。具体的には以下のようになる。
% go build -ldflags="-X github.com/Songmu/ghg.revision=$(git rev-parse --short HEAD)" ./cmd/ghg
もちろん、これは make build
で実行できるように、 Makefile
に定義してある。
これで、最新の ghg
のバージョンを表示させてみると、以下のようになる。
% ghg version
ghg version: 0.1.1 (rev: 63eb454)
go get
で実行ファイルを取得したり、 -ldflags
を指定せずに go build
した場合は以下のように、"Devel" が表示される。程よい挙動といえるのではないでしょうか。
% ghg version
ghg version: 0.1.1 (rev: Devel)
versionをどのように表示させるのが良いのか
コマンドラインツール全般の話として、バージョンをどのように表示させるのが良いのか最近少し悩んでいる。
-v
とか --version
でバージョン番号出すのあんま良くないんじゃないかと思うことがある。特に -v
は --verbose
と紛らわしいので絶対ダメ。
コマンドラインオプションはあくまで標準の振る舞いを調整するためのものであって、バージョン表示のように全然違う振る舞いをするものはオプションではなくて、サブコマンドでやるべきなのではないか。
確かに、 -h/--help
同様に慣習ではある。GNU Coding Standardのコマンドラインの項目にも以下のように書かれている。
All programs should support two standard options: ‘--version’ and ‘--help’.
ただ、最近のツールだと --version
オプションが用意されているツールも減ってきているようにも感じる。
また、バージョン表記がサブコマンドであれば、オプションで挙動の調整もやりやすい。例えば、 --format
オプションを与えれば、表示方法を切り替えられる、など。バージョン文字列は、人が読みやすい形、機械が読みやすい形、両方で提供できると嬉しいので、このような挙動は嬉しいはず。
% ore-tool version --format=json
{"version":"0.0.1"}
ただ、本当に単機能しか無いコマンドラインツールに、わざわざ version
サブコマンドだけを追加するとなるとやり過ぎ感もありますね。
ちなみに、最近個人で作るツールだと --version
オプションも version
サブコマンドどちらも用意せず、 --help
で表示される内容の中に、バージョン情報を記載するに留めることもあります。
結論として、 version
をサブコマンドで用意するのがやはり良いのではないかという気持ちなのが最近です。 dep
コマンドとかもそうなってますね。
今回はバージョンの話でしたが、Goツールのリリースに関するその他徒然について気が向けば続きを書きます。