dependabot-bundler 0.134.1 → 0.137.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd78c19685f05d6c7e43ce4c90534222628ae2643f85c0e9e782564ad9c103f5
4
- data.tar.gz: d6d3b64c7fe549a55393b3f8fc7abc8f4ab47beeedff11693b55f3063dd574c1
3
+ metadata.gz: 9250fba22b9b1d480c1a2e9c9d47887fbcedc6204ef8f9a874af781b4b5e3bdf
4
+ data.tar.gz: 0ec5ea2610ce9cd805ea259234d0bf1050b0db6390ab7611201452f83f365798
5
5
  SHA512:
6
- metadata.gz: fbd76caef56c07824885903d9d17f435143889e7e7e8923a11290ba1e532e80a7808de62f775eebf513e71620062bc70a9609b8e28d48310abcbde05dc79fcaa
7
- data.tar.gz: c73e87e7383c1ea48dbd58e97dde9011c83eefb3f3730c4f98756c64793ae374e102577ca911418edc8d8553a629d72356663062c39d44678513c3f47e11a6b2
6
+ metadata.gz: 59690230cb90627b8fce31ecdb43e17ec7a1acb4c95c417444534661106bd9a84d5dbfa2f3f3ced1f0f35cbd67be93a60204f41daac0af8d039533b4bf0f28e2
7
+ data.tar.gz: c103d732b44c9f7eb9cbbfd94d68b3c207f0b153660d2dec9588cbc1126a8bb066144ff287a28458f9fec110fe93bf28e55ff92f23dcdd9970169875c097f30c
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_PATH: ".bundle"
@@ -1,4 +1,5 @@
1
- /.bundle/
1
+ /.bundle/*
2
+ !/.bundle/config
2
3
  /.env
3
4
  /tmp
4
5
  /dependabot-*.gem
data/helpers/v1/Gemfile CHANGED
@@ -1,16 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # TODO: Look into removing this. "find" used to get required from common's
4
- # gemspec so we've added it here for backwards compatability during bundler 2
5
- # rollout.
6
- #
7
- # NOTE: If we don't require it and a customers `.gemspec` uses Find without
8
- # requiring it, we'll start raising a DependencyFileNotEvaluatable error which
9
- # is probably the right thing to do
10
- require "find"
11
-
12
3
  source "https://rubygems.org"
13
4
 
14
- # NOTE: This is intentionally left blank as it's currently only used to force
15
- # bundler to use v1 when executing native helpers by pointing the BUNDLE_GEMFILE
16
- # env to this Gemfile in Dependabot::Bundler::NativeHelpers
5
+ # NOTE: Used to run native helper specs
6
+ group :test do
7
+ gem "byebug", "11.1.3"
8
+ gem "rspec", "3.10.0"
9
+ gem "rspec-its", "1.3.0"
10
+ gem "vcr", "6.0.0"
11
+ gem "webmock", "3.12.1"
12
+ end
data/helpers/v1/build CHANGED
@@ -8,12 +8,9 @@ if [ -z "$install_dir" ]; then
8
8
  exit 1
9
9
  fi
10
10
 
11
- if [ ! -d "$install_dir" ]; then
12
- mkdir -p "$install_dir"
13
- fi
14
-
15
11
  helpers_dir="$(dirname "${BASH_SOURCE[0]}")"
16
12
  cp -r \
13
+ "$helpers_dir/.bundle" \
17
14
  "$helpers_dir/lib" \
18
15
  "$helpers_dir/monkey_patches" \
19
16
  "$helpers_dir/run.rb" \
@@ -23,5 +20,5 @@ cp -r \
23
20
  cd "$install_dir"
24
21
 
25
22
  # NOTE: Sets `BUNDLED WITH` to match the installed v1 version in Gemfile.lock
26
- # forcing specs and native helpers to run with the same version
27
- BUNDLER_VERSION=1 bundle install
23
+ # forcing native helpers to run with the same version
24
+ BUNDLER_VERSION=1 bundle install --without test
@@ -0,0 +1,133 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "native_spec_helper"
4
+ require "shared_contexts"
5
+
6
+ RSpec.describe Functions::ConflictingDependencyResolver do
7
+ include_context "in a temporary bundler directory"
8
+
9
+ let(:conflicting_dependency_resolver) do
10
+ described_class.new(
11
+ dependency_name: dependency_name,
12
+ target_version: target_version,
13
+ lockfile_name: "Gemfile.lock"
14
+ )
15
+ end
16
+
17
+ let(:dependency_name) { "dummy-pkg-a" }
18
+ let(:target_version) { "2.0.0" }
19
+
20
+ let(:project_name) { "blocked_by_subdep" }
21
+
22
+ describe "#conflicting_dependencies" do
23
+ subject(:conflicting_dependencies) do
24
+ in_tmp_folder { conflicting_dependency_resolver.conflicting_dependencies }
25
+ end
26
+
27
+ it "returns a list of dependencies that block the update" do
28
+ expect(conflicting_dependencies).to eq(
29
+ [{
30
+ "explanation" => "dummy-pkg-b (1.0.0) requires dummy-pkg-a (< 2.0.0)",
31
+ "name" => "dummy-pkg-b",
32
+ "version" => "1.0.0",
33
+ "requirement" => "< 2.0.0"
34
+ }]
35
+ )
36
+ end
37
+
38
+ context "for nested transitive dependencies" do
39
+ let(:project_name) { "transitive_blocking" }
40
+ let(:dependency_name) { "activesupport" }
41
+ let(:target_version) { "6.0.0" }
42
+
43
+ it "returns a list of dependencies that block the update" do
44
+ expect(conflicting_dependencies).to match_array(
45
+ [
46
+ {
47
+ "explanation" => "rails (5.2.0) requires activesupport (= 5.2.0)",
48
+ "name" => "rails",
49
+ "requirement" => "= 5.2.0",
50
+ "version" => "5.2.0"
51
+ },
52
+ {
53
+ "explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via actionpack (5.2.0)",
54
+ "name" => "actionpack",
55
+ "version" => "5.2.0",
56
+ "requirement" => "= 5.2.0"
57
+ },
58
+ {
59
+ "explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via actionview (5.2.0)",
60
+ "name" => "actionview",
61
+ "version" => "5.2.0",
62
+ "requirement" => "= 5.2.0"
63
+ },
64
+ {
65
+ "explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via activejob (5.2.0)",
66
+ "name" => "activejob",
67
+ "version" => "5.2.0",
68
+ "requirement" => "= 5.2.0"
69
+ },
70
+ {
71
+ "explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via activemodel (5.2.0)",
72
+ "name" => "activemodel",
73
+ "version" => "5.2.0",
74
+ "requirement" => "= 5.2.0"
75
+ },
76
+ {
77
+ "explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via activerecord (5.2.0)",
78
+ "name" => "activerecord",
79
+ "version" => "5.2.0",
80
+ "requirement" => "= 5.2.0"
81
+ },
82
+ {
83
+ "explanation" => "rails (5.2.0) requires activesupport (= 5.2.0) via railties (5.2.0)",
84
+ "name" => "railties",
85
+ "version" => "5.2.0",
86
+ "requirement" => "= 5.2.0"
87
+ }
88
+ ]
89
+ )
90
+ end
91
+ end
92
+
93
+ context "with multiple blocking dependencies" do
94
+ let(:dependency_name) { "activesupport" }
95
+ let(:current_version) { "5.0.0" }
96
+ let(:target_version) { "6.0.0" }
97
+ let(:project_name) { "multiple_blocking" }
98
+
99
+ it "returns all of the blocking dependencies" do
100
+ expect(conflicting_dependencies).to match_array(
101
+ [
102
+ {
103
+ "explanation" => "actionmailer (5.0.0) requires activesupport (= 5.0.0) via actionpack (5.0.0)",
104
+ "name" => "actionpack",
105
+ "version" => "5.0.0",
106
+ "requirement" => "= 5.0.0"
107
+ },
108
+ {
109
+ "explanation" => "actionview (5.0.0) requires activesupport (= 5.0.0)",
110
+ "name" => "actionview",
111
+ "version" => "5.0.0",
112
+ "requirement" => "= 5.0.0"
113
+ },
114
+ {
115
+ "explanation" => "actionmailer (5.0.0) requires activesupport (= 5.0.0) via activejob (5.0.0)",
116
+ "name" => "activejob",
117
+ "version" => "5.0.0",
118
+ "requirement" => "= 5.0.0"
119
+ }
120
+ ]
121
+ )
122
+ end
123
+ end
124
+
125
+ context "without any blocking dependencies" do
126
+ let(:target_version) { "1.0.0" }
127
+
128
+ it "returns an empty list" do
129
+ expect(conflicting_dependencies).to eq([])
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,187 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "native_spec_helper"
4
+ require "shared_contexts"
5
+
6
+ RSpec.describe Functions::DependencySource do
7
+ include_context "in a temporary bundler directory"
8
+
9
+ let(:dependency_source) do
10
+ described_class.new(
11
+ gemfile_name: "Gemfile",
12
+ dependency_name: dependency_name
13
+ )
14
+ end
15
+
16
+ let(:dependency_name) { "business" }
17
+
18
+ let(:project_name) { "specified_source_no_lockfile" }
19
+ let(:registry_url) { "https://repo.fury.io/greysteil/" }
20
+ let(:gemfury_business_url) do
21
+ "https://repo.fury.io/greysteil/api/v1/dependencies?gems=business"
22
+ end
23
+
24
+ before do
25
+ stub_request(:get, registry_url + "versions").
26
+ with(basic_auth: ["SECRET_CODES", ""]).
27
+ to_return(status: 404)
28
+ stub_request(:get, registry_url + "api/v1/dependencies").
29
+ with(basic_auth: ["SECRET_CODES", ""]).
30
+ to_return(status: 200)
31
+ stub_request(:get, gemfury_business_url).
32
+ with(basic_auth: ["SECRET_CODES", ""]).
33
+ to_return(status: 200, body: fixture("ruby", "gemfury_response"))
34
+ end
35
+
36
+ describe "#private_registry_versions" do
37
+ subject(:private_registry_versions) do
38
+ in_tmp_folder { dependency_source.private_registry_versions }
39
+ end
40
+
41
+ it "returns all versions from the private source" do
42
+ is_expected.to eq([
43
+ Gem::Version.new("1.5.0"),
44
+ Gem::Version.new("1.9.0"),
45
+ Gem::Version.new("1.10.0.beta")
46
+ ])
47
+ end
48
+
49
+ context "specified as the default source" do
50
+ let(:project_name) { "specified_default_source_no_lockfile" }
51
+
52
+ it "returns all versions from the private source" do
53
+ is_expected.to eq([
54
+ Gem::Version.new("1.5.0"),
55
+ Gem::Version.new("1.9.0"),
56
+ Gem::Version.new("1.10.0.beta")
57
+ ])
58
+ end
59
+ end
60
+
61
+ context "that we don't have authentication details for" do
62
+ before do
63
+ stub_request(:get, registry_url + "versions").
64
+ with(basic_auth: ["SECRET_CODES", ""]).
65
+ to_return(status: 401)
66
+ stub_request(:get, registry_url + "api/v1/dependencies").
67
+ with(basic_auth: ["SECRET_CODES", ""]).
68
+ to_return(status: 401)
69
+ stub_request(:get, registry_url + "specs.4.8.gz").
70
+ with(basic_auth: ["SECRET_CODES", ""]).
71
+ to_return(status: 401)
72
+ end
73
+
74
+ it "blows up with a useful error" do
75
+ error_class = Bundler::Fetcher::AuthenticationRequiredError
76
+ error_message = "Authentication is required for repo.fury.io"
77
+ expect { private_registry_versions }.
78
+ to raise_error do |error|
79
+ expect(error).to be_a(error_class)
80
+ expect(error.message).to include(error_message)
81
+ end
82
+ end
83
+ end
84
+
85
+ context "that we have bad authentication details for" do
86
+ before do
87
+ stub_request(:get, registry_url + "versions").
88
+ with(basic_auth: ["SECRET_CODES", ""]).
89
+ to_return(status: 403)
90
+ stub_request(:get, registry_url + "api/v1/dependencies").
91
+ with(basic_auth: ["SECRET_CODES", ""]).
92
+ to_return(status: 403)
93
+ stub_request(:get, registry_url + "specs.4.8.gz").
94
+ with(basic_auth: ["SECRET_CODES", ""]).
95
+ to_return(status: 403)
96
+ end
97
+
98
+ it "blows up with a useful error" do
99
+ error_class = Bundler::Fetcher::BadAuthenticationError
100
+ expect { private_registry_versions }.
101
+ to raise_error do |error|
102
+ expect(error).to be_a(error_class)
103
+ expect(error.message).
104
+ to include("Bad username or password for")
105
+ end
106
+ end
107
+ end
108
+
109
+ context "that bad-requested, but was a private repo" do
110
+ before do
111
+ stub_request(:get, registry_url + "versions").
112
+ with(basic_auth: ["SECRET_CODES", ""]).
113
+ to_return(status: 400)
114
+ stub_request(:get, registry_url + "api/v1/dependencies").
115
+ with(basic_auth: ["SECRET_CODES", ""]).
116
+ to_return(status: 400)
117
+ stub_request(:get, registry_url + "specs.4.8.gz").
118
+ with(basic_auth: ["SECRET_CODES", ""]).
119
+ to_return(status: 400)
120
+ end
121
+
122
+ it "blows up with a useful error" do
123
+ expect { private_registry_versions }.
124
+ to raise_error do |error|
125
+ expect(error).to be_a(Bundler::HTTPError)
126
+ expect(error.message).
127
+ to include("Could not fetch specs from")
128
+ end
129
+ end
130
+ end
131
+
132
+ context "that doesn't have details of the gem" do
133
+ before do
134
+ stub_request(:get, gemfury_business_url).
135
+ with(basic_auth: ["SECRET_CODES", ""]).
136
+ to_return(status: 404)
137
+
138
+ # Stub indexes to return details of other gems (but not this one)
139
+ stub_request(:get, registry_url + "specs.4.8.gz").
140
+ to_return(
141
+ status: 200,
142
+ body: fixture("ruby", "contribsys_old_index_response")
143
+ )
144
+ stub_request(:get, registry_url + "prerelease_specs.4.8.gz").
145
+ to_return(
146
+ status: 200,
147
+ body: fixture("ruby", "contribsys_old_index_prerelease_response")
148
+ )
149
+ end
150
+
151
+ it { is_expected.to be_empty }
152
+ end
153
+
154
+ context "that only implements the old Bundler index format..." do
155
+ let(:project_name) { "sidekiq_pro" }
156
+ let(:dependency_name) { "sidekiq-pro" }
157
+ let(:registry_url) { "https://gems.contribsys.com/" }
158
+
159
+ before do
160
+ stub_request(:get, registry_url + "versions").
161
+ with(basic_auth: %w(username password)).
162
+ to_return(status: 404)
163
+ stub_request(:get, registry_url + "api/v1/dependencies").
164
+ with(basic_auth: %w(username password)).
165
+ to_return(status: 404)
166
+ stub_request(:get, registry_url + "specs.4.8.gz").
167
+ with(basic_auth: %w(username password)).
168
+ to_return(
169
+ status: 200,
170
+ body: fixture("ruby", "contribsys_old_index_response")
171
+ )
172
+ stub_request(:get, registry_url + "prerelease_specs.4.8.gz").
173
+ with(basic_auth: %w(username password)).
174
+ to_return(
175
+ status: 200,
176
+ body: fixture("ruby", "contribsys_old_index_prerelease_response")
177
+ )
178
+ end
179
+
180
+ it "returns all versions from the private source" do
181
+ expect(private_registry_versions.length).to eql(70)
182
+ expect(private_registry_versions.min).to eql(Gem::Version.new("1.0.0"))
183
+ expect(private_registry_versions.max).to eql(Gem::Version.new("3.5.2"))
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "native_spec_helper"
4
+ require "shared_contexts"
5
+
6
+ RSpec.describe Functions::FileParser do
7
+ include_context "in a temporary bundler directory"
8
+
9
+ let(:dependency_source) do
10
+ described_class.new(
11
+ lockfile_name: "Gemfile.lock"
12
+ )
13
+ end
14
+
15
+ let(:project_name) { "gemfile" }
16
+
17
+ describe "#parsed_gemfile" do
18
+ subject(:parsed_gemfile) do
19
+ in_tmp_folder do
20
+ dependency_source.parsed_gemfile(gemfile_name: "Gemfile")
21
+ end
22
+ end
23
+
24
+ it "parses gemfile" do
25
+ parsed_gemfile = [
26
+ {
27
+ groups: [:default],
28
+ name: "business",
29
+ requirement: Gem::Requirement.new("~> 1.4.0"),
30
+ source: nil,
31
+ type: :runtime
32
+ },
33
+ {
34
+ groups: [:default],
35
+ name: "statesman",
36
+ requirement: Gem::Requirement.new("~> 1.2.0"),
37
+ source: nil,
38
+ type: :runtime
39
+ }
40
+ ]
41
+ is_expected.to eq(parsed_gemfile)
42
+ end
43
+ end
44
+
45
+ describe "#parsed_gemspec" do
46
+ let!(:gemspec_fixture) do
47
+ fixture("ruby", "gemspecs", "exact")
48
+ end
49
+
50
+ subject(:parsed_gemspec) do
51
+ in_tmp_folder do |tmp_path|
52
+ File.write(File.join(tmp_path, "test.gemspec"), gemspec_fixture)
53
+ dependency_source.parsed_gemspec(gemspec_name: "test.gemspec")
54
+ end
55
+ end
56
+
57
+ it "parses gemspec" do
58
+ parsed_gemspec = [
59
+ {
60
+ groups: nil,
61
+ name: "business",
62
+ requirement: Gem::Requirement.new("= 1.0.0"),
63
+ source: nil,
64
+ type: :runtime
65
+ },
66
+ {
67
+ groups: nil,
68
+ name: "statesman",
69
+ requirement: Gem::Requirement.new("= 1.0.0"),
70
+ source: nil,
71
+ type: :runtime
72
+ }
73
+ ]
74
+ is_expected.to eq(parsed_gemspec)
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "native_spec_helper"
4
+ require "shared_contexts"
5
+
6
+ RSpec.describe Functions::VersionResolver do
7
+ include_context "in a temporary bundler directory"
8
+ include_context "stub rubygems compact index"
9
+
10
+ let(:version_resolver) do
11
+ described_class.new(
12
+ dependency_name: dependency_name,
13
+ dependency_requirements: dependency_requirements,
14
+ gemfile_name: "Gemfile",
15
+ lockfile_name: "Gemfile.lock"
16
+ )
17
+ end
18
+
19
+ let(:dependency_name) { "business" }
20
+ let(:dependency_requirements) do
21
+ [{
22
+ file: "Gemfile",
23
+ requirement: requirement_string,
24
+ groups: [],
25
+ source: source
26
+ }]
27
+ end
28
+ let(:source) { nil }
29
+
30
+ let(:rubygems_url) { "https://index.rubygems.org/api/v1/" }
31
+ let(:old_index_url) { rubygems_url + "dependencies" }
32
+
33
+ describe "#version_details" do
34
+ subject do
35
+ in_tmp_folder { version_resolver.version_details }
36
+ end
37
+
38
+ let(:project_name) { "gemfile" }
39
+ let(:requirement_string) { " >= 0" }
40
+
41
+ its([:version]) { is_expected.to eq(Gem::Version.new("1.4.0")) }
42
+ its([:fetcher]) { is_expected.to eq("Bundler::Fetcher::CompactIndex") }
43
+
44
+ context "with a private gemserver source" do
45
+ include_context "stub rubygems compact index"
46
+
47
+ let(:project_name) { "specified_source" }
48
+ let(:requirement_string) { ">= 0" }
49
+
50
+ before do
51
+ gemfury_url = "https://repo.fury.io/greysteil/"
52
+ gemfury_deps_url = gemfury_url + "api/v1/dependencies"
53
+
54
+ stub_request(:get, gemfury_url + "versions").
55
+ to_return(status: 200, body: fixture("ruby", "gemfury-index"))
56
+ stub_request(:get, gemfury_url + "info/business").to_return(status: 404)
57
+ stub_request(:get, gemfury_deps_url).to_return(status: 200)
58
+ stub_request(:get, gemfury_deps_url + "?gems=business,statesman").
59
+ to_return(status: 200, body: fixture("ruby", "gemfury_response"))
60
+ stub_request(:get, gemfury_deps_url + "?gems=business").
61
+ to_return(status: 200, body: fixture("ruby", "gemfury_response"))
62
+ stub_request(:get, gemfury_deps_url + "?gems=statesman").
63
+ to_return(status: 200, body: fixture("ruby", "gemfury_response"))
64
+ end
65
+
66
+ its([:version]) { is_expected.to eq(Gem::Version.new("1.9.0")) }
67
+ its([:fetcher]) { is_expected.to eq("Bundler::Fetcher::Dependency") }
68
+ end
69
+
70
+ context "with a git source" do
71
+ let(:project_name) { "git_source" }
72
+
73
+ its([:version]) { is_expected.to eq(Gem::Version.new("1.6.0")) }
74
+ its([:fetcher]) { is_expected.to be_nil }
75
+ end
76
+
77
+ context "when Bundler's compact index is down" do
78
+ before do
79
+ stub_request(:get, "https://index.rubygems.org/versions").
80
+ to_return(status: 500, body: "We'll be back soon")
81
+ stub_request(:get, "https://index.rubygems.org/info/public_suffix").
82
+ to_return(status: 500, body: "We'll be back soon")
83
+ stub_request(:get, old_index_url).to_return(status: 200)
84
+ stub_request(:get, old_index_url + "?gems=business,statesman").
85
+ to_return(
86
+ status: 200,
87
+ body: fixture("ruby",
88
+ "rubygems_responses",
89
+ "dependencies-default-gemfile")
90
+ )
91
+ end
92
+
93
+ its([:version]) { is_expected.to eq(Gem::Version.new("1.4.0")) }
94
+ its([:fetcher]) { is_expected.to eq("Bundler::Fetcher::Dependency") }
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rspec/its"
4
+ require "webmock/rspec"
5
+ require "byebug"
6
+
7
+ $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
8
+ $LOAD_PATH.unshift(File.expand_path("../monkey_patches", __dir__))
9
+
10
+ # Bundler monkey patches
11
+ require "definition_ruby_version_patch"
12
+ require "definition_bundler_version_patch"
13
+ require "git_source_patch"
14
+
15
+ require "functions"
16
+
17
+ RSpec.configure do |config|
18
+ config.color = true
19
+ config.order = :rand
20
+ config.mock_with(:rspec) { |mocks| mocks.verify_partial_doubles = true }
21
+ config.raise_errors_for_deprecations!
22
+ end
23
+
24
+ # Duplicated in lib/dependabot/bundler/file_updater/lockfile_updater.rb
25
+ # TODO: Stop sanitizing the lockfile once we have bundler 2 installed
26
+ LOCKFILE_ENDING = /(?<ending>\s*(?:RUBY VERSION|BUNDLED WITH).*)/m.freeze
27
+
28
+ def project_dependency_files(project)
29
+ project_path = File.expand_path(File.join("../../spec/fixtures/projects/bundler1", project))
30
+ Dir.chdir(project_path) do
31
+ # NOTE: Include dotfiles (e.g. .npmrc)
32
+ files = Dir.glob("**/*", File::FNM_DOTMATCH)
33
+ files = files.select { |f| File.file?(f) }
34
+ files.map do |filename|
35
+ content = File.read(filename)
36
+ if filename == "Gemfile.lock"
37
+ content = content.gsub(LOCKFILE_ENDING, "")
38
+ end
39
+ {
40
+ name: filename,
41
+ content: content
42
+ }
43
+ end
44
+ end
45
+ end
46
+
47
+ def fixture(*name)
48
+ File.read(File.join("../../spec/fixtures", File.join(*name)))
49
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/compact_index_client"
4
+ require "bundler/compact_index_client/updater"
5
+
6
+ TMP_DIR_PATH = File.expand_path("../tmp", __dir__)
7
+
8
+ RSpec.shared_context "in a temporary bundler directory" do
9
+ let(:project_name) { "gemfile" }
10
+
11
+ let(:tmp_path) do
12
+ Dir.mkdir(TMP_DIR_PATH) unless Dir.exist?(TMP_DIR_PATH)
13
+ dir = Dir.mktmpdir("native_helper_spec_", TMP_DIR_PATH)
14
+ Pathname.new(dir).expand_path
15
+ end
16
+
17
+ before do
18
+ project_dependency_files(project_name).each do |file|
19
+ File.write(File.join(tmp_path, file[:name]), file[:content])
20
+ end
21
+ end
22
+
23
+ def in_tmp_folder(&block)
24
+ Dir.chdir(tmp_path, &block)
25
+ end
26
+ end
27
+
28
+ RSpec.shared_context "without caching rubygems" do
29
+ before do
30
+ # Stub Bundler to stop it using a cached versions of Rubygems
31
+ allow_any_instance_of(Bundler::CompactIndexClient::Updater).
32
+ to receive(:etag_for).and_return("")
33
+ end
34
+ end
35
+
36
+ RSpec.shared_context "stub rubygems compact index" do
37
+ include_context "without caching rubygems"
38
+
39
+ before do
40
+ # Stub the Rubygems index
41
+ stub_request(:get, "https://index.rubygems.org/versions").
42
+ to_return(
43
+ status: 200,
44
+ body: fixture("ruby", "rubygems_responses", "index")
45
+ )
46
+
47
+ # Stub the Rubygems response for each dependency we have a fixture for
48
+ fixtures =
49
+ Dir[File.join("../../spec", "fixtures", "ruby", "rubygems_responses", "info-*")]
50
+ fixtures.each do |path|
51
+ dep_name = path.split("/").last.gsub("info-", "")
52
+ stub_request(:get, "https://index.rubygems.org/info/#{dep_name}").
53
+ to_return(
54
+ status: 200,
55
+ body: fixture("ruby", "rubygems_responses", "info-#{dep_name}")
56
+ )
57
+ end
58
+ end
59
+ end
@@ -234,11 +234,8 @@ module Dependabot
234
234
  def remove_unnecessary_assignments(node)
235
235
  return unless node.is_a?(Parser::AST::Node)
236
236
 
237
- if unnecessary_assignment?(node) &&
238
- node.children.last&.location.respond_to?(:heredoc_end)
239
- range_to_remove = node.loc.expression.join(
240
- node.children.last.location.heredoc_end
241
- )
237
+ if unnecessary_assignment?(node) && node_includes_heredoc?(node)
238
+ range_to_remove = node.loc.expression.join(find_heredoc_end_range(node))
242
239
  return replace(range_to_remove, '"sanitized"')
243
240
  elsif unnecessary_assignment?(node)
244
241
  return replace(node.loc.expression, '"sanitized"')
@@ -249,6 +246,30 @@ module Dependabot
249
246
  end
250
247
  end
251
248
 
249
+ def node_includes_heredoc?(node)
250
+ find_heredoc_end_range(node)
251
+ end
252
+
253
+ # Performs a depth-first search for the first heredoc in the given
254
+ # Parser::AST::Node.
255
+ #
256
+ # Returns a Parser::Source::Range identifying the location of the end
257
+ # of the heredoc, or nil if no heredoc was found.
258
+ def find_heredoc_end_range(node)
259
+ return unless node.is_a?(Parser::AST::Node)
260
+
261
+ node.children.each do |child|
262
+ next unless child.is_a?(Parser::AST::Node)
263
+
264
+ return child.location.heredoc_end if child.location.respond_to?(:heredoc_end)
265
+
266
+ range = find_heredoc_end_range(child)
267
+ return range if range
268
+ end
269
+
270
+ nil
271
+ end
272
+
252
273
  def unnecessary_assignment?(node)
253
274
  return false unless node.is_a?(Parser::AST::Node)
254
275
  return false unless node.children.first.is_a?(Parser::AST::Node)
@@ -1,30 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "bundler"
3
4
  require "dependabot/shared_helpers"
4
5
 
5
6
  module Dependabot
6
7
  module Bundler
7
8
  module NativeHelpers
8
9
  def self.run_bundler_subprocess(function:, args:, bundler_version:)
9
- SharedHelpers.run_helper_subprocess(
10
- command: helper_path(bundler_version: bundler_version),
11
- function: function,
12
- args: args,
13
- env: {
14
- # Bundler will pick the matching installed major version
15
- "BUNDLER_VERSION" => bundler_version,
16
- # Force bundler to use the helper Gemfile that has been bundled with
17
- # v1, otherwise it will point to core's bundler/Gemfile which will
18
- # be bundled with v2 once it's installed
19
- "BUNDLE_GEMFILE" => File.join(versioned_helper_path(bundler_version: bundler_version), "Gemfile"),
20
- # Unset ruby env set by running dependabot-core with bundle exec,
21
- # forcing bundler to reset them from helpers/v1
22
- "RUBYLIB" => nil,
23
- "RUBYOPT" => nil,
24
- "GEM_PATH" => nil,
25
- "GEM_HOME" => nil
26
- }
27
- )
10
+ # Run helper suprocess with all bundler-related ENV variables removed
11
+ ::Bundler.with_original_env do
12
+ SharedHelpers.run_helper_subprocess(
13
+ command: helper_path(bundler_version: bundler_version),
14
+ function: function,
15
+ args: args,
16
+ env: {
17
+ # Bundler will pick the matching installed major version
18
+ "BUNDLER_VERSION" => bundler_version,
19
+ "BUNDLE_GEMFILE" => File.join(versioned_helper_path(bundler_version: bundler_version), "Gemfile"),
20
+ "BUNDLE_PATH" => File.join(versioned_helper_path(bundler_version: bundler_version), ".bundle")
21
+ }
22
+ )
23
+ end
28
24
  end
29
25
 
30
26
  def self.versioned_helper_path(bundler_version:)
@@ -33,7 +29,7 @@ module Dependabot
33
29
  end
34
30
 
35
31
  def self.helper_path(bundler_version:)
36
- "bundle exec ruby #{File.join(versioned_helper_path(bundler_version: bundler_version), 'run.rb')}"
32
+ "ruby #{File.join(versioned_helper_path(bundler_version: bundler_version), 'run.rb')}"
37
33
  end
38
34
 
39
35
  def self.native_helpers_root
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-bundler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.134.1
4
+ version: 0.137.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-02 00:00:00.000000000 Z
11
+ date: 2021-03-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.134.1
19
+ version: 0.137.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.134.1
26
+ version: 0.137.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: byebug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -100,14 +100,14 @@ dependencies:
100
100
  requirements:
101
101
  - - "~>"
102
102
  - !ruby/object:Gem::Version
103
- version: 1.10.0
103
+ version: 1.11.0
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
108
  - - "~>"
109
109
  - !ruby/object:Gem::Version
110
- version: 1.10.0
110
+ version: 1.11.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: simplecov
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -185,6 +185,7 @@ executables: []
185
185
  extensions: []
186
186
  extra_rdoc_files: []
187
187
  files:
188
+ - helpers/v1/.bundle/config
188
189
  - helpers/v1/.gitignore
189
190
  - helpers/v1/Gemfile
190
191
  - helpers/v1/build
@@ -199,6 +200,12 @@ files:
199
200
  - helpers/v1/monkey_patches/definition_ruby_version_patch.rb
200
201
  - helpers/v1/monkey_patches/git_source_patch.rb
201
202
  - helpers/v1/run.rb
203
+ - helpers/v1/spec/functions/conflicting_dependency_resolver_spec.rb
204
+ - helpers/v1/spec/functions/dependency_source_spec.rb
205
+ - helpers/v1/spec/functions/file_parser_spec.rb
206
+ - helpers/v1/spec/functions/version_resolver_spec.rb
207
+ - helpers/v1/spec/native_spec_helper.rb
208
+ - helpers/v1/spec/shared_contexts.rb
202
209
  - lib/dependabot/bundler.rb
203
210
  - lib/dependabot/bundler/file_fetcher.rb
204
211
  - lib/dependabot/bundler/file_fetcher/child_gemfile_finder.rb