kaeruspoon

rubyにコントリビュートする方法

76de73a1dae79a86bb99a813bd8e8e0a?s=30&d=http%3a%2f%2fkaeruspoon%.net2f2014%2fimages%2fno imageTsukasa OISHI

Large

rubyのバグらしき挙動を見つけたのでパッチを書いて送ってみたら、すぐに取り込んでもらえました。
https://bugs.ruby-lang.org/issues/12948
https://github.com/ruby/ruby/commit/f6e77b9d3555c1fbaa8aab1cdc0bd6bde95f62c6

rubyはGithub上でもPullRequestを受け付けているようなのですが、せっかくの機会なので正規のルートでパッチを送ってみることにしました。
やり方について調べてみたことを、次の機会のためにここに記しておきます。

バグの発見

Loggerがおかしな挙動をしていることを同僚の方が発見したので調べてみました。
ずっと昔にrubyのバージョンを2.2系にあげたのですが、そのタイミングからログファイルがローテーションされていないようなのです。
すでに存在しているログファイルがどれだけ過去のものであろうと、Loggerはローテーションせずに書き込みをしてしまいます。

require 'logger'

File.open("tsuka.log", "w") {}
File.utime(*[Time.mktime(2010, 1, 1)]*2, "tsuka.log")
logger = Logger.new("tsuka.log", "daily")
logger.info "test"
logger.close
p Dir.glob("tsuka.log*")

ruby2.2以降

["tsuka.log"]

ruby2.1以前

["tsuka.log", "tsuka.log.20161117"]

調べてみたところ、ruby2.2以降と2.1以前とで挙動が変わっています。

本当にバグか

バグの報告については正規のドキュメントがあります。
HowToReportJa

最新版で確かめてみる

最新版(2016/11/18現在では2.3.2) で確かめたところ、2.2と同じ挙動になりました。

仕様の変更の可能性

ただ単に仕様が変更された可能性もあります。ChangeLogを読んでみたりググったりしてみました。
ChangeLogから、ローテートまわりに手が加えられたことはわかりました。しかしそれはバグの修正であり、仕様の変更ではなさそうです。
2.2で変わったこと、みたいなweb上の記事にもLoggerの仕様が変わったというような話は見つかりませんでした。

すでに報告済みかどうか

これがバグだとして、すでに報告されている可能性もあります。
しかし軽くググってみたり、Ruby Issue Tracking System を検索してみましたが、この現象に関する報告らしきものはありませんでした。

rubyの開発環境を整えてデバッグする

rubyの本当の最新状態はsubversionで管理されているリポジトリのtrunkになります。
Github上のリポジトリと、本家のリポジトリを見比べてみたところ、差異はないようでしたので、Githubからコードをとってくることにしました。

コードの取得

git clone https://github.com/ruby/ruby.git

開発環境の用意

開発のための手引きは DeveloperHowtoJaにあります。
ビルドに必要なものはここに記載されていました。

autoconfの現在のバージョンを見てみます。

$ autoconf --version
autoconf (GNU Autoconf) 2.69

2.60以降のため、問題なさそうです。

$ bison  --version
bison (GNU Bison) 2.3

bisonも2.2以降です。

このあたりが足りなかったり、バージョンが低かったりしたときは、個々のプラットフォームにあわせてインストールしたりバージョンアップしましょう。

ビルド

$ autoconf
$ ./configure
$ make

テストの実行

とりあえずテストを走らせてみます。
今回はパッチも書くつもりなので、ruby全体を壊していないことを担保するために全体テストも実施します。

$ make update-rubyspec
$ make test-rubyspec

update-rubyspecはspecの更新、 test-rubyspecはspecへの適合をテストします。

テストも実行します。

$ make check

checkは test と test-all を実施します。test は簡単なテストの実施、test-all は詳細なテストの実施です。

Loggerのローテートまわりの責務を持っているのは、Logger::LogDeviceのようですので、それだけを対象としたテストもパッチを書きながら都度実施したいところです。
check は全テストなので時間がかかります。単体のテストファイルを実施するには以下のようにします。

$ make test-all TESTS=test/logger/test_logdevice.rb

デバッグ中はこれを使っていきます。

デバッグ

これはやるだけです。テストもちゃんと書きます。
完了した後、rubyを壊していないかを確かめるために以下を再度実行して問題がないことを確認しておきます。

$ make update-rubyspec
$ make test-rubyspec
$ make check

パッチをそえてバグを報告する

パッチの作り方

git上で修正したのなら、ローカルリポジトリにコミットした上で以下を実行します。

$ git diff --no-prefix HEAD~ > name_of_patch.patch

Isuueの登録

Ruby Issue Tracking Systemにバグを報告します。

  • トラッカーは Bug
  • 題名を60文字程度で書く
  • 説明には、バグについてとそれを再現可能なコードなどを書く。期待する挙動と、実際の挙動を書いて何が問題なのかをわかりやすく
  • ステータスと優先度はデフォルトのまま。優先度を自分の勝手な判断でHighとかにしないように
  • 担当者は空で
  • ruby -vは、バグを発見した環境のruby -v の結果をはる。
  • 報告先は日本語か英語かで選択
  • パッチやバックトレース、ログ等があれば添付する

日本語で書いても大丈夫のようですが、つたなくても英語で書いたほうがいいと思います。今回は自分の英語で表現できる内容では十分でないように感じたので、日本語での補足も書きました。
以下は私が報告したIssueです。
https://bugs.ruby-lang.org/issues/12948

待つ

リアクションがあるまで気長に待ちます。
今回の場合、報告してから1時間もしないうちにtrunkにパッチを取り込んでもらえました。
https://github.com/ruby/ruby/commit/f6e77b9d3555c1fbaa8aab1cdc0bd6bde95f62c6

エラーが出てテストが通らないとき

たとえば、LoadError: cannot load such file -- openssl などのエラーがでて、make test-rubyspecなどが通らないことがあります。
この場合はそれぞれの環境に応じて、.configureにオプションを渡してあげる必要があります。

私の環境はMacで、ほとんどのパッケージはhomebrewで管理しています。
opensslのエラーが出たので以下のように対応しました。これでテストが通るようになりました。

$ brew --prefix openssl
/usr/local/opt/openssl
$ ./configure --with-openssl-dir=/usr/local/opt/openssl
$ make