dependabot-core 0.93.17 → 0.94.0

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/lib/dependabot/dependency.rb +16 -21
  4. data/lib/dependabot/file_fetchers.rb +1 -5
  5. data/lib/dependabot/file_parsers.rb +1 -5
  6. data/lib/dependabot/file_updaters.rb +1 -5
  7. data/lib/dependabot/metadata_finders.rb +1 -5
  8. data/lib/dependabot/pull_request_creator/labeler.rb +26 -24
  9. data/lib/dependabot/update_checkers.rb +1 -5
  10. data/lib/dependabot/utils.rb +2 -12
  11. data/lib/dependabot/version.rb +1 -1
  12. metadata +1 -28
  13. data/lib/dependabot/file_fetchers/ruby/bundler.rb +0 -215
  14. data/lib/dependabot/file_fetchers/ruby/bundler/child_gemfile_finder.rb +0 -70
  15. data/lib/dependabot/file_fetchers/ruby/bundler/gemspec_finder.rb +0 -98
  16. data/lib/dependabot/file_fetchers/ruby/bundler/path_gemspec_finder.rb +0 -114
  17. data/lib/dependabot/file_fetchers/ruby/bundler/require_relative_finder.rb +0 -67
  18. data/lib/dependabot/file_parsers/ruby/bundler.rb +0 -294
  19. data/lib/dependabot/file_parsers/ruby/bundler/file_preparer.rb +0 -86
  20. data/lib/dependabot/file_parsers/ruby/bundler/gemfile_checker.rb +0 -48
  21. data/lib/dependabot/file_updaters/ruby/bundler.rb +0 -123
  22. data/lib/dependabot/file_updaters/ruby/bundler/gemfile_updater.rb +0 -116
  23. data/lib/dependabot/file_updaters/ruby/bundler/gemspec_dependency_name_finder.rb +0 -52
  24. data/lib/dependabot/file_updaters/ruby/bundler/gemspec_sanitizer.rb +0 -298
  25. data/lib/dependabot/file_updaters/ruby/bundler/gemspec_updater.rb +0 -64
  26. data/lib/dependabot/file_updaters/ruby/bundler/git_pin_replacer.rb +0 -80
  27. data/lib/dependabot/file_updaters/ruby/bundler/git_source_remover.rb +0 -102
  28. data/lib/dependabot/file_updaters/ruby/bundler/lockfile_updater.rb +0 -389
  29. data/lib/dependabot/file_updaters/ruby/bundler/requirement_replacer.rb +0 -223
  30. data/lib/dependabot/metadata_finders/ruby/bundler.rb +0 -202
  31. data/lib/dependabot/update_checkers/ruby/bundler.rb +0 -331
  32. data/lib/dependabot/update_checkers/ruby/bundler/file_preparer.rb +0 -281
  33. data/lib/dependabot/update_checkers/ruby/bundler/force_updater.rb +0 -261
  34. data/lib/dependabot/update_checkers/ruby/bundler/latest_version_finder.rb +0 -169
  35. data/lib/dependabot/update_checkers/ruby/bundler/requirements_updater.rb +0 -283
  36. data/lib/dependabot/update_checkers/ruby/bundler/ruby_requirement_setter.rb +0 -115
  37. data/lib/dependabot/update_checkers/ruby/bundler/shared_bundler_helpers.rb +0 -246
  38. data/lib/dependabot/update_checkers/ruby/bundler/version_resolver.rb +0 -272
  39. data/lib/dependabot/utils/ruby/requirement.rb +0 -26
@@ -1,281 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/dependency_file"
4
- require "dependabot/update_checkers/ruby/bundler"
5
- require "dependabot/file_updaters/ruby/bundler/gemspec_sanitizer"
6
- require "dependabot/file_updaters/ruby/bundler/git_pin_replacer"
7
- require "dependabot/file_updaters/ruby/bundler/git_source_remover"
8
- require "dependabot/file_updaters/ruby/bundler/requirement_replacer"
9
- require "dependabot/file_updaters/ruby/bundler/gemspec_dependency_name_finder"
10
- require "dependabot/file_updaters/ruby/bundler/lockfile_updater"
11
- require "dependabot/update_checkers/ruby/bundler/ruby_requirement_setter"
12
-
13
- module Dependabot
14
- module UpdateCheckers
15
- module Ruby
16
- class Bundler
17
- # This class takes a set of dependency files and sanitizes them for use
18
- # in UpdateCheckers::Ruby::Bundler. In particular, it:
19
- # - Removes any version requirement on the dependency being updated
20
- # (in the Gemfile)
21
- # - Sanitizes any provided gemspecs to remove file imports etc. (since
22
- # Dependabot doesn't pull down the entire repo). This process is
23
- # imperfect - an alternative would be to clone the repo
24
- # - Sets the ruby version in the Gemfile to be the lowest possible
25
- # version allowed by the gemspec, if the gemspec has a required ruby
26
- # version range
27
- class FilePreparer
28
- VERSION_REGEX = /[0-9]+(?:\.[A-Za-z0-9\-_]+)*/.freeze
29
-
30
- # Can't be a constant because some of these don't exist in bundler
31
- # 1.15, which Heroku uses, which causes an exception on boot.
32
- def gemspec_sources
33
- [
34
- ::Bundler::Source::Path,
35
- ::Bundler::Source::Gemspec
36
- ]
37
- end
38
-
39
- def initialize(dependency_files:, dependency:,
40
- remove_git_source: false,
41
- unlock_requirement: true,
42
- replacement_git_pin: nil,
43
- latest_allowable_version: nil,
44
- lock_ruby_version: true)
45
- @dependency_files = dependency_files
46
- @dependency = dependency
47
- @remove_git_source = remove_git_source
48
- @unlock_requirement = unlock_requirement
49
- @replacement_git_pin = replacement_git_pin
50
- @latest_allowable_version = latest_allowable_version
51
- @lock_ruby_version = lock_ruby_version
52
- end
53
-
54
- # rubocop:disable Metrics/AbcSize
55
- # rubocop:disable Metrics/MethodLength
56
- def prepared_dependency_files
57
- files = []
58
-
59
- if gemfile
60
- files << DependencyFile.new(
61
- name: gemfile.name,
62
- content: gemfile_content_for_update_check(gemfile),
63
- directory: gemfile.directory
64
- )
65
- end
66
-
67
- top_level_gemspecs.each do |gemspec|
68
- files << DependencyFile.new(
69
- name: gemspec.name,
70
- content: gemspec_content_for_update_check(gemspec),
71
- directory: gemspec.directory
72
- )
73
- end
74
-
75
- path_gemspecs.each do |file|
76
- files << DependencyFile.new(
77
- name: file.name,
78
- content: sanitize_gemspec_content(file.content),
79
- directory: file.directory,
80
- support_file: file.support_file?
81
- )
82
- end
83
-
84
- evaled_gemfiles.each do |file|
85
- files << DependencyFile.new(
86
- name: file.name,
87
- content: gemfile_content_for_update_check(file),
88
- directory: file.directory
89
- )
90
- end
91
-
92
- # No editing required for lockfile or Ruby version file
93
- files += [lockfile, ruby_version_file, *imported_ruby_files].compact
94
- end
95
- # rubocop:enable Metrics/AbcSize
96
- # rubocop:enable Metrics/MethodLength
97
-
98
- private
99
-
100
- attr_reader :dependency_files, :dependency, :replacement_git_pin,
101
- :latest_allowable_version
102
-
103
- def remove_git_source?
104
- @remove_git_source
105
- end
106
-
107
- def unlock_requirement?
108
- @unlock_requirement
109
- end
110
-
111
- def replace_git_pin?
112
- !replacement_git_pin.nil?
113
- end
114
-
115
- def gemfile
116
- dependency_files.find { |f| f.name == "Gemfile" } ||
117
- dependency_files.find { |f| f.name == "gems.rb" }
118
- end
119
-
120
- def evaled_gemfiles
121
- dependency_files.
122
- reject { |f| f.name.end_with?(".gemspec") }.
123
- reject { |f| f.name.end_with?(".lock") }.
124
- reject { |f| f.name.end_with?(".ruby-version") }.
125
- reject { |f| f.name == "Gemfile" }.
126
- reject { |f| f.name == "gems.rb" }.
127
- reject { |f| f.name == "gems.locked" }
128
- end
129
-
130
- def lockfile
131
- dependency_files.find { |f| f.name == "Gemfile.lock" } ||
132
- dependency_files.find { |f| f.name == "gems.locked" }
133
- end
134
-
135
- def top_level_gemspecs
136
- dependency_files.
137
- select { |f| f.name.end_with?(".gemspec") }.
138
- reject(&:support_file?)
139
- end
140
-
141
- def ruby_version_file
142
- dependency_files.find { |f| f.name == ".ruby-version" }
143
- end
144
-
145
- def path_gemspecs
146
- all = dependency_files.select { |f| f.name.end_with?(".gemspec") }
147
- all - top_level_gemspecs
148
- end
149
-
150
- def imported_ruby_files
151
- dependency_files.
152
- select { |f| f.name.end_with?(".rb") }.
153
- reject { |f| f.name == "gems.rb" }
154
- end
155
-
156
- def gemfile_content_for_update_check(file)
157
- content = file.content
158
- content = replace_gemfile_constraint(content, file.name)
159
- content = remove_git_source(content) if remove_git_source?
160
- content = replace_git_pin(content) if replace_git_pin?
161
- content = lock_ruby_version(content) if lock_ruby_version?(file)
162
- content
163
- end
164
-
165
- def gemspec_content_for_update_check(gemspec)
166
- content = gemspec.content
167
- content = replace_gemspec_constraint(content, gemspec.name)
168
- sanitize_gemspec_content(content)
169
- end
170
-
171
- def replace_gemfile_constraint(content, filename)
172
- FileUpdaters::Ruby::Bundler::RequirementReplacer.new(
173
- dependency: dependency,
174
- file_type: :gemfile,
175
- updated_requirement: updated_version_requirement_string(filename),
176
- insert_if_bare: true
177
- ).rewrite(content)
178
- end
179
-
180
- def replace_gemspec_constraint(content, filename)
181
- FileUpdaters::Ruby::Bundler::RequirementReplacer.new(
182
- dependency: dependency,
183
- file_type: :gemspec,
184
- updated_requirement: updated_version_requirement_string(filename),
185
- insert_if_bare: true
186
- ).rewrite(content)
187
- end
188
-
189
- def sanitize_gemspec_content(gemspec_content)
190
- new_version = replacement_version_for_gemspec(gemspec_content)
191
-
192
- FileUpdaters::Ruby::Bundler::GemspecSanitizer.
193
- new(replacement_version: new_version).
194
- rewrite(gemspec_content)
195
- end
196
-
197
- def updated_version_requirement_string(filename)
198
- lower_bound_req = updated_version_req_lower_bound(filename)
199
-
200
- return lower_bound_req if latest_allowable_version.nil?
201
- unless Gem::Version.correct?(latest_allowable_version)
202
- return lower_bound_req
203
- end
204
-
205
- lower_bound_req + ", <= #{latest_allowable_version}"
206
- end
207
-
208
- def updated_version_req_lower_bound(filename)
209
- original_req = dependency.requirements.
210
- find { |r| r.fetch(:file) == filename }&.
211
- fetch(:requirement)
212
-
213
- if original_req && !unlock_requirement? then original_req
214
- elsif dependency.version&.match?(/^[0-9a-f]{40}$/) then ">= 0"
215
- elsif dependency.version then ">= #{dependency.version}"
216
- else
217
- version_for_requirement =
218
- dependency.requirements.map { |r| r[:requirement] }.
219
- reject { |req_string| req_string.start_with?("<") }.
220
- select { |req_string| req_string.match?(VERSION_REGEX) }.
221
- map { |req_string| req_string.match(VERSION_REGEX) }.
222
- select { |version| Gem::Version.correct?(version) }.
223
- max_by { |version| Gem::Version.new(version) }
224
-
225
- ">= #{version_for_requirement || 0}"
226
- end
227
- end
228
-
229
- def remove_git_source(content)
230
- FileUpdaters::Ruby::Bundler::GitSourceRemover.new(
231
- dependency: dependency
232
- ).rewrite(content)
233
- end
234
-
235
- def replace_git_pin(content)
236
- FileUpdaters::Ruby::Bundler::GitPinReplacer.new(
237
- dependency: dependency,
238
- new_pin: replacement_git_pin
239
- ).rewrite(content)
240
- end
241
-
242
- def lock_ruby_version(gemfile_content)
243
- top_level_gemspecs.each do |gs|
244
- gemfile_content =
245
- RubyRequirementSetter.new(gemspec: gs).rewrite(gemfile_content)
246
- end
247
-
248
- gemfile_content
249
- end
250
-
251
- def lock_ruby_version?(file)
252
- @lock_ruby_version && file == gemfile
253
- end
254
-
255
- def replacement_version_for_gemspec(gemspec_content)
256
- return "0.0.1" unless lockfile
257
-
258
- gemspec_specs =
259
- ::Bundler::LockfileParser.new(sanitized_lockfile_content).specs.
260
- select { |s| gemspec_sources.include?(s.source.class) }
261
-
262
- gem_name =
263
- FileUpdaters::Ruby::Bundler::GemspecDependencyNameFinder.
264
- new(gemspec_content: gemspec_content).
265
- dependency_name
266
-
267
- return gemspec_specs.first&.version || "0.0.1" unless gem_name
268
-
269
- spec = gemspec_specs.find { |s| s.name == gem_name }
270
- spec&.version || gemspec_specs.first&.version || "0.0.1"
271
- end
272
-
273
- def sanitized_lockfile_content
274
- re = FileUpdaters::Ruby::Bundler::LockfileUpdater::LOCKFILE_ENDING
275
- lockfile.content.gsub(re, "")
276
- end
277
- end
278
- end
279
- end
280
- end
281
- end
@@ -1,261 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler_definition_ruby_version_patch"
4
- require "bundler_definition_bundler_version_patch"
5
- require "bundler_git_source_patch"
6
-
7
- require "dependabot/update_checkers/ruby/bundler"
8
- require "dependabot/update_checkers/ruby/bundler/requirements_updater"
9
- require "dependabot/file_updaters/ruby/bundler/lockfile_updater"
10
- require "dependabot/file_parsers/ruby/bundler"
11
- require "dependabot/shared_helpers"
12
- require "dependabot/errors"
13
-
14
- module Dependabot
15
- module UpdateCheckers
16
- module Ruby
17
- class Bundler
18
- class ForceUpdater
19
- def initialize(dependency:, dependency_files:, credentials:,
20
- target_version:, requirements_update_strategy:)
21
- @dependency = dependency
22
- @dependency_files = dependency_files
23
- @credentials = credentials
24
- @target_version = target_version
25
- @requirements_update_strategy = requirements_update_strategy
26
- end
27
-
28
- def updated_dependencies
29
- @updated_dependencies ||= force_update
30
- end
31
-
32
- private
33
-
34
- attr_reader :dependency, :dependency_files, :credentials,
35
- :target_version, :requirements_update_strategy
36
-
37
- def force_update
38
- in_a_temporary_bundler_context do
39
- other_updates = []
40
-
41
- begin
42
- definition = build_definition(other_updates: other_updates)
43
- definition.resolve_remotely!
44
- specs = definition.resolve
45
- dependencies_from([dependency] + other_updates, specs)
46
- rescue ::Bundler::VersionConflict => error
47
- # TODO: Not sure this won't unlock way too many things...
48
- new_dependencies_to_unlock =
49
- new_dependencies_to_unlock_from(
50
- error: error,
51
- already_unlocked: other_updates
52
- )
53
-
54
- raise if new_dependencies_to_unlock.none?
55
-
56
- other_updates += new_dependencies_to_unlock
57
- retry
58
- end
59
- end
60
- rescue SharedHelpers::ChildProcessFailed => error
61
- raise_unresolvable_error(error)
62
- end
63
-
64
- #########################
65
- # Bundler context setup #
66
- #########################
67
-
68
- def in_a_temporary_bundler_context
69
- SharedHelpers.in_a_temporary_directory do
70
- write_temporary_dependency_files
71
-
72
- SharedHelpers.in_a_forked_process do
73
- # Remove installed gems from the default Rubygems index
74
- ::Gem::Specification.all = []
75
-
76
- # Set auth details
77
- relevant_credentials.each do |cred|
78
- token = cred["token"] ||
79
- "#{cred['username']}:#{cred['password']}"
80
-
81
- ::Bundler.settings.set_command_option(
82
- cred.fetch("host"),
83
- token.gsub("@", "%40F").gsub("?", "%3F")
84
- )
85
- end
86
-
87
- # Only allow upgrades. Othewise it's unlikely that this
88
- # resolution will be found by the FileUpdater
89
- ::Bundler.settings.set_command_option(
90
- "only_update_to_newer_versions",
91
- true
92
- )
93
-
94
- yield
95
- end
96
- end
97
- end
98
-
99
- def new_dependencies_to_unlock_from(error:, already_unlocked:)
100
- potentials_deps =
101
- error.cause.conflicts.values.
102
- flat_map(&:requirement_trees).
103
- reject do |tree|
104
- next true unless tree.last.requirement.specific?
105
- next false unless tree.last.name == dependency.name
106
-
107
- tree.last.requirement.satisfied_by?(
108
- Gem::Version.new(target_version)
109
- )
110
- end.map(&:first)
111
-
112
- potentials_deps.
113
- reject { |dep| already_unlocked.map(&:name).include?(dep.name) }.
114
- reject { |dep| [dependency.name, "ruby\0"].include?(dep.name) }.
115
- uniq
116
- end
117
-
118
- def raise_unresolvable_error(error)
119
- msg = error.error_class + " with message: " + error.error_message
120
- raise Dependabot::DependencyFileNotResolvable, msg
121
- end
122
-
123
- def build_definition(other_updates:)
124
- gems_to_unlock = other_updates.map(&:name) + [dependency.name]
125
- definition = ::Bundler::Definition.build(
126
- gemfile.name,
127
- lockfile&.name,
128
- gems: gems_to_unlock + subdependencies,
129
- lock_shared_dependencies: true
130
- )
131
-
132
- # Remove the Gemfile / gemspec requirements on the gems we're
133
- # unlocking (i.e., completely unlock them)
134
- gems_to_unlock.each do |gem_name|
135
- unlock_gem(definition: definition, gem_name: gem_name)
136
- end
137
-
138
- # Set the requirement for the gem we're forcing an update of
139
- new_req = Gem::Requirement.create("= #{target_version}")
140
- definition.dependencies.
141
- find { |d| d.name == dependency.name }.
142
- instance_variable_set(:@requirement, new_req)
143
-
144
- definition
145
- end
146
-
147
- def subdependencies
148
- # If there's no lockfile we don't need to worry about
149
- # subdependencies
150
- return [] unless lockfile
151
-
152
- all_deps = ::Bundler::LockfileParser.new(sanitized_lockfile_body).
153
- specs.map(&:name).map(&:to_s)
154
- top_level = ::Bundler::Definition.
155
- build(gemfile.name, lockfile.name, {}).
156
- dependencies.map(&:name).map(&:to_s)
157
-
158
- all_deps - top_level
159
- end
160
-
161
- def unlock_gem(definition:, gem_name:)
162
- dep = definition.dependencies.find { |d| d.name == gem_name }
163
- version = definition.locked_gems.specs.
164
- find { |d| d.name == gem_name }.version
165
-
166
- dep&.instance_variable_set(
167
- :@requirement,
168
- Gem::Requirement.create(">= #{version}")
169
- )
170
- end
171
-
172
- def original_dependencies
173
- @original_dependencies ||=
174
- FileParsers::Ruby::Bundler.new(
175
- dependency_files: dependency_files,
176
- credentials: credentials,
177
- source: nil
178
- ).parse
179
- end
180
-
181
- def dependencies_from(updated_deps, specs)
182
- # You might think we'd want to remove dependencies whose version
183
- # hadn't changed from this array. We don't. We still need to unlock
184
- # them to get Bundler to resolve, because unlocking them is what
185
- # updates their subdependencies.
186
- #
187
- # This is kind of a bug in Bundler, and we should try to fix it,
188
- # but resolving it won't necessarily be easy.
189
- updated_deps.map do |dep|
190
- original_dep =
191
- original_dependencies.find { |d| d.name == dep.name }
192
- spec = specs.find { |d| d.name == dep.name }
193
-
194
- next if spec.version.to_s == original_dep.version
195
-
196
- build_dependency(original_dep, spec)
197
- end.compact
198
- end
199
-
200
- def build_dependency(original_dep, updated_spec)
201
- Dependency.new(
202
- name: updated_spec.name,
203
- version: updated_spec.version.to_s,
204
- requirements:
205
- RequirementsUpdater.new(
206
- requirements: original_dep.requirements,
207
- update_strategy: requirements_update_strategy,
208
- updated_source: source_for(original_dep),
209
- latest_version: updated_spec.version.to_s,
210
- latest_resolvable_version: updated_spec.version.to_s
211
- ).updated_requirements,
212
- previous_version: original_dep.version,
213
- previous_requirements: original_dep.requirements,
214
- package_manager: original_dep.package_manager
215
- )
216
- end
217
-
218
- def source_for(dependency)
219
- dependency.requirements.
220
- find { |r| r.fetch(:source) }&.
221
- fetch(:source)
222
- end
223
-
224
- def gemfile
225
- dependency_files.find { |f| f.name == "Gemfile" } ||
226
- dependency_files.find { |f| f.name == "gems.rb" }
227
- end
228
-
229
- def lockfile
230
- dependency_files.find { |f| f.name == "Gemfile.lock" } ||
231
- dependency_files.find { |f| f.name == "gems.locked" }
232
- end
233
-
234
- def sanitized_lockfile_body
235
- re = FileUpdaters::Ruby::Bundler::LockfileUpdater::LOCKFILE_ENDING
236
- lockfile.content.gsub(re, "")
237
- end
238
-
239
- def write_temporary_dependency_files
240
- dependency_files.each do |file|
241
- path = file.name
242
- FileUtils.mkdir_p(Pathname.new(path).dirname)
243
- File.write(path, file.content)
244
- end
245
-
246
- File.write(lockfile.name, sanitized_lockfile_body) if lockfile
247
- end
248
-
249
- def relevant_credentials
250
- credentials.select do |cred|
251
- next true if cred["type"] == "git_source"
252
- next true if cred["type"] == "rubygems_server"
253
-
254
- false
255
- end
256
- end
257
- end
258
- end
259
- end
260
- end
261
- end