詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

Fork me on GitHub

gobump で Go プロジェクトのバージョニングをおこなう

Go に限らず、公開しているプロジェクトのバージョニングは必要だけれど面倒なタスクのひとつで、プロジェクトのメンテナンスを続けていくつもりがあるのなら、ほぼ必ず通らなければならない道でしょう。ここで話題にしているのは Git などによるソースコードのバージョン管理ではなく、たとえばバージョン 3.1.4 といった、リリースされるソフトウェアの公開バージョンをどう運用するか、という話です。

バイナリとして配布する前提のプロジェクトであればソース中で var version string と宣言した変数に、ビルド時に -ldflags '-X main.Version 3.1.4' などとしてバージョンを設定するという方法もありますが、go get による配布ができるのなら、提供側としては楽ができます。たとえば gore は開発者向けということでバイナリの配布をしていませんが、リリース作業がないとなると意識してバージョンを切るタイミングがないので、ここを自動化したいものです。

幸い Go はソースコードの操作がとても簡単に行えるので、version 変数に代入されている文字列リテラルを書き換える……というようなことの実現もたいした苦労ではありません。

gobump

そこで作ったのが gobump

go get github.com/motemen/gobump/cmd/gobump

Go プロジェクトのワークツリーで、以下のようにして使います:

gobump minor -w

バージョニングが Semantic Versioning に従っている前提で、ソースコード中のバージョン的な(/^version$/i)変数や定数に与えられている値を進めます。第一引数には "major"、"minor"、"patch" を与えることができて、それぞれバージョン番号の対応する箇所をインクリメントさせます。たとえば上の例だと、

package main

const version = "1.2.3"

みたいなコードが

package main

const version = "1.3.0"

に書き換えられる。

-w は gofmt や goimports など標準のツールにおなじみのオプションで、バージョンアップ後のコードを標準出力に印字する代わりに、対象のファイルの内容を書き換えます。 この際 -v オプションを与えると、書き換えられた名前と値が JSON で出力されるので、スクリプトからの利用に便利です。

% gobump minor -w -v
{"version":"1.3.0"}

motemen/gobump · GitHub

これを利用した自動化については後ほど紹介します。2015-08-13: 書きました

Mackerel + peco + zsh でコマンドラインにホスト名を補完する

複数のサーバが関わっている環境では、ホストに人間が分かる名前を関連付けなければ運用がスケールしなくなるものです。その名前はホスト名だったり、ロールやタグのようなものだったりすると思いますが、仮にホスト名を利用するなら、DNS を用いて名前とホスト(の IP アドレス)の対応をつけるようなこともできるでしょう。DNS が利用できない場合は、/etc/hosts に書くというようなのもありですね。

しかしホスト名を直接利用した運用というのは意外と難儀なところがあって、とくに自分のように普段サーバを扱った作業をあまりしないアプリケーションエンジニアなどは、「前に接続したことあるあのホストは何だっけ……」といううろ覚え状態に弱い。名前の一部は覚えているわけなので、シェルの履歴を検索すればなんとかなるのですが、一度も接続したことがなければ目当てのホストを探し出すことはできません(この、接続したことがあるかどうかに確信が持てないのもストレス)。

Mackerel と mkr

さて、Mackerel ははてなが提供するサーバ管理・監視サービスで、私もふだん利用しているものなので、これを使うことを考えます。Mackerel ではサーバはホスト名だけでなくサービス/ロールにひも付きますから、たとえホスト名に意味のある名前をつけない運用であっても、サービスとロール("app" や "db" など)をたどることで目当てのサーバを見つけることができます。この側面を利用すると、とても人間にやさしい。ここで mkr というツールを用いて、関心のあるホストを簡単に見つけられるようにする方法を実現します。

mkr は Mackerel が提供する API の公式クライアントです。Go で実装されていて、go get またはバイナリのダウンロードで利用できます。

go get github.com/mackerelio/mkr

mkr では、

  • Mackerel へのホストの登録(mkr create
  • ホスト情報の更新(mkr update
  • メトリックの投稿(mkr throw
  • ホスト情報の一覧(mkr hosts

などの API がコマンドラインインターフェースで利用できます。基本的には MACKEREL_APIKEY 環境変数に Mackerel の API キーを設定して使いますが、標準的な構成で mackerel-agent を稼働させているホストで実行する場合にはその設定ファイルから API キーやホスト ID を再構成してくれるため、便利なことに追加の設定なしですぐ使えるようです(詳しくは README をご覧ください)。

ここではホスト情報の一覧(mkr hosts)を使うことになりますが、このコマンドには -f オプションが定義されていて、Go の text/template 形式で出力を加工できるようになっているので、これを利用します。

mkr + peco + zsh による実現

f:id:motemen:20150630233012g:plain

上のスクリーンキャストでは Mackerel に登録しているサーバをそのホスト名およびサービス/ロールとともに一覧し、peco であいまい検索を行って、選択したものをコマンドラインに補完する、ということをしています(というのを ^[o にマッピングしている)。コマンドラインには直接 IP アドレスを展開し、末尾にコメントとしてホスト名を記録しているので、シェルの履歴にもコンテキストが残りますね。

これは以下の zsh 関数とシェルスクリプトの組み合わせで実現しています。

complete-mackerel-host-ip

zsh 関数 complete-mackerel-host-ip がキモで、入力中の単語から Mackerel に登録しているホストのあいまい検索を行ない、入力中のバッファに展開します。環境変数を用いず第1引数に API キーを取るようにしているので、環境変数以外の場所でキーを管理しているような場合にもたぶん簡単に使えるはずです。ちなみにあまり用途はないかもしれませんが第2引数には API キーの名前を指定できて、 複数の Mackerel オーガニゼーションを並行して利用している場合にはこれでキャッシュを分離できるようになっています。

ここでは IP アドレス部分のマッチをおこなわないよう指定できる fzf を利用していますが、filter 変数を 'peco' に書き換えることで peco にもすぐ切り替えることができます。

https://gist.github.com/motemen/2b0656be9e2acf32b35d#file-complete-mackerel-host-ip-zsh

mkr-hosts-tsv

これはキャッシュしつつ Mackerel のホストを TSV で一覧するだけのシェルスクリプト。PATH の通るところに置いてください。ここで mkr hosts とその -f オプションを利用していいます。

https://gist.github.com/motemen/2b0656be9e2acf32b35d#file-mkr-hosts-tsv

参考資料

Go Conference 2015 Summer で Go の REPL gore の話をしてきました & gore 0.2.1

去年からこちら Go の話をしたり聞いたりする機会があればぜひ言ってみたいと思っていたのですが、このたび Go Conferecne 2015 Summer の話を聞きつけて、うまいことスピーカー枠に入ることができたので、前に作った Go の REPL(正確には違うんだけど)である motemen/gore の話をしてきました。

speakerdeck.com

gore の紹介は過去のエントリ コード補完もできる Go の REPL「gore」を作った - 詩と創作・思索のひろば にある通りです。今回はその実装に若干立ち入った紹介をしました。

この日のトークは oracle の紹介にはじまり Go の静的解析めいた発表が多く、個人的にはとてもわくわくさせられた内容でした。時間の都合もあって、gore(と go-quickfix)の面白い部分の詳細の話はぜんぜんできなかったので、また別の機会にできればなと思います。しかし今回は思いがけず Gopher 君人形をもらえて本当にうれしかった! 運営のみなさま、楽しいイベントをありがとうございます。

gore 0.2.1

また GoCon 後のテンションで、gore のバージョンをアップデートしました。主な変更は以下のとおりです。

  • -pkg=<path> フラグを追加しました。あたかも特定のパッケージの中にいるかのようにして、gore セッションを開始することができます。
% gore -pkg=github.com/motemen/gore
gore version 0.2.1  :help for help
added file /Users/motemen/dev/go/src/github.com/motemen/gore/commands.go
added file /Users/motemen/dev/go/src/github.com/motemen/gore/complete.go
added file /Users/motemen/dev/go/src/github.com/motemen/gore/liner.go
added file /Users/motemen/dev/go/src/github.com/motemen/gore/log.go
added file /Users/motemen/dev/go/src/github.com/motemen/gore/main.go
added file /Users/motemen/dev/go/src/github.com/motemen/gore/node.go
added file /Users/motemen/dev/go/src/github.com/motemen/gore/quickfix.go
added file /Users/motemen/dev/go/src/github.com/motemen/gore/terminal_unix.go
added file /Users/motemen/dev/go/src/github.com/motemen/gore/utils.go
gore> version
"0.2.1"

ここでは version 定数 が評価されています。

ちなみに -pkg の指定にはパッケージのパスのほか、ディレクトリを指定することもできます。

  • 内部で motemen/go-quickfix を使うようにしました。これは GoCon の仕込み的な変更です。何か変なことがあった場合には GitHub Issues 経由でお知らせください。
  • ある形の式を評価するとエラーが発生していた件を修正しました。(#21

アップデートは以下のようにして行えます。(開発者向けのツールなのでバイナリの配布はしていません)

% go get -u github.com/motemen/gore

はてなで一緒に働きませんか?