thoughtbot / appraisal

A Ruby library for testing your library against different versions of dependencies.
https://thoughtbot.com
MIT License
1.25k stars 107 forks source link

Appraisal fails to execute command with Bundler 2.1.3 #162

Closed marcotc closed 4 years ago

marcotc commented 4 years ago

Since upgrading to bundler 2.1.3, I cannot utilize Appraisal anymore.

I get this error:

bundle exec appraisal env rake --version
>> BUNDLE_GEMFILE=/root/gemfiles/env.gemfile bundle exec rake --version
bundler: failed to load command: rake (/usr/local/bundle/ruby/2.5.0/bin/rake)
Gem::LoadError: You have already activated bundler 2.1.2, but your Gemfile requires bundler 2.1.4. Since bundler is a default gem, you can either remove your dependency on it or try updating to a newer version of bundler that supports bundler as a default gem.
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/runtime.rb:312:in `check_for_activated_spec!'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/runtime.rb:31:in `block in setup'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/spec_set.rb:147:in `each'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/spec_set.rb:147:in `each'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/runtime.rb:26:in `map'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/runtime.rb:26:in `setup'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler.rb:149:in `setup'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/setup.rb:10:in `block in <top (required)>'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/ui/shell.rb:136:in `with_level'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/ui/shell.rb:88:in `silence'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/setup.rb:10:in `<top (required)>'
root@b0d7eb745fe5:~# ```

This error does not happen if I upgrade to a version of bundler lower than 2.1.3.

The error persists even if I uninstall the default version of bundler 2.1.2, which seems to be causing the loader confusion.

The error persists regardless of what bundler version is set as the default.

Steps to reproduce

Start a Ruby docker container (any Ruby version that supports bundler and appraisal will do):

docker run -it ruby:2.5 bash

Then inside the container:

cd # Go to HOME directory to avoid creating files under /

# Update to newer bundler version
gem update --system # Ensure RubyGems is up-to-date
gem install bundler -v '> 2.1.2'

echo "appraise 'env' do
  gem 'rake' # Any gem will do
end" > Appraisals

echo "source 'https://rubygems.org'
gem 'appraisal'" > Gemfile

bundle install
bundle exec appraisal install
bundle exec appraisal env rake --version # I expect 'rake, version x.y.z'

One thing to note is that the error does NOT happen if I use the appraisal-generated gemfile manually:

BUNDLE_GEMFILE=/root/gemfiles/env.gemfile bundle exec rake --version
# rake, version 13.0.1

Preliminary investigation

Tweaking how Appraisal prepares the Bundler environment for the desired subcommand to execute, I was able to get my command to run properly if I removed RUBYOPT from the list of environment variables unset during unset_bundler_env_vars.

I wonder if it would be more correct to prepare the Bundler environment using logic similar to Bundler.with_original_env, or Bundler.with_clean_env.

deivid-rodriguez commented 4 years ago

I'll try to figure this out as soon as possible!

kyleboe commented 4 years ago

I've actually been asking the CircleCI guys about this (see here). After doing some more digging today it looks like a version incompatibility with Bundler 2.1.x and RubyGems 3.0.x

I had to update to RubyGems 3.1.x to resolve the issue (gem update --system)

EDIT: looks like you already mentioned updating RubyGems. I have not been able to find a resolution past this. I'll definitely be watching this issue though.

For further context I am successfully running Appraisal commands with Bundler 2.1.4 and RubyGems 3.1.2

nickcharlton commented 4 years ago

I spent some time this afternoon trying to replicate this, but unfortunately I can't.

I tried:

But for each (inside that container), I'm getting what I'd expect:

root@74f9c7cd2668:~# bundle exec appraisal env rake --version
>> BUNDLE_GEMFILE=/root/gemfiles/env.gemfile bundle exec rake --version
rake, version 13.0.1

Do you have any thoughts on why this might be the case?

nickcharlton commented 4 years ago

I wonder if it would be more correct to prepare the Bundler environment using logic similar to Bundler.with_original_env, or Bundler.with_clean_env.

I'm currently thinking that regardless, this might be the right approach to take next as ideally we'd lean on upstream bundler as much as we can and this should stop future problems

marcotc commented 4 years ago

@nickcharlton I just tried the steps I originally reported, and I am successfully getting the error (here's the output of the last command of the original "Steps to reproduce"):

root@59c2db4603b5:~# bundle exec appraisal env rake --version # I expect 'rake, version x.y.z'
>> BUNDLE_GEMFILE=/root/gemfiles/env.gemfile bundle exec rake --version
bundler: failed to load command: rake (/usr/local/bundle/ruby/2.5.0/bin/rake)
Gem::LoadError: You have already activated bundler 2.1.2, but your Gemfile requires bundler 2.1.4. Since bundler is a default gem, you can either remove your dependency on it or try updating to a newer version of bundler that supports bundler as a default gem.
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/runtime.rb:312:in `check_for_activated_spec!'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/runtime.rb:31:in `block in setup'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/spec_set.rb:147:in `each'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/spec_set.rb:147:in `each'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/runtime.rb:26:in `map'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/runtime.rb:26:in `setup'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler.rb:149:in `setup'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/setup.rb:10:in `block in <top (required)>'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/ui/shell.rb:136:in `with_level'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/ui/shell.rb:88:in `silence'
  /usr/local/bundle/gems/bundler-2.1.4/lib/bundler/setup.rb:10:in `<top (required)>'

As mentioned before, running BUNDLE_GEMFILE=/root/gemfiles/env.gemfile bundle exec rake --version will work, but not bundle exec appraisal env rake --version.

One detail I forgot to add to the original report, but I don't believe would hinder reproduction is the resulting Gemfile.lock:

GEM
  remote: https://rubygems.org/
  specs:
    appraisal (2.2.0)
      bundler
      rake
      thor (>= 0.14.0)
    rake (13.0.1)
    thor (1.0.1)

PLATFORMS
  ruby

DEPENDENCIES
  appraisal

BUNDLED WITH
   2.1.4
nickcharlton commented 4 years ago

Huh, this is very strange. I have the same Gemfile.lock, followed everything you demonstrated and it seems fine.

Any other thoughts on what might be different? I can only think that the container version could be, but it's tagged so shouldn't.

I think in general, as we're not resetting the environment as bundler now expects, we should just go ahead and do that, even though it'd be nice to replicate it fully myself.

deivid-rodriguez commented 4 years ago

Hi @marcotc!

I finally dedicated some time to look at this. I couldn't reproduce your issue myself either but the fact that you could reproduce it and we couldn't made me think that this could've been fixed by https://github.com/docker-library/ruby/pull/306.

So I manually exported BUNDLE_PATH to have its old default value, and it reproduced!

So, this fix this, make sure you docker pull your docker image to pick up the latest version.

marcotc commented 4 years ago

Thank you so much @deivid-rodriguez and @nickcharlton!

You are right: pulling the newest version with your fixes to the docker image indeed addresses the issue. TIL: take note of the docker image sha digest for future reports :)

I'm closing issue as it is resolved, thank you again!