Gemのアップデート方法

エンジニアとして働き始めると、学生時代には意識しない問題に取り組むことが多くなります。

ライブラリのアップデートもその中の一つでしょう。RubyのライブラリであるGemをアップデートする方法を学んだので忘れないうちにアウトプットしようと思います。

なぜ、Gemをアップデートする必要があるのか

なぜライブラリをアップデートし続ける必要があるのでしょうか?その理由は、以下のように様々ですが個人としては、最新バージョンはワクワクしながら仕事ができるからだと思います。

  • インシデントが起こり得るセキュリティエラーへの対応
  • 新機能が実装されることで生産性の向上
  • Rubyのバージョンを上げる必要がある

Gemをアップデートする前に

いきなりアップデートをしようとすると失敗しやすいので、事前に考えることを紹介します。

Dependabotで可視化

GitHubでDependabotを利用するとGemアップデートのPullRequest(以降、PRと呼ぶ)を自動で作成してくれます。

利用するGemを限定する

誰も利用していないGemを苦労してアップデートしたくはありません。

Gemfileに追加したGemが本当に必要なのかを洗い出します。

開発やテスト環境のみで利用されるGemのうち、チームが使用していないものから手をつけると良いのではないかと思います。

アップデートする時に考えること

Dependabotで可視化されたアップデートで優先度を決めましょう。

優先度は、多くの要因から総合的な判断で決定します。

  • 深刻度

    • セキュリテイ
    • バグの修正
    • 機能改善
  • 依存の深さ

    • 依存しているGemが少ないほどアップデートはしやすい
  • 差分量

    • メジャー、マイナー、パッチバージョンとバージョンの上がり幅が大きいほど難しい
  • 互換性はあるか

    • deprecatedとなっていたメソッドは要注意

優先度が決まったら、工数を見積もります。

見積もりの判断材料は、以下の通りです。

  • リポジトリの活発さ
  • CHANGELOGの内容
  • 差分コード、該当PRの内容
  • PRを詳細に書く文化があるか
  • アップデートのトリガーとなったPR/issueの内容
  • ユーザーベースの多さ・メジャー度(記事があるかどうか)

実際にアップデートをしてみる

pry-docを0.13.4から1.0.0にアップデートする手順を例に説明します。

GitHubと連携しているCircleCIのRSpecが落ちているので確認すると下記のようなエラーが出力されていました。

NoMethodError: undefined method
 `before_command' for #<Pry::CommandSet:xxxxxxx>

Pry::CommandSetモジュールのbefore_commandメソッドがないようです。

pry-docにbefore_commandがあるを確認すると全ての項目で存在しないことがわかりました。

次に、依存Gemを知るためにgemspecを確認します。

ここで、add_development_dependencyはpry-docを開発する際に必要になるGemなのでadd_dependencyが重要です。s.add_dependency 'pry', "~> 0.11"から、pryというGemが原因のようです。

require './lib/pry-doc/version.rb'

Gem::Specification.new do |s|
  # ...

  s.required_ruby_version = '>= 2.0'

  s.add_dependency 'yard', "~> 0.9.11"
  s.add_dependency 'pry', "~> 0.11"
  s.add_development_dependency 'latest_ruby', '~> 1.0.0'
  s.add_development_dependency 'rspec', '~> 3.5'
  s.add_development_dependency 'rake', "~> 10.0"
end

pryをGitHubページでbefore_commandを確認するとCHANGELOG.mdからDelete Pry::CommandSet#{before,after}_command #1838のPRでRemoveされたことがわかりました。

pry-docpryを同時にアップデートすることが必要そうだとわかりました。

しかし、GitHub上でFiles changedを確認するとpryのバージョンはpry-docと一緒に上がっていることがわかりました。

問題の切り分けを行うために、CircleCIのキャッシュが原因であるかを調べます。

CircleCIのClearing Cacheから、.circleci/config.ymlに記載されているrestore_cacheのkeyオプションのprefixをv1からv2に変更しPushします。

依然として、エラーが出力されました。

NoMethodError: undefined method
  `before_command' for #<Pry::CommandSet:xxxxxxx>

次に、pryに依存している別GemのPRがDependabotにて通知されていたので、該当コミットをgit cherry-pickで取り込んだ後に、RSpecを走らせるとテストが通ることが確認できました。

アップデート作業は終了です。

まとめ

  • Gemのアップデートも普段の業務のようにタスク分解し、PDCAサイクルを回すことで臆せずできる
  • ライブラリのアップデートは、ドキュメントを読み込むので勉強になる
  • 最新のGemに追従しよう