はじめに
最近副業で Ruby version up 業を行いました。(2.7 -> 3.0 -> 3.1)
本業の方でも古い Ruby を使っており EOL が近づいたら version up を行うという方針だったのですが、
EOL が来たらあげるんじゃなくてこういうルールで上げていきましょうという日本語を書いて共有したらやっていくことになった。
それで、僕はもう version up 業ができるので本業の方でも僕が作業してもあまり得られるものがないので、
それならば別の誰かに作業して貰う方がその人の成長に寄与するのでは?と思ったので他の誰かに任せることにした。(予想以上に手を上げてくれる人がいた)
その為、これまで僕がどのように Ruby の version up 業を行なってきたか?をメモって公開することにした。(特に社内限定である意味がないので)
ちなみに Ruby は 1.9 から使い始めて 3.1 までの version の version up は全て対応したことがあります。
前提条件
前提として以下の状態であること。
実際の作業
0. 方針を決める
事前に決めておいた方がいいのは deprecation warning をどうするか?という点です。
リリース前に対応するのか?リリース後に対応するのか?次の version にあげる際に対応するのか?あたりになると思います。
チームで話し合って決めるのが良いと思います。
僕はリリース前に対応するのが好みです。
1. Release Note を見る
例えば Ruby 3.0 の場合は下記のページ
www.ruby-lang.org
release note を眺めてざっとどんな変更があったか?を脳内に記憶しておくと脳内に index が作られて後々エラーなどが発生した場合に原因の追求が楽になります。
2. 開発環境の Ruby を version up 後の version にする
docker 上で動かしている場合は Dockerfile 等に書いてある Ruby の version を変えたり
local の PC 上で動かしている場合は rbenv install x.x.x や .ruby-version を変えて rbenv install したりしてあげようとしている version の Ruby を install します。
3. 必要な gem を入れる
Rails の application は Gemfile で管理されているはずなので bundle install を行うだけです。
この段階で gem によっては RUBY_VERSION を見ており install が失敗する可能性があります。その場合は該当の gem に対応 PR を送っておきましょう。
4. rails が起動するか確認
まずは bundle exec rails c で rails console を立ち上げてみてまともに起動するか?というのをみます。(別に s で server 立ち上げでも問題ないです)
ここで立ち上がらない場合は表示されている error log から原因を探っていきます。原因に関しては個々の application や環境で異なってくるので対応方法は個別に判断しましょう
5. CI で動いている Ruby version を変える
続いて CI を通すために CI 上で使っている Ruby の version を変更します。
GitHub Actions なら .github/workflows/*.yml
CircleCi なら .circleci/config.yml
上記あたりで使用している Ruby の image の version を変更しましょう。
僕が担当していたサービスでは CI 上で Ruby 2.7 を使っているつもりだったのに実は CI 上は Ruby 2.6 が動いていたという問題があったために下記のように Ruby version をチェックする spec を書いていたりしました。
describe RUBY_VERSION do it { expect(RUBY_VERSION).to eq('2.7.0') } end
6. CI を全て通す
5 の対応で CI 上で version up 後の Ruby が動くようになるはずなのであとは落ちる test をひたすら修正していきます。
7. 不安であれば動作確認も行う
CI を全て通すことに成功したのちまだちゃんと動くか?というのが不安であれば開発環境にて動作確認を行うのも良いでしょう。
8. version up 前の Ruby でも問題ない変更の場合は事前にリリースを行う
例えば Ruby 3.0 では keyword arguments の非互換性な変更があります。
しかしこれらの変更に関しては Ruby 2.7 の段階で対応していても何ら問題ない場合がほとんどになるので事前に対応して Ruby2.7 の段階でリリースを済ませておくと良いでしょう。
メリットとしては下記のようなものがあります。
- version up 時の Pull Request の差分を少なくできる
- レビュワーの負担軽減
- version up 前に問題ないコードだという安心を得られる
- version up 後にもし問題が起きた場合の原因特定が容易になる
9. version up の Pull Request を作成する
8 を行なったことで Pull Request の差分も最小のものになりレビューもスムーズに終わるはずです。
10. 本番などの環境の Ruby を管理している file なども変更する
これは個々の環境よりますが、開発環境と同じ Dockerfile を使って動いている場合は変更しなくても 9 のものをリリースすれば勝手に変更になります。
本番などが別の Dockerfile なりプロビジョニングツールなりで管理されていた場合はそちらに変更の PR を送るなどを行なってください。
11. リリース
staging 環境などがある場合に動作確認をしたいなどのパターンはあると思いますのでチームの方針によって行なって貰いますが、残りはリリースするだけになります。
エラーが発生しやすいパターン
上記のように作業進めていく中でいくつかエラーが発生しやすいパターンがあるので軽く触れていきます
default gem になるなどして使用していた gem がなくなる
Ruby 本体に含まれなくなっただけで、実際には無くなっておらず Gemfile に追記して gem を引き続き使用することが可能です
非互換性な変更によるエラー
先で紹介した keyword arguments の変更など非互換性な変更によりエラーが発生することが稀に存在します。
Release Note を読んだりすればどのような変更を行えばエラーを解消できるか?は書いてあります。
gem が対応していない
Ruby 3.0 のように非互換性の変更がある場合は特に多いのですが、使っている gem が使いたい version の Ruby にまだ対応していないことがあります。
その場合はその gem に対応するための Pull Request を送ってみましょう。
既にその gem の更新が止まってしまっており Pull Request が取り込まれなさそうな場合は、代替えの gem を探す/fork したものをメンテする/独自に実装する/軽微なものなら monkey patch を当てる等の方法を取る必要があります。どの方針を選ぶかはチームで話し合って決めるのが良いでしょう。