dependabot-bundler 0.136.0 → 0.138.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.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/v1/Gemfile +8 -3
  3. data/helpers/v1/build +2 -2
  4. data/helpers/v1/spec/functions/conflicting_dependency_resolver_spec.rb +133 -0
  5. data/helpers/v1/spec/functions/dependency_source_spec.rb +187 -0
  6. data/helpers/v1/spec/functions/file_parser_spec.rb +77 -0
  7. data/helpers/v1/spec/functions/version_resolver_spec.rb +97 -0
  8. data/helpers/v1/spec/native_spec_helper.rb +49 -0
  9. data/helpers/v1/spec/shared_contexts.rb +59 -0
  10. data/helpers/v2/.bundle/config +2 -0
  11. data/helpers/v2/.gitignore +9 -0
  12. data/helpers/v2/Gemfile +12 -0
  13. data/helpers/v2/build +23 -0
  14. data/helpers/v2/lib/functions.rb +67 -0
  15. data/helpers/v2/run.rb +30 -0
  16. data/helpers/v2/spec/functions_spec.rb +37 -0
  17. data/helpers/v2/spec/native_spec_helper.rb +50 -0
  18. data/lib/dependabot/bundler/file_parser.rb +13 -1
  19. data/lib/dependabot/bundler/file_updater.rb +3 -2
  20. data/lib/dependabot/bundler/file_updater/lockfile_updater.rb +4 -3
  21. data/lib/dependabot/bundler/helpers.rb +15 -3
  22. data/lib/dependabot/bundler/native_helpers.rb +8 -1
  23. data/lib/dependabot/bundler/update_checker.rb +12 -6
  24. data/lib/dependabot/bundler/update_checker/conflicting_dependency_resolver.rb +5 -2
  25. data/lib/dependabot/bundler/update_checker/force_updater.rb +6 -3
  26. data/lib/dependabot/bundler/update_checker/latest_version_finder.rb +6 -3
  27. data/lib/dependabot/bundler/update_checker/latest_version_finder/dependency_source.rb +5 -3
  28. data/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb +0 -4
  29. data/lib/dependabot/bundler/update_checker/version_resolver.rb +8 -4
  30. metadata +18 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 393bf9b8a90811c0809226907cbff66998c3fb481f16d23115cbf4e22444ed8e
4
- data.tar.gz: 7e334d28a93224445785f7f23215d782bc3b2c70b177faf9f35276604ff1adae
3
+ metadata.gz: '098bacb84fe60a2f7e46f7f272f89623567b18cd9ce7f21b9450c6ced8c43ce3'
4
+ data.tar.gz: f13d6f9506e266880ded948007e0df3050962a16efa6ec323e870804dbce5b93
5
5
  SHA512:
6
- metadata.gz: efbd895bfb249b021160b2806b74449741d4d7dfb1e955436d3ef6919683b8465f8574708be01b9a3fca992dc5df06e055647d4236aea66b219fe3c5f48ade2f
7
- data.tar.gz: 21d703a2ad5dfe9eeba687172f558ec0cf7abddd5e6b4f9dbf72d05dead39b6a5764857903982d2fa3809fa19b5acf75c2d3b006c5c5ce6e9fc80453f3f7460b
6
+ metadata.gz: 672c92cf4c9dbafd99e67516d085c8a81ab9cedfc4ef0c1b9e1d1fc70706e19698013ccf546c653bddc857b9a58debd5112ad2c2dddd40abc02d5afac8c3c0fa
7
+ data.tar.gz: a89c52b1b2b0b7a7cd14b2d9186d6b10d29e63bc29bf890b4e2e74931eaa1ce828e5e8e2117079887bcbee5c85dacf5903092f75febb430c3ef7f107c0c6151d
data/helpers/v1/Gemfile CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- # NOTE: This is intentionally left blank as it's currently only used to force
6
- # bundler to use v1 when executing native helpers by pointing the BUNDLE_GEMFILE
7
- # 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
@@ -20,5 +20,5 @@ cp -r \
20
20
  cd "$install_dir"
21
21
 
22
22
  # NOTE: Sets `BUNDLED WITH` to match the installed v1 version in Gemfile.lock
23
- # forcing specs and native helpers to run with the same version
24
- 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