おそらくはそれさえも平凡な日々

GoツールのリリースにおけるバージョニングについてAdd Star

Goのツールをリリースする時、個人的には以下のような手順を踏んでいる。もちろんスクリプトで一撃でできるようにはしている。今回は1.の話。セマンティックバージョニングの話は出てきません。

  1. versionをbumpする
  2. CHANGELOGを更新する
  3. 1,2での変更をgitに反映する
  4. ビルドする
  5. ビルドをアップロードする

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ツールのリリースに関するその他徒然について気が向けば続きを書きます。

created at
last modified at