restore_bundled_withを使ってBundlerのBUNDLED WITHをうまく取り扱う

tl;dr

  • Bundler v1.10.0からBUNDLED WITHのsectionが導入された。
  • restore_bundled_withを使うことで、Bundler開発チームの精神を逸脱して(!)、異なるversionのBundlerとBUNDLED WITHをうまく取り扱う。
BUNDLED WITH section
BUNDLED WITHのsectionで差分が出る

Bundler v1.10 とBUNDLED WITH

Bundler v1.10.0からBUNDLED WITHというsectionにbundle updateを実行したBundlerのversionを 記録するようになった。 日本語詳細はこちらが詳しい。 Ruby - BUNDLED WITH で Gemfile.lock が更新されてしまう件 - Qiita

挙動の確認

Bundler v1.10.2でbundle updateして、BUNDLED WITHにversionを記録しておく。

$ cat Gemfile.lock
GEM
  remote: https://rubygems.org/
  specs:
    actionmailer (4.1.11)
      actionpack (= 4.1.11)
(snip)
  unicorn-worker-killer
  webmock

BUNDLED WITH
   1.10.2

Bundler v1.9.9で bundle update

BUNDLED WITHのsectionごと消える。悲しい。

$ bundle update
(update)

$ git diff
(snip)
@@ -289,6 +290,3 @@ DEPENDENCIES
   unicorn
   unicorn-worker-killer
   webmock
-
-BUNDLED WITH
-   1.10.2

Bundler v1.10.4(新しい)で bundle update

BUNDLED WITHの記録を更新する。

$ bundle update
(update)

$ git diff
(snip)
@@ -291,4 +292,4 @@ DEPENDENCIES
   webmock

 BUNDLED WITH
-   1.10.2
+   1.10.4

Bundler v1.10.1(古い)で bundle update

Warning出しつつ、BUNDLED WITHは更新しない。

$ bundle update
Warning: the running version of Bundler is older than the version that created the lockfile.
We suggest you upgrade to the latest version of Bundler by running `gem install bundler`.
(snip)

$ git diff
(no diff)

正しい解

まずは、Bundlerのversionをv1.10系の最新版に上げる。 そして、依存ライブラリのバージョンを上げていくと同時にBundlerも最新版が出るたびに上げていく。

現実解?

  • そうは言っても、localではpreとかv2とか新しすぎるものも使いたい。
  • 実際にproductionで実行するBundlerのversionと離れてしまいかねないのはいつか問題になりそう。
  • Gemfileの中はBundler管轄だけど、Bundler自体はそこで管理してないわけで、lockの記述に引きずられるのはどうなんだろう(私見)
  • minimalなbundlerのmini_bundler(仮)が薄くいて、bundle execなどのコマンドはその内側でバージョン管理されたbundlerで実行すればいい?(私見)

などの理由から、Bundler開発チームの精神を逸脱して(!)、restore_bundled_withというgemのrestore-bundled-withコマンドを使う。

restore_bundled_with

Gemfile.lockのBUNDLED WITHにリポジトリとdiffがある状態で、restore-bundled-withコマンドを実行する。 つまり、bundle updateしたあと、commitする前に、restore-bundled-withする。 すると、リポジトリからBUNDLED WITHのsectionを取り出してきて、そこだけ元に戻る。

Bundler v1.9なら、消えたsectionが戻る。 より新しいBundler v1.10なら、使った記録がそこだけ戻る。

Example

Newer Bundler Case

$ cat Gemfile.lock
(snip)
  unicorn-worker-killer
  webmock

BUNDLED WITH
   1.10.2

Execute bundle update by Bundler v1.10.3.

$ bundle update
(update)

$ git diff
(snip)
@@ -291,4 +296,4 @@ DEPENDENCIES
   webmock

 BUNDLED WITH
-   1.10.2
+   1.10.3

Then, execute restore-bundled-with.

$ restore-bundled-with
(restore BUNDLED WITH section)

$ git diff
(no diff)

There is no diff, because this restores BUNDLED WITH from git repository.

まとめ

Bundler開発チームの精神を逸脱するので、あまり推奨はしない。 最新版を使って、もし壊れていたらみんなで直していくのが、アプリケーションを健全に保つ一番痛みが少ない方法なのです!

詰まったら聞いてください。このサイトやREADMEなどに反映します。 ruby-restore_bundled_withにスターください!


参照