dependabot-bundler 0.138.1 → 0.138.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/v1/build +2 -1
  3. data/helpers/v1/run.rb +16 -0
  4. data/helpers/v1/spec/native_spec_helper.rb +3 -0
  5. data/helpers/v2/.gitignore +1 -2
  6. data/helpers/v2/build +3 -1
  7. data/helpers/v2/lib/functions.rb +141 -13
  8. data/helpers/v2/lib/functions/conflicting_dependency_resolver.rb +86 -0
  9. data/helpers/v2/lib/functions/dependency_source.rb +86 -0
  10. data/helpers/v2/lib/functions/file_parser.rb +106 -0
  11. data/helpers/v2/lib/functions/force_updater.rb +167 -0
  12. data/helpers/v2/lib/functions/lockfile_updater.rb +224 -0
  13. data/helpers/v2/lib/functions/version_resolver.rb +140 -0
  14. data/helpers/v2/monkey_patches/definition_bundler_version_patch.rb +15 -0
  15. data/helpers/v2/monkey_patches/definition_ruby_version_patch.rb +20 -0
  16. data/helpers/v2/monkey_patches/git_source_patch.rb +62 -0
  17. data/helpers/v2/run.rb +15 -1
  18. data/helpers/v2/spec/functions/conflicting_dependency_resolver_spec.rb +133 -0
  19. data/helpers/v2/spec/functions/dependency_source_spec.rb +185 -0
  20. data/helpers/v2/spec/functions/file_parser_spec.rb +142 -0
  21. data/helpers/v2/spec/functions/version_resolver_spec.rb +97 -0
  22. data/helpers/v2/spec/functions_spec.rb +15 -27
  23. data/helpers/v2/spec/native_spec_helper.rb +5 -2
  24. data/helpers/v2/spec/shared_contexts.rb +60 -0
  25. data/lib/dependabot/bundler/file_updater/requirement_replacer.rb +4 -2
  26. data/lib/dependabot/bundler/update_checker/requirements_updater.rb +2 -2
  27. data/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb +3 -1
  28. metadata +18 -5
  29. data/helpers/v2/.bundle/config +0 -2
@@ -0,0 +1,142 @@
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
+
44
+ context "with a git source" do
45
+ let(:project_name) { "git_source" }
46
+
47
+ it "parses gemfile" do
48
+ parsed_gemfile = [
49
+ {
50
+ groups: [:default],
51
+ name: "business",
52
+ requirement: Gem::Requirement.new("~> 1.6.0"),
53
+ source: {
54
+ branch: "master",
55
+ ref: "a1b78a9",
56
+ type: "git",
57
+ url: "git@github.com:gocardless/business"
58
+ },
59
+ type: :runtime
60
+ },
61
+ {
62
+ groups: [:default],
63
+ name: "statesman",
64
+ requirement: Gem::Requirement.new("~> 1.2.0"),
65
+ source: nil,
66
+ type: :runtime
67
+ },
68
+ {
69
+ groups: [:default],
70
+ name: "prius",
71
+ requirement: Gem::Requirement.new(">= 0"),
72
+ source: {
73
+ branch: "master",
74
+ ref: "master",
75
+ type: "git",
76
+ url: "https://github.com/gocardless/prius"
77
+ },
78
+ type: :runtime
79
+ },
80
+ {
81
+ groups: [:default],
82
+ name: "que",
83
+ requirement: Gem::Requirement.new(">= 0"),
84
+ source: {
85
+ branch: "master",
86
+ ref: "v0.11.6",
87
+ type: "git",
88
+ url: "git@github.com:chanks/que"
89
+ },
90
+ type: :runtime
91
+ },
92
+ {
93
+ groups: [:default],
94
+ name: "uk_phone_numbers",
95
+ requirement: Gem::Requirement.new(">= 0"),
96
+ source: {
97
+ branch: "master",
98
+ ref: "master",
99
+ type: "git",
100
+ url: "http://github.com/gocardless/uk_phone_numbers"
101
+ },
102
+ type: :runtime
103
+ }
104
+ ]
105
+ is_expected.to eq(parsed_gemfile)
106
+ end
107
+ end
108
+ end
109
+
110
+ describe "#parsed_gemspec" do
111
+ let!(:gemspec_fixture) do
112
+ fixture("ruby", "gemspecs", "exact")
113
+ end
114
+
115
+ subject(:parsed_gemspec) do
116
+ in_tmp_folder do |tmp_path|
117
+ File.write(File.join(tmp_path, "test.gemspec"), gemspec_fixture)
118
+ dependency_source.parsed_gemspec(gemspec_name: "test.gemspec")
119
+ end
120
+ end
121
+
122
+ it "parses gemspec" do
123
+ parsed_gemspec = [
124
+ {
125
+ groups: nil,
126
+ name: "business",
127
+ requirement: Gem::Requirement.new("= 1.0.0"),
128
+ source: nil,
129
+ type: :runtime
130
+ },
131
+ {
132
+ groups: nil,
133
+ name: "statesman",
134
+ requirement: Gem::Requirement.new("= 1.0.0"),
135
+ source: nil,
136
+ type: :runtime
137
+ }
138
+ ]
139
+ is_expected.to eq(parsed_gemspec)
140
+ end
141
+ end
142
+ 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
@@ -1,36 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "native_spec_helper"
4
+ require "shared_contexts"
4
5
 
5
6
  RSpec.describe Functions do
6
- # Verify v1 method signatures are exist, but raise as NYI
7
- {
8
- parsed_gemfile: [ :lockfile_name, :gemfile_name, :dir ],
9
- parsed_gemspec: [ :lockfile_name, :gemspec_name, :dir ],
10
- vendor_cache_dir: [ :dir ],
11
- update_lockfile: [ :dir, :gemfile_name, :lockfile_name, :using_bundler2, :credentials, :dependencies ],
12
- force_update: [ :dir, :dependency_name, :target_version, :gemfile_name, :lockfile_name, :using_bundler2,
13
- :credentials, :update_multiple_dependencies ],
14
- dependency_source_type: [ :gemfile_name, :dependency_name, :dir, :credentials ],
15
- depencency_source_latest_git_version: [ :gemfile_name, :dependency_name, :dir, :credentials, :dependency_source_url,
16
- :dependency_source_branch ],
17
- private_registry_versions: [:gemfile_name, :dependency_name, :dir, :credentials ],
18
- resolve_version: [:dependency_name, :dependency_requirements, :gemfile_name, :lockfile_name, :using_bundler2,
19
- :dir, :credentials],
20
- jfrog_source: [:dir, :gemfile_name, :credentials, :using_bundler2],
21
- git_specs: [:dir, :gemfile_name, :credentials, :using_bundler2],
22
- set_bundler_flags_and_credentials: [:dir, :credentials, :using_bundler2],
23
- conflicting_dependencies: [:dir, :dependency_name, :target_version, :lockfile_name, :using_bundler2, :credentials]
24
- }.each do |function, kwargs|
25
- describe "::#{function}" do
26
- let(:args) do
27
- kwargs.inject({}) do |args, keyword|
28
- args.merge({ keyword => anything })
29
- end
30
- end
7
+ include_context "in a temporary bundler directory"
8
+
9
+ describe "#jfrog_source" do
10
+ let(:project_name) { "jfrog_source" }
11
+
12
+ it "returns the jfrog source" do
13
+ in_tmp_folder do
14
+ jfrog_source = Functions.jfrog_source(
15
+ dir: tmp_path,
16
+ gemfile_name: "Gemfile",
17
+ credentials: {},
18
+ using_bundler2: true
19
+ )
31
20
 
32
- it "raises a NYI" do
33
- expect { Functions.send(function, **args) }.to raise_error(Functions::NotImplementedError)
21
+ expect(jfrog_source).to eq("test.jfrog.io")
34
22
  end
35
23
  end
36
24
  end
@@ -5,8 +5,7 @@ require "webmock/rspec"
5
5
  require "byebug"
6
6
 
7
7
  $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
8
- # TODO: Fork `v1/monkey_patches` into `v2/monkey_patches` ?
9
- $LOAD_PATH.unshift(File.expand_path("../../v1/monkey_patches", __dir__))
8
+ $LOAD_PATH.unshift(File.expand_path("../monkey_patches", __dir__))
10
9
 
11
10
  # Bundler monkey patches
12
11
  require "definition_ruby_version_patch"
@@ -27,7 +26,11 @@ end
27
26
  LOCKFILE_ENDING = /(?<ending>\s*(?:RUBY VERSION|BUNDLED WITH).*)/m.freeze
28
27
 
29
28
  def project_dependency_files(project)
29
+ # TODO: Retrieve files from bundler2 folder once it is fully up to date
30
30
  project_path = File.expand_path(File.join("../../spec/fixtures/projects/bundler1", project))
31
+
32
+ raise "Fixture does not exist for project: '#{project}'" unless Dir.exist?(project_path)
33
+
31
34
  Dir.chdir(project_path) do
32
35
  # NOTE: Include dotfiles (e.g. .npmrc)
33
36
  files = Dir.glob("**/*", File::FNM_DOTMATCH)
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "tmpdir"
4
+ require "bundler/compact_index_client"
5
+ require "bundler/compact_index_client/updater"
6
+
7
+ TMP_DIR_PATH = File.expand_path("../tmp", __dir__)
8
+
9
+ RSpec.shared_context "in a temporary bundler directory" do
10
+ let(:project_name) { "gemfile" }
11
+
12
+ let(:tmp_path) do
13
+ Dir.mkdir(TMP_DIR_PATH) unless Dir.exist?(TMP_DIR_PATH)
14
+ dir = Dir.mktmpdir("native_helper_spec_", TMP_DIR_PATH)
15
+ Pathname.new(dir).expand_path
16
+ end
17
+
18
+ before do
19
+ project_dependency_files(project_name).each do |file|
20
+ File.write(File.join(tmp_path, file[:name]), file[:content])
21
+ end
22
+ end
23
+
24
+ def in_tmp_folder(&block)
25
+ Dir.chdir(tmp_path, &block)
26
+ end
27
+ end
28
+
29
+ RSpec.shared_context "without caching rubygems" do
30
+ before do
31
+ # Stub Bundler to stop it using a cached versions of Rubygems
32
+ allow_any_instance_of(Bundler::CompactIndexClient::Updater).
33
+ to receive(:etag_for).and_return("")
34
+ end
35
+ end
36
+
37
+ RSpec.shared_context "stub rubygems compact index" do
38
+ include_context "without caching rubygems"
39
+
40
+ before do
41
+ # Stub the Rubygems index
42
+ stub_request(:get, "https://index.rubygems.org/versions").
43
+ to_return(
44
+ status: 200,
45
+ body: fixture("ruby", "rubygems_responses", "index")
46
+ )
47
+
48
+ # Stub the Rubygems response for each dependency we have a fixture for
49
+ fixtures =
50
+ Dir[File.join("../../spec", "fixtures", "ruby", "rubygems_responses", "info-*")]
51
+ fixtures.each do |path|
52
+ dep_name = path.split("/").last.gsub("info-", "")
53
+ stub_request(:get, "https://index.rubygems.org/info/#{dep_name}").
54
+ to_return(
55
+ status: 200,
56
+ body: fixture("ruby", "rubygems_responses", "info-#{dep_name}")
57
+ )
58
+ end
59
+ end
60
+ end
@@ -167,6 +167,8 @@ module Dependabot
167
167
  req_string.include?(" ")
168
168
  end
169
169
 
170
+ EQUALITY_OPERATOR = /(?<![<>!])=/.freeze
171
+
170
172
  def use_equality_operator?(requirement_nodes)
171
173
  return true if requirement_nodes.none?
172
174
 
@@ -178,7 +180,7 @@ module Dependabot
178
180
  requirement_nodes.first.children.first.loc.expression.source
179
181
  end
180
182
 
181
- req_string.match?(/(?<![<>])=/)
183
+ req_string.match?(EQUALITY_OPERATOR)
182
184
  end
183
185
 
184
186
  def new_requirement_string(quote_characters:,
@@ -203,7 +205,7 @@ module Dependabot
203
205
  # Gem::Requirement serializes exact matches as a string starting
204
206
  # with `=`. We may need to remove that equality operator if it
205
207
  # wasn't used originally.
206
- tmp_req = tmp_req.gsub(/(?<![<>])=/, "") unless use_equality_operator
208
+ tmp_req = tmp_req.gsub(EQUALITY_OPERATOR, "") unless use_equality_operator
207
209
 
208
210
  tmp_req.strip
209
211
  end
@@ -188,7 +188,7 @@ module Dependabot
188
188
  req
189
189
  end
190
190
  when "<", "<=" then [update_greatest_version(req, latest_version)]
191
- when "~>" then convert_twidle_to_range(req, latest_version)
191
+ when "~>" then convert_twiddle_to_range(req, latest_version)
192
192
  when "!=" then []
193
193
  when ">", ">=" then raise UnfixableRequirement
194
194
  else raise "Unexpected operation for requirement: #{op}"
@@ -214,7 +214,7 @@ module Dependabot
214
214
  end
215
215
  end
216
216
 
217
- def convert_twidle_to_range(requirement, version_to_be_permitted)
217
+ def convert_twiddle_to_range(requirement, version_to_be_permitted)
218
218
  version = requirement.requirements.first.last
219
219
  version = version.release if version.prerelease?
220
220
 
@@ -187,7 +187,9 @@ module Dependabot
187
187
  end
188
188
 
189
189
  def jfrog_source
190
- in_a_native_bundler_context(error_handling: false) do |dir|
190
+ return @jfrog_source unless defined?(@jfrog_source)
191
+
192
+ @jfrog_source = in_a_native_bundler_context(error_handling: false) do |dir|
191
193
  NativeHelpers.run_bundler_subprocess(
192
194
  bundler_version: bundler_version,
193
195
  function: "jfrog_source",
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.138.1
4
+ version: 0.138.6
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-17 00:00:00.000000000 Z
11
+ date: 2021-03-29 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.138.1
19
+ version: 0.138.6
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.138.1
26
+ version: 0.138.6
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: byebug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -206,14 +206,27 @@ files:
206
206
  - helpers/v1/spec/functions/version_resolver_spec.rb
207
207
  - helpers/v1/spec/native_spec_helper.rb
208
208
  - helpers/v1/spec/shared_contexts.rb
209
- - helpers/v2/.bundle/config
210
209
  - helpers/v2/.gitignore
211
210
  - helpers/v2/Gemfile
212
211
  - helpers/v2/build
213
212
  - helpers/v2/lib/functions.rb
213
+ - helpers/v2/lib/functions/conflicting_dependency_resolver.rb
214
+ - helpers/v2/lib/functions/dependency_source.rb
215
+ - helpers/v2/lib/functions/file_parser.rb
216
+ - helpers/v2/lib/functions/force_updater.rb
217
+ - helpers/v2/lib/functions/lockfile_updater.rb
218
+ - helpers/v2/lib/functions/version_resolver.rb
219
+ - helpers/v2/monkey_patches/definition_bundler_version_patch.rb
220
+ - helpers/v2/monkey_patches/definition_ruby_version_patch.rb
221
+ - helpers/v2/monkey_patches/git_source_patch.rb
214
222
  - helpers/v2/run.rb
223
+ - helpers/v2/spec/functions/conflicting_dependency_resolver_spec.rb
224
+ - helpers/v2/spec/functions/dependency_source_spec.rb
225
+ - helpers/v2/spec/functions/file_parser_spec.rb
226
+ - helpers/v2/spec/functions/version_resolver_spec.rb
215
227
  - helpers/v2/spec/functions_spec.rb
216
228
  - helpers/v2/spec/native_spec_helper.rb
229
+ - helpers/v2/spec/shared_contexts.rb
217
230
  - lib/dependabot/bundler.rb
218
231
  - lib/dependabot/bundler/file_fetcher.rb
219
232
  - lib/dependabot/bundler/file_fetcher/child_gemfile_finder.rb