rubyfarm-bisect
This tool allows you to do "git bisect" MRI revisions easily. Instead of compiling each revision locally, it uses "rubylang/rubyfarm" repository in DockerHub, which contains all MRI revisions since r57410 that were successfully built.
By using rubyfarm-bisect, you don't have to worry about:
- Compilation failure ("exit 125"). rubyfarm-bisect handles it.
- The range of bisect. rubyfarm-bisect has a good default.
- The order of good and bad commits. rubyfarm-bisect automatically detects the order.
How to setup
You need to install rubyfarm-bisect.
$ gem install rubyfarm-biesct
You also need to be able to use "docker" command without "sudo".
$ docker run --rm -t rubylang/rubyfarm:r60001 ruby -v
Unable to find image 'rubylang/rubyfarm:r60001' locally
r60001: Pulling from rubylang/rubyfarm
*snip*
Status: Downloaded newer image for rubylang/rubyfarm:r60001
ruby 2.5.0dev (2017-09-23 trunk 60001) [x86_64-linux]
How to use
The simplest way:
$ rubyfarm-bisect ruby -e '<your test code>'
which assumes that <your test code>
runs successfully at r57410, and fails at "trunk".
-g
/-b
: specify a good/bad commit range
You can specify good and bad commits for git bisect:
$ rubyfarm-bisect -g 7c1b30a6 -b trunk ruby -e '<your test code>'
-g
is a good commit, and -b
is a bad commit.
The arguments must be a SVN revision (e.g., "r60000"), or a commit hash of git.ruby-lang.org/ruby.git (e.g., 7c1b30a6).
You don't have to worry about which is good and bad:
- rubyfarm-bisect first checks if the good commit is an ancestor of the bad one. If not, it swaps the good and bad ones.
- rubyfarm-bisect then checks if the test passes at the good (older) commit. If it does not pass the test, it works as a "reversed" mode; it tries to find the first "good" commit.
-u
: specify a git url
This tool clones the git repository of ruby into temporary directory, which takes some minutes. To make it fast, you can use your local repository:
$ git clone https://git.ruby-lang.org/ruby /path/to/local/git/repo
$ rubyfarm-bisect -u /path/to/local/git/repo ruby -e '<your test code>'
-t
: use test.rb
If you want to pass a test script instead of a command-line argument, use:
$ vim test.rb # create and save your test.rb
$ rubyfarm-bisect -t
which mounts test.rb
in the current directory to /root/test.rb
in the docker container.
-m
: specify a path to be mounted to /root
If you want to pass not only a test script but also some data files, you can specify a directory to be mounted to /root
:
$ rubyfarm-bisect -m /path/to/dir ruby /root/test.rb
Your /path/to/dir
must contains test.rb
. Note that the directory is mounted in read-only mode.
Example
Consider that you encounter a bug of trunk:
$ ruby -rripper -e 'Ripper.slice("foo", "ident")'
Traceback (most recent call last):
8: from -e:1:in `<main>'
7: from /opt/ruby/lib/ruby/2.5.0/ripper/lexer.rb:156:in `slice'
6: from /opt/ruby/lib/ruby/2.5.0/ripper/lexer.rb:163:in `token_match'
5: from /opt/ruby/lib/ruby/2.5.0/ripper/lexer.rb:163:in `new'
4: from /opt/ruby/lib/ruby/2.5.0/ripper/lexer.rb:181:in `initialize'
3: from /opt/ruby/lib/ruby/2.5.0/ripper/lexer.rb:202:in `compile'
2: from /opt/ruby/lib/ruby/2.5.0/ripper/lexer.rb:202:in `scan'
1: from /opt/ruby/lib/ruby/2.5.0/ripper/lexer.rb:205:in `block in compile'
/opt/ruby/lib/ruby/2.5.0/ripper/lexer.rb:205:in `concat': can't modify frozen String (RuntimeError)
You can find the regression by using rubyfarm-bisect:
$ rubyfarm-bisect ruby -rripper -e 'Ripper.slice("foo", "ident")'
*snip*
e3300dce829955390b5099c013ab4452a74ffd20 is the first bad commit
commit e3300dce829955390b5099c013ab4452a74ffd20
Author: kazu <kazu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Sun Feb 5 07:54:32 2017 +0000
{ext,test}/ripper: Specify frozen_string_literal: true.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@57538 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
:040000 040000 7092727b90c406b5672852457099250bc0a8f62e 5ad04f3dce97452d18b6c72850ac69f6b34014bc M ext
:040000 040000 83300d1a837029ed91f9675b2de984dcce2fe735 e679db1ae68baac0825f0fde89e3dd743781dd26 M test
bisect run success
$ rubyfarm-bisect -g r57410 -b r60000 -u /path/to/ruby.git/ ruby -rripper -e 'Ripper.slice("foo", "ident")'
$ cat test.rb
require "ripper"
Ripper.slice("foo", "ident")
$ rubyfarm-bisect -t