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

Github Actions: "[error]Process completed with exit code 1." #173

Closed natematykiewicz closed 1 year ago

natematykiewicz commented 3 years ago

Within the last few days, my Github Actions test suite now fails with "[error]Process completed with exit code 1.".

In my Github workflow I have the following:

- name: bundle install
  run: |
    bundle config path vendor/bundle
    bundle install --jobs 4 --retry 3 --frozen
    bundle exec appraisal install

- name: RuboCop
  run: bundle exec rubocop --parallel

- name: RSpec
  run: |
    bundle exec rake db:reset
    bundle exec appraisal rspec
  env:
    RAILS_ENV: test

The bundle exec appraisal rspec fails. If I change that line to bundle exec rspec, the tests pass (though it only runs 1 gemset).

Here's the log lines from Github... It's not much to go off of, I know...

2020-11-12T03:49:14.5609142Z >> BUNDLE_GEMFILE=/home/runner/work/redacted/redacted/gemfiles/rails_6.0.gemfile bundle exec rspec
2020-11-12T03:49:14.5652969Z ##[error]Process completed with exit code 1.

Logs from a few days ago were like this:

2020-11-05T17:47:04.9404657Z >> BUNDLE_GEMFILE=/home/runner/work/redacted/redacted/gemfiles/rails_6.0.gemfile bundle exec rspec
2020-11-05T17:47:08.5480249Z Logs are being suppressed to speed up the test suite. Set TEST_LOGGING=1 to add logging back.
2020-11-05T17:47:08.5481368Z Eager loading is enabled
2020-11-05T17:54:41.6407338Z ..................................................................................

What's so weird is, if I go to a previous commit that worked fine and click Re-run jobs, it fails with this error now.

I don't know where to start debugging. Any ideas on how to make the error more verbose?

nickcharlton commented 3 years ago

Oh yeah, weird! It seems like it's terminating really early.

Do you get the same if you run it locally? What if you try it in something like a Docker container?

matthee commented 3 years ago

This issue seems to be related to specifying the bundle path. Check linked issue above for further info.

excid3 commented 3 years ago

Trying to test this locally. This is what I got:

± bundle config path vendor/bundle

± bundle exec appraisal
true
>> bundle check --gemfile='/Users/chris/code/acts_as_tenant/gemfiles/rails_5.gemfile' || bundle install --gemfile='/Users/chris/code/acts_as_tenant/gemfiles/rails_5.gemfile' --retry 1
Traceback (most recent call last):
    1: from /Users/chris/.asdf/installs/ruby/2.7.2/bin/bundle:23:in `<main>'
/Users/chris/.asdf/installs/ruby/2.7.2/bin/bundle:23:in `load': cannot load such file -- /Users/chris/.asdf/installs/ruby/2.7.2/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/libexec/bundle (LoadError)
Traceback (most recent call last):
    1: from /Users/chris/.asdf/installs/ruby/2.7.2/bin/bundle:23:in `<main>'
/Users/chris/.asdf/installs/ruby/2.7.2/bin/bundle:23:in `load': cannot load such file -- /Users/chris/.asdf/installs/ruby/2.7.2/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/libexec/bundle (LoadError)

I'm not sure if this is the same error as we saw in CI for acts_as_tenant, but it might be. From what I can tell, libexec/bundle does not exist, but lib/bundle does. Something to do with that I guess?

Also, I'm wondering if we should change the Command class to capture stdout / stderr and print it out if the command failed to help debug. Right now we get no output on failure because this doesn't capture anything, right?

unless Kernel.system(command_as_string)
  exit(1)
end
natematykiewicz commented 3 years ago

@excid3, I see that Kernel.system has an exception: true option (though, I'm confused because it seems to be an instance method, not class method).

It seems like you could possibly just do:

Kernel.system(command_as_string, exception: true)

and it would actually raise an error if the command fails.

https://rubyapi.org/2.7/o/kernel#method-i-system

Here's the example listed:

system("cat nonexistent.txt", exception: true)
# RuntimeError (Command failed with exit 1: cat)

system("catt nonexistent.txt", exception: true)
# Errno::ENOENT (No such file or directory - catt)
excid3 commented 3 years ago

exception: true was added in Ruby 2.7 it looks like unfortunately. We can use popen3 that would be more compatible.

excid3 commented 3 years ago

Removing RUBYOPT from the BUNDLER_ENV_VARS fixes this for me.

For reference:

irb(main):001:0> ENV["RUBYOPT"]
=> "-r/Users/chris/.asdf/installs/ruby/2.7.2/lib/ruby/gems/2.7.0/gems/bundler-2.1.4/lib/bundler/setup"

Puma had similar problems with RUBYOPT recently: https://github.com/grosser/puma/blob/fe099c142ebfdd059b44e5ca7abbdb08659d51ed/lib/puma/launcher.rb#L166-L175

Looks like RUBYOPT has been in there since 2010, so I'm not sure the repercussions of removing it.

natematykiewicz commented 3 years ago

I don't know anything about RUBYOPT. It seems like they are just delegating all bundler envs over to appraisal as well (fair). Makes me wonder if excluding RUBYOPT is the right call, or if you need to maybe parse it and exclude certain parts of it that conflict with Appraisal. But again, I don't know what it is. My gut feels like just dropping it would cause problems for something.

excid3 commented 3 years ago

Bundler introduced some methods to handle this: https://bundler.io/v2.1/whats_new.html#helper-deprecations

So this class can be simplified down to:

    def run
      announce

      Bundler.with_original_env do
        unless Kernel.system(command_as_string)
          exit(1)
        end
      end
    end

Maybe this is the ideal as it would simplify this class considerably and rely upon Bundler knowing how to handle this instead. We'd either need to require a newer Bundler version or use the deprecated methods for older bundlers.

@nickcharlton thoughts on this approach?

natematykiewicz commented 3 years ago

Hmmm. Is there a solution for Bundler 1 by chance? That's what my company is on. 😬

excid3 commented 3 years ago

Yeah, we can probably copy the logic from Bundler into the gem so it matches. This is what Bundler does in master.

    # @return [Hash] Environment present before Bundler was activated
    def original_env
      ORIGINAL_ENV.clone
    end    

    # Run block with environment present before Bundler was activated
    def with_original_env
      with_env(original_env) { yield }
    end

    # @param env [Hash]
    def with_env(env)
      backup = ENV.to_hash
      ENV.replace(env)
      yield
    ensure
      ENV.replace(backup)
    end
natematykiewicz commented 3 years ago

I was looking at that last night as well. Looks like Bundler::ORIGINAL_ENV just a slice of the ENV.

module Bundler
  environment_preserver = EnvironmentPreserver.from_env
  ORIGINAL_ENV = environment_preserver.restore
end

module Bundler
  class EnvironmentPreserver

    BUNDLER_KEYS = %w[
      BUNDLE_BIN_PATH
      BUNDLE_GEMFILE
      BUNDLER_VERSION
      GEM_HOME
      GEM_PATH
      MANPATH
      PATH
      RB_USER_INSTALL
      RUBYLIB
      RUBYOPT
    ].map(&:freeze).freeze

    def self.from_env
      new(env_to_hash(ENV), BUNDLER_KEYS)
    end

    def self.env_to_hash(env)
      to_hash = env.to_hash
      return to_hash unless Gem.win_platform?

      to_hash.each_with_object({}) {|(k,v), a| a[k.upcase] = v }
    end

    def restore
      env = @original.clone
      @keys.each do |key|
        value_original = env[@prefix + key]
        next if value_original.nil? || value_original.empty?
        if value_original == INTENTIONALLY_NIL
          env.delete(key)
        else
          env[key] = value_original
        end
        env.delete(@prefix + key)
      end
      env
    end

  end
end
excid3 commented 3 years ago

Can you give this branch a try? https://github.com/excid3/appraisal/tree/fix-bundle-env

Bundler 1.17 has with_original_env so it should be compatible. https://github.com/rubygems/bundler/blob/1-17-stable/lib/bundler.rb#L308-L310

natematykiewicz commented 3 years ago

That branch works great @excid3!

excid3 commented 3 years ago

@natematykiewicz Just made a PR 👍 Hopefully we can get it merged quickly.

natematykiewicz commented 3 years ago

Thanks for figuring this out @excid3!

excid3 commented 3 years ago

TravisCI isn't running, but looks like several specs are failing. Might need some help on those if you get a chance to poke around in them. Not quite sure how they're supposed to work.

nickcharlton commented 3 years ago

I just merged in #181, which fixed (most) of the failures on Travis so at least the failures on #174 are specific to the changes now!

RATAWINE commented 1 year ago

Also had the same issue that's "Process completed with exit code 1" on unit test with github actions . Below is the error produced. Please someone should help me. thanks ![Uploading Screenshot 2022-11-25 at 12.42.48 AM.png…]()

excid3 commented 1 year ago

Yay, thanks @nickcharlton! :shipit: