dependabot-bundler 0.153.0 → 0.154.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/helpers/v1/build +1 -1
  3. data/helpers/v1/lib/functions.rb +2 -2
  4. data/helpers/v1/lib/functions/dependency_source.rb +3 -1
  5. data/helpers/v1/lib/functions/file_parser.rb +5 -7
  6. data/helpers/v1/lib/functions/force_updater.rb +2 -0
  7. data/helpers/v1/lib/functions/lockfile_updater.rb +13 -11
  8. data/helpers/v1/lib/functions/version_resolver.rb +5 -7
  9. data/helpers/v1/monkey_patches/git_source_patch.rb +1 -3
  10. data/helpers/v1/run.rb +3 -3
  11. data/helpers/v1/spec/functions/dependency_source_spec.rb +8 -8
  12. data/helpers/v1/spec/functions/file_parser_spec.rb +5 -8
  13. data/helpers/v1/spec/functions/force_updater_spec.rb +58 -0
  14. data/helpers/v1/spec/functions/version_resolver_spec.rb +8 -0
  15. data/helpers/v1/spec/native_spec_helper.rb +1 -3
  16. data/helpers/v2/build +1 -1
  17. data/helpers/v2/lib/functions.rb +0 -2
  18. data/helpers/v2/lib/functions/dependency_source.rb +3 -1
  19. data/helpers/v2/lib/functions/file_parser.rb +5 -7
  20. data/helpers/v2/lib/functions/force_updater.rb +2 -0
  21. data/helpers/v2/lib/functions/lockfile_updater.rb +6 -3
  22. data/helpers/v2/lib/functions/version_resolver.rb +5 -7
  23. data/helpers/v2/monkey_patches/git_source_patch.rb +1 -3
  24. data/helpers/v2/run.rb +4 -2
  25. data/helpers/v2/spec/functions/dependency_source_spec.rb +8 -8
  26. data/helpers/v2/spec/functions/file_parser_spec.rb +12 -15
  27. data/helpers/v2/spec/functions/force_updater_spec.rb +58 -0
  28. data/helpers/v2/spec/functions/version_resolver_spec.rb +8 -0
  29. data/helpers/v2/spec/functions_spec.rb +34 -1
  30. data/helpers/v2/spec/native_spec_helper.rb +2 -5
  31. data/lib/dependabot/bundler/file_updater/ruby_requirement_setter.rb +3 -3
  32. data/lib/dependabot/bundler/native_helpers.rb +1 -2
  33. data/lib/dependabot/bundler/update_checker/latest_version_finder.rb +3 -6
  34. data/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb +4 -1
  35. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec91f10e65aef27d7201abd0c2bf2bc1572c2d58df66cf2b45ea8d6d33763e3f
4
- data.tar.gz: 73cdc686c5e9e46c4415d55a2121c67c02357baf3d47da58fe1df3f1851ab3c6
3
+ metadata.gz: db9d3b38b9de6ef0b765e7cbec3928e84e8bad183050d6ee2823320cb77ec5c2
4
+ data.tar.gz: 25113301bb42ea306542906e45a6c4b184d6496d429f7796299174f493ebef71
5
5
  SHA512:
6
- metadata.gz: 043c8707e4111cf0c824c99d2390c852a40a998aad11cafe2e6fe34a1f2c234a7644f90d2790911c35ec03721389a897b6f976a5eb32568dd443bde8f2381491
7
- data.tar.gz: 66e8c805e2146d22f56aa7b8f4a9740308ec27b488bf9c7b352a68f11fa3f128a76dba712f0d6f8910fa5f8e111f8bfc2c2ae788d7726927c51721da2cda851d
6
+ metadata.gz: 49e53c4d9b41658f0f4c162f97c5f4ba963bdb864f1263bd858dafd9b8c08113cd6ec910eb694ec8b755e17195e135ad04037fbafdf1570f41f031a3203ce51b
7
+ data.tar.gz: f534780eec5ec4645bd3036365a8b80152b92043de14964461e1366d734469a3cc61919f101774cf00c4287e9c950f751e114cc7e50a640aa7ba0f1b1318b5d0
data/helpers/v1/build CHANGED
@@ -20,6 +20,6 @@ cd "$install_dir"
20
20
 
21
21
  # NOTE: Sets `BUNDLED WITH` to match the installed v1 version in Gemfile.lock
22
22
  # forcing native helpers to run with the same version
23
- BUNDLER_VERSION=2 bundle config set --local path ".bundle"
23
+ BUNDLER_VERSION=1 bundle config set --local path ".bundle"
24
24
  BUNDLER_VERSION=1 bundle config set --local without "test"
25
25
  BUNDLER_VERSION=1 bundle install
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "functions/file_parser"
2
4
  require "functions/force_updater"
3
5
  require "functions/lockfile_updater"
@@ -124,8 +126,6 @@ module Functions
124
126
  ).conflicting_dependencies
125
127
  end
126
128
 
127
- private
128
-
129
129
  def self.set_bundler_flags_and_credentials(dir:, credentials:)
130
130
  dir = dir ? Pathname.new(dir) : dir
131
131
  Bundler.instance_variable_set(:@root, dir)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Functions
2
4
  class DependencySource
3
5
  attr_reader :gemfile_name, :dependency_name
@@ -66,7 +68,7 @@ module Functions
66
68
  return @specified_source if defined? @specified_source
67
69
 
68
70
  @specified_source = definition.dependencies.
69
- find { |dep| dep.name == dependency_name }&.source
71
+ find { |dep| dep.name == dependency_name }&.source
70
72
  end
71
73
 
72
74
  def default_source
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Functions
2
4
  class FileParser
3
5
  def initialize(lockfile_name:)
@@ -39,7 +41,7 @@ module Functions
39
41
  end
40
42
 
41
43
  def source_from_lockfile(dependency_name)
42
- parsed_lockfile&.specs.find { |s| s.name == dependency_name }&.source
44
+ parsed_lockfile&.specs&.find { |s| s.name == dependency_name }&.source
43
45
  end
44
46
 
45
47
  def source_for(dependency)
@@ -54,12 +56,8 @@ module Functions
54
56
  return nil if default_rubygems?(source)
55
57
 
56
58
  details = { type: source.class.name.split("::").last.downcase }
57
- if source.is_a?(Bundler::Source::Git)
58
- details.merge!(git_source_details(source))
59
- end
60
- if source.is_a?(Bundler::Source::Rubygems)
61
- details[:url] = source.remotes.first.to_s
62
- end
59
+ details.merge!(git_source_details(source)) if source.is_a?(Bundler::Source::Git)
60
+ details[:url] = source.remotes.first.to_s if source.is_a?(Bundler::Source::Rubygems)
63
61
  details
64
62
  end
65
63
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Functions
2
4
  class ForceUpdater
3
5
  class TransitiveDependencyError < StandardError; end
@@ -1,12 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
4
+
1
5
  module Functions
2
6
  class LockfileUpdater
3
7
  RETRYABLE_ERRORS = [Bundler::HTTPError].freeze
4
8
  GEM_NOT_FOUND_ERROR_REGEX =
5
- /
6
- locked\sto\s(?<name>[^\s]+)\s\(|
7
- not\sfind\s(?<name>[^\s]+)-\d|
8
- has\s(?<name>[^\s]+)\slocked\sat
9
- /x.freeze
9
+ /
10
+ locked\sto\s(?<name>[^\s]+)\s\(|
11
+ not\sfind\s(?<name>[^\s]+)-\d|
12
+ has\s(?<name>[^\s]+)\slocked\sat
13
+ /x.freeze
10
14
 
11
15
  def initialize(gemfile_name:, lockfile_name:, dependencies:)
12
16
  @gemfile_name = gemfile_name
@@ -22,7 +26,7 @@ module Functions
22
26
 
23
27
  attr_reader :gemfile_name, :lockfile_name, :dependencies
24
28
 
25
- def generate_lockfile
29
+ def generate_lockfile # rubocop:disable Metrics/PerceivedComplexity
26
30
  dependencies_to_unlock = dependencies.map { |d| d.fetch("name") }
27
31
 
28
32
  begin
@@ -135,7 +139,7 @@ module Functions
135
139
  raise unless error.message.match?(GEM_NOT_FOUND_ERROR_REGEX)
136
140
 
137
141
  gem_name = error.message.match(GEM_NOT_FOUND_ERROR_REGEX).
138
- named_captures["name"]
142
+ named_captures["name"]
139
143
  raise if dependencies_to_unlock.include?(gem_name)
140
144
 
141
145
  dependencies_to_unlock << gem_name
@@ -161,9 +165,7 @@ module Functions
161
165
  end.compact.map(&:name)
162
166
 
163
167
  # If there are specific dependencies we can unlock, unlock them
164
- if potentials_deps.any?
165
- return dependencies_to_unlock.append(*potentials_deps)
166
- end
168
+ return dependencies_to_unlock.append(*potentials_deps) if potentials_deps.any?
167
169
 
168
170
  # Fall back to unlocking *all* sub-dependencies. This is required
169
171
  # because Bundler's VersionConflict objects don't include enough
@@ -205,7 +207,7 @@ module Functions
205
207
  defn_dep.source.is_a?(Bundler::Source::Git)
206
208
  defn_dep.source.unlock!
207
209
  elsif Gem::Version.correct?(dep.fetch("version"))
208
- new_req = Gem::Requirement.create("= #{dep.fetch("version")}")
210
+ new_req = Gem::Requirement.create("= #{dep.fetch('version')}")
209
211
  old_reqs[dep.fetch("name")] = defn_dep.requirement
210
212
  defn_dep.instance_variable_set(:@requirement, new_req)
211
213
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Functions
2
4
  class VersionResolver
3
5
  GEM_NOT_FOUND_ERROR_REGEX = /locked to (?<name>[^\s]+) \(/.freeze
@@ -20,9 +22,7 @@ module Functions
20
22
  # included in a gemspec, it's because the Gemfile didn't import
21
23
  # the gemspec. This is unusual, but the correct behaviour if/when
22
24
  # it happens is to behave as if the repo was gemspec-only.
23
- if dep.nil? && dependency_requirements.any?
24
- return "latest"
25
- end
25
+ return "latest" if dep.nil? && dependency_requirements.any?
26
26
 
27
27
  # Otherwise, if the dependency wasn't found it's because it is a
28
28
  # subdependency that was removed when attempting to update it.
@@ -38,9 +38,7 @@ module Functions
38
38
  ruby_version: ruby_version,
39
39
  fetcher: fetcher_class(dep)
40
40
  }
41
- if dep.source.instance_of?(::Bundler::Source::Git)
42
- details[:commit_sha] = dep.source.revision
43
- end
41
+ details[:commit_sha] = dep.source.revision if dep.source.instance_of?(::Bundler::Source::Git)
44
42
  details
45
43
  end
46
44
 
@@ -92,7 +90,7 @@ module Functions
92
90
  end
93
91
 
94
92
  def build_definition(dependencies_to_unlock)
95
- # Note: we lock shared dependencies to avoid any top-level
93
+ # NOTE: we lock shared dependencies to avoid any top-level
96
94
  # dependencies getting unlocked (which would happen if they were
97
95
  # also subdependencies of the dependency being unlocked)
98
96
  ::Bundler::Definition.build(
@@ -41,9 +41,7 @@ module Bundler
41
41
  $LOAD_PATH.shift until $LOAD_PATH.empty?
42
42
  reduced_load_paths.each { |p| $LOAD_PATH << p }
43
43
 
44
- if destination.relative?
45
- destination = destination.expand_path(Bundler.root)
46
- end
44
+ destination = destination.expand_path(Bundler.root) if destination.relative?
47
45
  Dir["#{destination}/#{@glob}"].each do |spec_path|
48
46
  # Evaluate gemspecs and cache the result. Gemspecs
49
47
  # in git might require git or other dependencies.
data/helpers/v1/run.rb CHANGED
@@ -13,7 +13,7 @@ require "git_source_patch"
13
13
 
14
14
  require "functions"
15
15
 
16
- MAX_BUNDLER_VERSION="2.0.0"
16
+ MAX_BUNDLER_VERSION = "2.0.0"
17
17
 
18
18
  def validate_bundler_version!
19
19
  return true if correct_bundler_version?
@@ -38,9 +38,9 @@ begin
38
38
  args = request["args"].transform_keys(&:to_sym)
39
39
 
40
40
  output({ result: Functions.send(function, **args) })
41
- rescue => error
41
+ rescue StandardError => e
42
42
  output(
43
- { error: error.message, error_class: error.class, trace: error.backtrace }
43
+ { error: e.message, error_class: e.class, trace: e.backtrace }
44
44
  )
45
45
  exit(1)
46
46
  end
@@ -40,10 +40,10 @@ RSpec.describe Functions::DependencySource do
40
40
 
41
41
  it "returns all versions from the private source" do
42
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
- ])
43
+ Gem::Version.new("1.5.0"),
44
+ Gem::Version.new("1.9.0"),
45
+ Gem::Version.new("1.10.0.beta")
46
+ ])
47
47
  end
48
48
 
49
49
  context "specified as the default source" do
@@ -51,10 +51,10 @@ RSpec.describe Functions::DependencySource do
51
51
 
52
52
  it "returns all versions from the private source" do
53
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
- ])
54
+ Gem::Version.new("1.5.0"),
55
+ Gem::Version.new("1.9.0"),
56
+ Gem::Version.new("1.10.0.beta")
57
+ ])
58
58
  end
59
59
  end
60
60
 
@@ -12,9 +12,9 @@ RSpec.describe Functions::FileParser do
12
12
  )
13
13
  end
14
14
 
15
- let(:project_name) { "gemfile" }
16
-
17
15
  describe "#parsed_gemfile" do
16
+ let(:project_name) { "gemfile" }
17
+
18
18
  subject(:parsed_gemfile) do
19
19
  in_tmp_folder do
20
20
  dependency_source.parsed_gemfile(gemfile_name: "Gemfile")
@@ -43,14 +43,11 @@ RSpec.describe Functions::FileParser do
43
43
  end
44
44
 
45
45
  describe "#parsed_gemspec" do
46
- let!(:gemspec_fixture) do
47
- fixture("ruby", "gemspecs", "exact")
48
- end
46
+ let(:project_name) { "gemfile_exact" }
49
47
 
50
48
  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")
49
+ in_tmp_folder do |_tmp_path|
50
+ dependency_source.parsed_gemspec(gemspec_name: "example.gemspec")
54
51
  end
55
52
  end
56
53
 
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "native_spec_helper"
4
+ require "shared_contexts"
5
+
6
+ RSpec.describe Functions::ForceUpdater do
7
+ include_context "in a temporary bundler directory"
8
+ include_context "stub rubygems compact index"
9
+
10
+ let(:force_updater) do
11
+ described_class.new(
12
+ dependency_name: dependency_name,
13
+ target_version: target_version,
14
+ gemfile_name: gemfile_name,
15
+ lockfile_name: lockfile_name,
16
+ update_multiple_dependencies: update_multiple_dependencies
17
+ )
18
+ end
19
+ let(:gemfile_name) { "Gemfile" }
20
+ let(:lockfile_name) { "Gemfile.lock" }
21
+ let(:update_multiple_dependencies) { true }
22
+
23
+ describe "#run" do
24
+ subject(:force_update) do
25
+ in_tmp_folder { force_updater.run }
26
+ end
27
+
28
+ context "with a version conflict" do
29
+ let(:target_version) { "3.6.0" }
30
+ let(:dependency_name) { "rspec-support" }
31
+ let(:project_name) { "version_conflict" }
32
+
33
+ it "updates the conflicting dependencies" do
34
+ updated_deps, _specs = force_update
35
+ expect(updated_deps).to eq([{ name: "rspec-support" }, { name: "rspec-mocks" }])
36
+ end
37
+
38
+ context "when updating a single dependency" do
39
+ let(:update_multiple_dependencies) { false }
40
+
41
+ it { expect { force_update }.to raise_error(Bundler::VersionConflict) }
42
+ end
43
+ end
44
+
45
+ context "with a version conflict in gems rb" do
46
+ let(:target_version) { "3.6.0" }
47
+ let(:dependency_name) { "rspec-support" }
48
+ let(:project_name) { "version_conflict_gems_rb" }
49
+ let(:gemfile_name) { "gems.rb" }
50
+ let(:lockfile_name) { "gems.locked" }
51
+
52
+ it "updates the conflicting dependencies" do
53
+ updated_deps, _specs = force_update
54
+ expect(updated_deps).to eq([{ name: "rspec-support" }, { name: "rspec-mocks" }])
55
+ end
56
+ end
57
+ end
58
+ end
@@ -92,5 +92,13 @@ RSpec.describe Functions::VersionResolver do
92
92
  its([:version]) { is_expected.to eq(Gem::Version.new("1.4.0")) }
93
93
  its([:fetcher]) { is_expected.to eq("Bundler::Fetcher::Dependency") }
94
94
  end
95
+
96
+ context "with no update possible due to a version conflict" do
97
+ let(:project_name) { "version_conflict_with_listed_subdep" }
98
+ let(:dependency_name) { "rspec-mocks" }
99
+ let(:requirement_string) { ">= 0" }
100
+
101
+ its([:version]) { is_expected.to eq(Gem::Version.new("3.6.0")) }
102
+ end
95
103
  end
96
104
  end
@@ -36,9 +36,7 @@ def project_dependency_files(project)
36
36
  files = files.select { |f| File.file?(f) }
37
37
  files.map do |filename|
38
38
  content = File.read(filename)
39
- if filename == "Gemfile.lock"
40
- content = content.gsub(LOCKFILE_ENDING, "")
41
- end
39
+ content = content.gsub(LOCKFILE_ENDING, "") if filename == "Gemfile.lock"
42
40
  {
43
41
  name: filename,
44
42
  content: content
data/helpers/v2/build CHANGED
@@ -18,7 +18,7 @@ cp -r \
18
18
 
19
19
  cd "$install_dir"
20
20
 
21
- # NOTE: Sets `BUNDLED WITH` to match the installed v1 version in Gemfile.lock
21
+ # NOTE: Sets `BUNDLED WITH` to match the installed v2 version in Gemfile.lock
22
22
  # forcing specs and native helpers to run with the same version
23
23
  BUNDLER_VERSION=2 bundle config set --local path ".bundle"
24
24
  BUNDLER_VERSION=2 bundle config set --local without "test"
@@ -128,8 +128,6 @@ module Functions
128
128
  ).conflicting_dependencies
129
129
  end
130
130
 
131
- private
132
-
133
131
  def self.set_bundler_flags_and_credentials(dir:, credentials:)
134
132
  dir = dir ? Pathname.new(dir) : dir
135
133
  Bundler.instance_variable_set(:@root, dir)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Functions
2
4
  class DependencySource
3
5
  attr_reader :gemfile_name, :dependency_name
@@ -66,7 +68,7 @@ module Functions
66
68
  return @specified_source if defined? @specified_source
67
69
 
68
70
  @specified_source = definition.dependencies.
69
- find { |dep| dep.name == dependency_name }&.source
71
+ find { |dep| dep.name == dependency_name }&.source
70
72
  end
71
73
 
72
74
  def default_source
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Functions
2
4
  class FileParser
3
5
  def initialize(lockfile_name:)
@@ -39,7 +41,7 @@ module Functions
39
41
  end
40
42
 
41
43
  def source_from_lockfile(dependency_name)
42
- parsed_lockfile&.specs.find { |s| s.name == dependency_name }&.source
44
+ parsed_lockfile&.specs&.find { |s| s.name == dependency_name }&.source
43
45
  end
44
46
 
45
47
  def source_for(dependency)
@@ -54,12 +56,8 @@ module Functions
54
56
  return nil if default_rubygems?(source)
55
57
 
56
58
  details = { type: source.class.name.split("::").last.downcase }
57
- if source.is_a?(Bundler::Source::Git)
58
- details.merge!(git_source_details(source))
59
- end
60
- if source.is_a?(Bundler::Source::Rubygems)
61
- details[:url] = source.remotes.first.to_s
62
- end
59
+ details.merge!(git_source_details(source)) if source.is_a?(Bundler::Source::Git)
60
+ details[:url] = source.remotes.first.to_s if source.is_a?(Bundler::Source::Rubygems)
63
61
  details
64
62
  end
65
63
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Functions
2
4
  class ForceUpdater
3
5
  class TransitiveDependencyError < StandardError; end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "fileutils"
4
+
3
5
  module Functions
4
6
  class LockfileUpdater
5
7
  RETRYABLE_ERRORS = [Bundler::HTTPError].freeze
@@ -9,6 +11,7 @@ module Functions
9
11
  not\sfind\s(?<name>[^\s]+)-\d|
10
12
  has\s(?<name>[^\s]+)\slocked\sat
11
13
  /x.freeze
14
+ DEPENDENCY_DROPPED = "_dependency_dropped_"
12
15
 
13
16
  def initialize(gemfile_name:, lockfile_name:, dependencies:)
14
17
  @gemfile_name = gemfile_name
@@ -24,7 +27,7 @@ module Functions
24
27
 
25
28
  attr_reader :gemfile_name, :lockfile_name, :dependencies
26
29
 
27
- def generate_lockfile
30
+ def generate_lockfile # rubocop:disable Metrics/PerceivedComplexity
28
31
  dependencies_to_unlock = dependencies.map { |d| d.fetch("name") }
29
32
 
30
33
  begin
@@ -36,7 +39,7 @@ module Functions
36
39
 
37
40
  old_reqs.each do |dep_name, old_req|
38
41
  d_dep = definition.dependencies.find { |d| d.name == dep_name }
39
- if old_req == :none then definition.dependencies.delete(d_dep)
42
+ if old_req.to_s == DEPENDENCY_DROPPED then definition.dependencies.delete(d_dep)
40
43
  else
41
44
  d_dep.instance_variable_set(:@requirement, old_req)
42
45
  end
@@ -200,7 +203,7 @@ module Functions
200
203
  if defn_dep.nil?
201
204
  definition.dependencies <<
202
205
  Bundler::Dependency.new(dep.fetch("name"), dep.fetch("version"))
203
- old_reqs[dep.fetch("name")] = :none
206
+ old_reqs[dep.fetch("name")] = DEPENDENCY_DROPPED
204
207
  elsif git_dependency?(dep) &&
205
208
  defn_dep.source.is_a?(Bundler::Source::Git)
206
209
  defn_dep.source.unlock!
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Functions
2
4
  class VersionResolver
3
5
  GEM_NOT_FOUND_ERROR_REGEX = /locked to (?<name>[^\s]+) \(/.freeze
@@ -20,9 +22,7 @@ module Functions
20
22
  # included in a gemspec, it's because the Gemfile didn't import
21
23
  # the gemspec. This is unusual, but the correct behaviour if/when
22
24
  # it happens is to behave as if the repo was gemspec-only.
23
- if dep.nil? && dependency_requirements.any?
24
- return "latest"
25
- end
25
+ return "latest" if dep.nil? && dependency_requirements.any?
26
26
 
27
27
  # Otherwise, if the dependency wasn't found it's because it is a
28
28
  # subdependency that was removed when attempting to update it.
@@ -38,9 +38,7 @@ module Functions
38
38
  ruby_version: ruby_version,
39
39
  fetcher: fetcher_class(dep)
40
40
  }
41
- if dep.source.instance_of?(::Bundler::Source::Git)
42
- details[:commit_sha] = dep.source.revision
43
- end
41
+ details[:commit_sha] = dep.source.revision if dep.source.instance_of?(::Bundler::Source::Git)
44
42
  details
45
43
  end
46
44
 
@@ -92,7 +90,7 @@ module Functions
92
90
  end
93
91
 
94
92
  def build_definition(dependencies_to_unlock)
95
- # Note: we lock shared dependencies to avoid any top-level
93
+ # NOTE: we lock shared dependencies to avoid any top-level
96
94
  # dependencies getting unlocked (which would happen if they were
97
95
  # also subdependencies of the dependency being unlocked)
98
96
  ::Bundler::Definition.build(
@@ -40,9 +40,7 @@ module Bundler
40
40
  $LOAD_PATH.shift until $LOAD_PATH.empty?
41
41
  reduced_load_paths.each { |p| $LOAD_PATH << p }
42
42
 
43
- if destination.relative?
44
- destination = destination.expand_path(Bundler.root)
45
- end
43
+ destination = destination.expand_path(Bundler.root) if destination.relative?
46
44
  Dir["#{destination}/#{@glob}"].each do |spec_path|
47
45
  # Evaluate gemspecs and cache the result. Gemspecs
48
46
  # in git might require git or other dependencies.
data/helpers/v2/run.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler"
2
4
  require "json"
3
5
 
@@ -36,9 +38,9 @@ begin
36
38
  args = request["args"].transform_keys(&:to_sym)
37
39
 
38
40
  output({ result: Functions.send(function, **args) })
39
- rescue => error
41
+ rescue StandardError => e
40
42
  output(
41
- { error: error.message, error_class: error.class, trace: error.backtrace }
43
+ { error: e.message, error_class: e.class, trace: e.backtrace }
42
44
  )
43
45
  exit(1)
44
46
  end
@@ -40,10 +40,10 @@ RSpec.describe Functions::DependencySource do
40
40
 
41
41
  it "returns all versions from the private source" do
42
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
- ])
43
+ Gem::Version.new("1.5.0"),
44
+ Gem::Version.new("1.9.0"),
45
+ Gem::Version.new("1.10.0.beta")
46
+ ])
47
47
  end
48
48
 
49
49
  context "specified as the default source" do
@@ -51,10 +51,10 @@ RSpec.describe Functions::DependencySource do
51
51
 
52
52
  it "returns all versions from the private source" do
53
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
- ])
54
+ Gem::Version.new("1.5.0"),
55
+ Gem::Version.new("1.9.0"),
56
+ Gem::Version.new("1.10.0.beta")
57
+ ])
58
58
  end
59
59
  end
60
60
 
@@ -12,9 +12,9 @@ RSpec.describe Functions::FileParser do
12
12
  )
13
13
  end
14
14
 
15
- let(:project_name) { "gemfile" }
16
-
17
15
  describe "#parsed_gemfile" do
16
+ let(:project_name) { "gemfile" }
17
+
18
18
  subject(:parsed_gemfile) do
19
19
  in_tmp_folder do
20
20
  dependency_source.parsed_gemfile(gemfile_name: "Gemfile")
@@ -54,7 +54,7 @@ RSpec.describe Functions::FileParser do
54
54
  branch: "master",
55
55
  ref: "a1b78a9",
56
56
  type: "git",
57
- url: "git@github.com:gocardless/business"
57
+ url: "git@github.com:dependabot-fixtures/business"
58
58
  },
59
59
  type: :runtime
60
60
  },
@@ -68,36 +68,36 @@ RSpec.describe Functions::FileParser do
68
68
  {
69
69
  groups: [:default],
70
70
  name: "prius",
71
- requirement: Gem::Requirement.new(">= 0"),
71
+ requirement: Gem::Requirement.new(">= 0"),
72
72
  source: {
73
73
  branch: "master",
74
74
  ref: "master",
75
75
  type: "git",
76
- url: "https://github.com/gocardless/prius"
76
+ url: "https://github.com/dependabot-fixtures/prius"
77
77
  },
78
78
  type: :runtime
79
79
  },
80
80
  {
81
81
  groups: [:default],
82
82
  name: "que",
83
- requirement: Gem::Requirement.new(">= 0"),
83
+ requirement: Gem::Requirement.new(">= 0"),
84
84
  source: {
85
85
  branch: "master",
86
86
  ref: "v0.11.6",
87
87
  type: "git",
88
- url: "git@github.com:chanks/que"
88
+ url: "git@github.com:dependabot-fixtures/que"
89
89
  },
90
90
  type: :runtime
91
91
  },
92
92
  {
93
93
  groups: [:default],
94
94
  name: "uk_phone_numbers",
95
- requirement: Gem::Requirement.new(">= 0"),
95
+ requirement: Gem::Requirement.new(">= 0"),
96
96
  source: {
97
97
  branch: "master",
98
98
  ref: "master",
99
99
  type: "git",
100
- url: "http://github.com/gocardless/uk_phone_numbers"
100
+ url: "http://github.com/dependabot-fixtures/uk_phone_numbers"
101
101
  },
102
102
  type: :runtime
103
103
  }
@@ -108,14 +108,11 @@ RSpec.describe Functions::FileParser do
108
108
  end
109
109
 
110
110
  describe "#parsed_gemspec" do
111
- let!(:gemspec_fixture) do
112
- fixture("ruby", "gemspecs", "exact")
113
- end
111
+ let(:project_name) { "gemfile_exact" }
114
112
 
115
113
  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")
114
+ in_tmp_folder do |_tmp_path|
115
+ dependency_source.parsed_gemspec(gemspec_name: "example.gemspec")
119
116
  end
120
117
  end
121
118
 
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "native_spec_helper"
4
+ require "shared_contexts"
5
+
6
+ RSpec.describe Functions::ForceUpdater do
7
+ include_context "in a temporary bundler directory"
8
+ include_context "stub rubygems compact index"
9
+
10
+ let(:force_updater) do
11
+ described_class.new(
12
+ dependency_name: dependency_name,
13
+ target_version: target_version,
14
+ gemfile_name: gemfile_name,
15
+ lockfile_name: lockfile_name,
16
+ update_multiple_dependencies: update_multiple_dependencies
17
+ )
18
+ end
19
+ let(:gemfile_name) { "Gemfile" }
20
+ let(:lockfile_name) { "Gemfile.lock" }
21
+ let(:update_multiple_dependencies) { true }
22
+
23
+ describe "#run" do
24
+ subject(:force_update) do
25
+ in_tmp_folder { force_updater.run }
26
+ end
27
+
28
+ context "with a version conflict" do
29
+ let(:target_version) { "3.6.0" }
30
+ let(:dependency_name) { "rspec-support" }
31
+ let(:project_name) { "version_conflict" }
32
+
33
+ it "updates the conflicting dependencies" do
34
+ updated_deps, _specs = force_update
35
+ expect(updated_deps).to eq([{ name: "rspec-support" }, { name: "rspec-mocks" }])
36
+ end
37
+
38
+ context "when updating a single dependency" do
39
+ let(:update_multiple_dependencies) { false }
40
+
41
+ it { expect { force_update }.to raise_error(Bundler::VersionConflict) }
42
+ end
43
+ end
44
+
45
+ context "with a version conflict in gems rb" do
46
+ let(:target_version) { "3.6.0" }
47
+ let(:dependency_name) { "rspec-support" }
48
+ let(:project_name) { "version_conflict_gems_rb" }
49
+ let(:gemfile_name) { "gems.rb" }
50
+ let(:lockfile_name) { "gems.locked" }
51
+
52
+ it "updates the conflicting dependencies" do
53
+ updated_deps, _specs = force_update
54
+ expect(updated_deps).to eq([{ name: "rspec-support" }, { name: "rspec-mocks" }])
55
+ end
56
+ end
57
+ end
58
+ end
@@ -92,5 +92,13 @@ RSpec.describe Functions::VersionResolver do
92
92
  its([:version]) { is_expected.to eq(Gem::Version.new("1.4.0")) }
93
93
  its([:fetcher]) { is_expected.to eq("Bundler::Fetcher::Dependency") }
94
94
  end
95
+
96
+ context "with no update possible due to a version conflict" do
97
+ let(:project_name) { "version_conflict_with_listed_subdep" }
98
+ let(:dependency_name) { "rspec-mocks" }
99
+ let(:requirement_string) { ">= 0" }
100
+
101
+ its([:version]) { is_expected.to eq(Gem::Version.new("3.6.0")) }
102
+ end
95
103
  end
96
104
  end
@@ -14,11 +14,44 @@ RSpec.describe Functions do
14
14
  jfrog_source = Functions.jfrog_source(
15
15
  dir: tmp_path,
16
16
  gemfile_name: "Gemfile",
17
- credentials: {},
17
+ credentials: {}
18
18
  )
19
19
 
20
20
  expect(jfrog_source).to eq("test.jfrog.io")
21
21
  end
22
22
  end
23
23
  end
24
+
25
+ describe "#git_specs" do
26
+ let(:project_name) { "git_source" }
27
+ subject(:git_specs) do
28
+ in_tmp_folder do
29
+ Functions.git_specs(
30
+ dir: tmp_path,
31
+ gemfile_name: "Gemfile",
32
+ credentials: {}
33
+ )
34
+ end
35
+ end
36
+
37
+ def expect_specs(count)
38
+ expect(git_specs.size).to eq(count)
39
+ git_specs.each do |gs|
40
+ uri = URI.parse(gs[:auth_uri])
41
+ expect(uri.scheme).to(satisfy { |s| %w(http https).include?(s) })
42
+ end
43
+ end
44
+
45
+ it "returns git specs" do
46
+ expect_specs(4)
47
+ end
48
+
49
+ context "with github shorthand" do
50
+ let(:project_name) { "github_source" }
51
+
52
+ it "returns git specs" do
53
+ expect_specs(1)
54
+ end
55
+ end
56
+ end
24
57
  end
@@ -26,8 +26,7 @@ end
26
26
  LOCKFILE_ENDING = /(?<ending>\s*(?:RUBY VERSION|BUNDLED WITH).*)/m.freeze
27
27
 
28
28
  def project_dependency_files(project)
29
- # TODO: Retrieve files from bundler2 folder once it is fully up to date
30
- project_path = File.expand_path(File.join("../../spec/fixtures/projects/bundler1", project))
29
+ project_path = File.expand_path(File.join("../../spec/fixtures/projects/bundler2", project))
31
30
 
32
31
  raise "Fixture does not exist for project: '#{project}'" unless Dir.exist?(project_path)
33
32
 
@@ -37,9 +36,7 @@ def project_dependency_files(project)
37
36
  files = files.select { |f| File.file?(f) }
38
37
  files.map do |filename|
39
38
  content = File.read(filename)
40
- if filename == "Gemfile.lock"
41
- content = content.gsub(LOCKFILE_ENDING, "")
42
- end
39
+ content = content.gsub(LOCKFILE_ENDING, "") if filename == "Gemfile.lock"
43
40
  {
44
41
  name: filename,
45
42
  content: content
@@ -50,10 +50,10 @@ module Dependabot
50
50
  end
51
51
 
52
52
  def ruby_version
53
- requirement = if !ruby_requirement.is_a?(Gem::Requirement)
54
- Dependabot::Bundler::Requirement.new(ruby_requirement)
55
- else
53
+ requirement = if ruby_requirement.is_a?(Gem::Requirement)
56
54
  ruby_requirement
55
+ else
56
+ Dependabot::Bundler::Requirement.new(ruby_requirement)
57
57
  end
58
58
 
59
59
  ruby_version =
@@ -17,7 +17,6 @@ module Dependabot
17
17
  # Bundler will pick the matching installed major version
18
18
  "BUNDLER_VERSION" => bundler_version,
19
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
20
  # Prevent the GEM_HOME from being set to a folder owned by root
22
21
  "GEM_HOME" => File.join(versioned_helper_path(bundler_version: bundler_version), ".bundle")
23
22
  }
@@ -36,7 +35,7 @@ module Dependabot
36
35
  end
37
36
 
38
37
  def self.helper_path(bundler_version:)
39
- "ruby #{File.join(versioned_helper_path(bundler_version: bundler_version), 'run.rb')}"
38
+ "bundle exec ruby #{File.join(versioned_helper_path(bundler_version: bundler_version), 'run.rb')}"
40
39
  end
41
40
 
42
41
  def self.native_helpers_root
@@ -3,6 +3,7 @@
3
3
  require "excon"
4
4
 
5
5
  require "dependabot/bundler/update_checker"
6
+ require "dependabot/update_checkers/version_filters"
6
7
  require "dependabot/bundler/requirement"
7
8
  require "dependabot/shared_helpers"
8
9
  require "dependabot/errors"
@@ -55,7 +56,8 @@ module Dependabot
55
56
 
56
57
  relevant_versions = dependency_source.versions
57
58
  relevant_versions = filter_prerelease_versions(relevant_versions)
58
- relevant_versions = filter_vulnerable_versions(relevant_versions)
59
+ relevant_versions = Dependabot::UpdateCheckers::VersionFilters.filter_vulnerable_versions(relevant_versions,
60
+ security_advisories)
59
61
  relevant_versions = filter_ignored_versions(relevant_versions)
60
62
  relevant_versions = filter_lower_versions(relevant_versions)
61
63
 
@@ -78,11 +80,6 @@ module Dependabot
78
80
  filtered
79
81
  end
80
82
 
81
- def filter_vulnerable_versions(versions_array)
82
- versions_array.
83
- reject { |v| security_advisories.any? { |a| a.vulnerable?(v) } }
84
- end
85
-
86
83
  def filter_lower_versions(versions_array)
87
84
  return versions_array unless dependency.version && Gem::Version.correct?(dependency.version)
88
85
 
@@ -174,8 +174,11 @@ module Dependabot
174
174
  }
175
175
  )
176
176
  git_specs.reject do |spec|
177
+ uri = URI.parse(spec.fetch("auth_uri"))
178
+ next false unless %w(http https).include?(uri.scheme)
179
+
177
180
  Excon.get(
178
- spec.fetch("auth_uri"),
181
+ uri.to_s,
179
182
  idempotent: true,
180
183
  **SharedHelpers.excon_defaults
181
184
  ).status == 200
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.153.0
4
+ version: 0.154.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-14 00:00:00.000000000 Z
11
+ date: 2021-06-22 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.153.0
19
+ version: 0.154.4
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.153.0
26
+ version: 0.154.4
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: byebug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -202,6 +202,7 @@ files:
202
202
  - helpers/v1/spec/functions/conflicting_dependency_resolver_spec.rb
203
203
  - helpers/v1/spec/functions/dependency_source_spec.rb
204
204
  - helpers/v1/spec/functions/file_parser_spec.rb
205
+ - helpers/v1/spec/functions/force_updater_spec.rb
205
206
  - helpers/v1/spec/functions/version_resolver_spec.rb
206
207
  - helpers/v1/spec/native_spec_helper.rb
207
208
  - helpers/v1/spec/shared_contexts.rb
@@ -222,6 +223,7 @@ files:
222
223
  - helpers/v2/spec/functions/conflicting_dependency_resolver_spec.rb
223
224
  - helpers/v2/spec/functions/dependency_source_spec.rb
224
225
  - helpers/v2/spec/functions/file_parser_spec.rb
226
+ - helpers/v2/spec/functions/force_updater_spec.rb
225
227
  - helpers/v2/spec/functions/version_resolver_spec.rb
226
228
  - helpers/v2/spec/functions_spec.rb
227
229
  - helpers/v2/spec/native_spec_helper.rb