Posted at

【曲芸】社内向けツールをGemで、Gem Serverなし・バージョンつきで配布する方法

More than 3 years have passed since last update.

実用性はともかく曲芸として個人的に面白かったので共有しておきます。

社内向けのツール、その名もtoolsを下記のような要件で配布したくなりました。


  • CLI

  • gemとして配布

  • gem server無し

  • バージョンを表示できる

まず、



  • gemとして配布

  • gem server無し


これは https://github.com/rdp/specific_install を使うとできる。

$ gem install specific_install

$ gem install git@github.com:your-company/tools.git

次に



  • バージョンを表示できる


これを実現するにはいくつか課題がある。



  • Tools::VERSIONを更新する


    • どうせ頻繁に更新されるんだし、いちいちインクリメントするのが面倒くさい。絶対忘れる。



  • Gitのcommit hashを出力する


    • 当然コミット毎に一意に定まるので頻繁に更新されるツールのバージョニングとしては悪くない。


    • $ tools --sha$ git log --pretty="%h" -1の結果を出せばいいのでは?

    • gemはtools.pkgにファイルをまとめた形で配布される。これはGitリポジトリではないので、gitコマンドは使えない。



ということで、試行錯誤の末、gemspecの中でTools::VERSIONにcommit hashを文字列リテラルとして更新するコードを生成するという方法で実現しました。gemspecはRubyのDSLとして実行されるので、その途中でファイルを書くことは可能なのです。

さらに、specific_installは一時ディレクトリでgit clone してrake installしているので、gitコマンドが使える。

下記、具体的な手順です。

元となるファイルはこんな感じでコミットしておく。

lib/tools/sha.rb

module Tools

SHA = "undefined"
end

tools.gemspec

Gem::Specification.new do |spec|

# Update sha.rb
sha = `git log --pretty="%h" -1`.chomp

sha_rb = <<SHA
module Tools
SHA = "
#{sha}"
end
SHA
File.open(File.expand_path('./lib/tools/sha.rb'), 'w') { |f| f << sha_rb }

# 以下略

これで$ gem build tools.gemspecすると

module Tools

SHA = "cd570fa"
end

というふうに最新のcommit hashを代入するコードが生成され、それがGemとしてパッケージングされる。

バージョンを表示するには、このTools::SHA を適宜出力すればよい。

以上です。もうちょっとまともな方法がある気がするので、妙案があれば是非教えてください。