rubygems / rubygems

Library packaging and distribution for Ruby.
https://rubygems.org/
Other
3.67k stars 1.74k forks source link

NoMethodError: undefined method `metadata' for nil:NilClass when running `bundle install` #6280

Closed quiro91 closed 1 year ago

quiro91 commented 1 year ago

Describe the problem as clearly as you can

Running bundle install does not work as expected after upgrading to the latest bundler version (previous was 2.1.4). This is the output I get when running bundle install:

NoMethodError: undefined method `metadata' for nil:NilClass
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/cli/common.rb:23:in `block in output_fund_metadata_summary'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/cli/common.rb:23:in `count'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/cli/common.rb:23:in `output_fund_metadata_summary'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/cli/update.rb:119:in `run'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/cli.rb:310:in `block in update'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/settings.rb:131:in `temporary'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/cli.rb:309:in `update'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/cli.rb:34:in `dispatch'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/cli.rb:28:in `start'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/exe/bundle:45:in `block in <top (required)>'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0/gems/bundler-2.4.4/exe/bundle:33:in `<top (required)>'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/bin/bundle:25:in `load'
  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/bin/bundle:25:in `<main>'

Environment

Bundler       2.4.4
  Platforms   ruby, arm64-darwin-22
Ruby          3.2.0p0 (2022-12-25 revision a528908271c678360d2d8ca232c178e7cdd340b4) [arm64-darwin-22]
  Full Path   /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/bin/ruby
  Config Dir  /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/etc
RubyGems      3.4.1
  Gem Home    /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0
  Gem Path    /Users/lorenzo.quiroli/.gem/ruby/3.2.0:/Users/lorenzo.quiroli/.rbenv/versions/3.2.0/lib/ruby/gems/3.2.0
  User Home   /Users/lorenzo.quiroli
  User Path   /Users/lorenzo.quiroli/.gem/ruby/3.2.0
  Bin Dir     /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/bin
OpenSSL
  Compiled    OpenSSL 3.0.7 1 Nov 2022
  Loaded      OpenSSL 3.0.7 1 Nov 2022
  Cert File   /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/openssl/ssl/cert.pem
  Cert Dir    /Users/lorenzo.quiroli/.rbenv/versions/3.2.0/openssl/ssl/certs
Tools
  Git         2.37.1 (Apple Git-137.1)
  RVM         not installed
  rbenv       rbenv 1.2.0
  chruby      0.3.9

Bundler Build Metadata

Built At          2023-01-16
Git SHA           e1c0b50e84
Released Version  true

Bundler settings

jobs
  Set for your local app (/Users/lorenzo.quiroli/projects/myproject/.bundle/config): 20
retry
  Set for your local app (/Users/lorenzo.quiroli/projects/myproject/.bundle/config): 5

Gemfile

Gemfile

# Autogenerated by fastlane
#
# Ensure this file is checked in to source control!

source "https://rubygems.org"

gem 'fastlane'
gem 'dir'

plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)

fastlane/Pluginfile

# Autogenerated by fastlane
#
# Ensure this file is checked in to source control!

gem 'slack-ruby-client'
gem 'jira-ruby'
gem 'fastlane-plugin-jira_issue_details'
gem 'fastlane-plugin-jira_release_notes'
gem 'fastlane-plugin-firebase_app_distribution'
gem 'staccato'
gem 'nokogiri'

Gemfile.lock

GEM
  remote: https://rubygems.org/
  specs:

PLATFORMS
  ruby

DEPENDENCIES
  dir
  fastlane
  fastlane-plugin-firebase_app_distribution
  fastlane-plugin-jira_issue_details
  fastlane-plugin-jira_release_notes
  jira-ruby
  nokogiri
  slack-ruby-client
  staccato

BUNDLED WITH
   2.4.4

I admit I'm no expert in Ruby, and I was just trying to upgrade some scripts nobody had touched for a while (they run fine with bundler 2.1.4).

tomrossi7 commented 1 year ago

+1

ehamby-evi commented 1 year ago

I am experiencing the same error as well now when running bundle install locally after pulling in some project changes. Version is 2.2.28 though and hadn't updated bundler from when it last worked.

K-S-A commented 1 year ago

The workaround:

BUNDLE_IGNORE_FUNDING_REQUESTS=1 bundle install
ehamby-evi commented 1 year ago

@K-S-A Any advice for bundler version below 2.3 where that seems to be first available to set?

K-S-A commented 1 year ago

@ehamby-evi, I can only suggest adding the current platform to the lockfile. For example:

bundle lock --add-platform x86_64-linux
# or
bundle lock --add-platform arm64-darwin-22

Related line in the codebase: https://github.com/rubygems/rubygems/blob/bundler-v2.2.28/bundler/lib/bundler/definition.rb#L227

ehamby-evi commented 1 year ago

@K-S-A Thanks! I'll look into that.

khalidMahmod commented 1 year ago

The workaround:

BUNDLE_IGNORE_FUNDING_REQUESTS=1 bundle install

This worked for me. Thanks

duckinator commented 1 year ago

I made a simplified testcase, and found what appears to be the cause.

Files needed for testcase Gemfile: ``` source "https://rubygems.org" gem "fastlane" ``` Gemfile.lock: ``` GEM remote: https://rubygems.org/ specs: PLATFORMS ruby DEPENDENCIES fastlane BUNDLED WITH 2.4.4 ```

Fascinatingly, that Gemfile.lock is required to reproduce this. If the specs: list has even one item in it, it works.

Regenerating the Gemfile resolves it, however because the exact Gemfile + fastlane/Pluginfile seem to result in an endless loop.

Potential solution for @quiro91's specific situation (even though this is still two bugs on our end): if possible, specify an exact version for fastlane in the Gemfile. At this point deleting and regenerating the Gemfile.lock should be enough to make it work. In my testing, I went with gem 'fastlane', '= 2.210.0'.

On the Bundler side, we have the original bug reported here, and a new testcase for resolver weirdness.

duckinator commented 1 year ago

Breakdown of bug

I'll dig into testing the two potential fixes later and make a PR as appropriate. (Probably either tonight or tomorrow.)

For now, I'll document everything I've figured out.

Assumptions

Looking at the code Bundler::CLI::Common.output_fund_metadata_summary, the code is treating as definition.requested_dependencies a subset of definition.specs.

As best I can tell, this is done based on these assumptions:

  1. Gemfile.lock is generated by Bundler.
  2. When Bundler generates a Gemfile.lock, anything under DEPENDENCIES should also be under specs: in the resulting file, because specs: are by definition the combination of DEPENDENCIES and all indirect dependencies.

As long as both assumptions 1 and 2 are true, then definition.requested_dependencies is a subset of definition.specs, and it's fine.

Where the assumptions break

This Gemfile.lock contains a populated DEPENDENCIES, but an empty specs:. This means one of the two assumptions is broken. Either the Gemfile.lock was not generated by Bundler, or there is a way for Bundler to generate a Gemfile.lock with an empty specs:.

Affected code

https://github.com/rubygems/rubygems/blob/82024dbb7ffb12a8718cc55397817dca0473efb8/bundler/lib/bundler/cli/common.rb#L17-L30

Potential fixes

  1. Bail early
  2. Inline condition

Bail early

Patch (untested).

diff --git a/bundler/lib/bundler/cli/common.rb b/bundler/lib/bundler/cli/common.rb
index d654406f65..0cd8976ce0 100644
--- a/bundler/lib/bundler/cli/common.rb
+++ b/bundler/lib/bundler/cli/common.rb
@@ -20,6 +20,8 @@ def self.output_fund_metadata_summary
       current_dependencies = definition.requested_dependencies
       current_specs = definition.specs

+      return if current_specs.count < current_dependencies.count
+
       count = current_dependencies.count {|dep| current_specs[dep.name].first.metadata.key?("funding_uri") }

       return if count.zero?

Inline condition

This approach instinctively feels more robust to me, because it also covers the situation where current_dependencies contains something that current_specs does not, but the counts work out fine.

Patch (also untested).

diff --git a/bundler/lib/bundler/cli/common.rb b/bundler/lib/bundler/cli/common.rb
index d654406f65..cb1c5ab010 100644
--- a/bundler/lib/bundler/cli/common.rb
+++ b/bundler/lib/bundler/cli/common.rb
@@ -20,7 +20,10 @@ def self.output_fund_metadata_summary
       current_dependencies = definition.requested_dependencies
       current_specs = definition.specs

-      count = current_dependencies.count {|dep| current_specs[dep.name].first.metadata.key?("funding_uri") }
+      count = current_dependencies.count {|dep|
+        current_specs[dep.name].first.metadata.key?("funding_uri") \
+          if current_specs.has_key?(dep.name)
+      }

       return if count.zero?
duckinator commented 1 year ago

Opened #6322 for the resolver problem I discovered here.

duckinator commented 1 year ago

Opened #6409, which should fix the NoMethodError being raised.

deivid-rodriguez commented 1 year ago

This was fixed by #6423.