dependabot-bundler 0.95.5 → 0.95.6

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 (36) hide show
  1. checksums.yaml +4 -4
  2. metadata +4 -38
  3. data/helpers/Makefile +0 -9
  4. data/helpers/build +0 -26
  5. data/lib/dependabot/bundler.rb +0 -27
  6. data/lib/dependabot/bundler/file_fetcher.rb +0 -216
  7. data/lib/dependabot/bundler/file_fetcher/child_gemfile_finder.rb +0 -68
  8. data/lib/dependabot/bundler/file_fetcher/gemspec_finder.rb +0 -96
  9. data/lib/dependabot/bundler/file_fetcher/path_gemspec_finder.rb +0 -112
  10. data/lib/dependabot/bundler/file_fetcher/require_relative_finder.rb +0 -65
  11. data/lib/dependabot/bundler/file_parser.rb +0 -297
  12. data/lib/dependabot/bundler/file_parser/file_preparer.rb +0 -84
  13. data/lib/dependabot/bundler/file_parser/gemfile_checker.rb +0 -46
  14. data/lib/dependabot/bundler/file_updater.rb +0 -125
  15. data/lib/dependabot/bundler/file_updater/gemfile_updater.rb +0 -114
  16. data/lib/dependabot/bundler/file_updater/gemspec_dependency_name_finder.rb +0 -50
  17. data/lib/dependabot/bundler/file_updater/gemspec_sanitizer.rb +0 -298
  18. data/lib/dependabot/bundler/file_updater/gemspec_updater.rb +0 -62
  19. data/lib/dependabot/bundler/file_updater/git_pin_replacer.rb +0 -78
  20. data/lib/dependabot/bundler/file_updater/git_source_remover.rb +0 -100
  21. data/lib/dependabot/bundler/file_updater/lockfile_updater.rb +0 -387
  22. data/lib/dependabot/bundler/file_updater/requirement_replacer.rb +0 -221
  23. data/lib/dependabot/bundler/metadata_finder.rb +0 -204
  24. data/lib/dependabot/bundler/requirement.rb +0 -29
  25. data/lib/dependabot/bundler/update_checker.rb +0 -334
  26. data/lib/dependabot/bundler/update_checker/file_preparer.rb +0 -279
  27. data/lib/dependabot/bundler/update_checker/force_updater.rb +0 -259
  28. data/lib/dependabot/bundler/update_checker/latest_version_finder.rb +0 -165
  29. data/lib/dependabot/bundler/update_checker/requirements_updater.rb +0 -281
  30. data/lib/dependabot/bundler/update_checker/ruby_requirement_setter.rb +0 -113
  31. data/lib/dependabot/bundler/update_checker/shared_bundler_helpers.rb +0 -244
  32. data/lib/dependabot/bundler/update_checker/version_resolver.rb +0 -272
  33. data/lib/dependabot/bundler/version.rb +0 -13
  34. data/lib/dependabot/monkey_patches/bundler/definition_bundler_version_patch.rb +0 -15
  35. data/lib/dependabot/monkey_patches/bundler/definition_ruby_version_patch.rb +0 -14
  36. data/lib/dependabot/monkey_patches/bundler/git_source_patch.rb +0 -27
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/bundler/file_updater"
4
-
5
- module Dependabot
6
- module Bundler
7
- class FileUpdater
8
- class GemspecUpdater
9
- require_relative "requirement_replacer"
10
-
11
- def initialize(dependencies:, gemspec:)
12
- @dependencies = dependencies
13
- @gemspec = gemspec
14
- end
15
-
16
- def updated_gemspec_content
17
- content = gemspec.content
18
-
19
- dependencies.each do |dependency|
20
- content = replace_gemspec_version_requirement(
21
- gemspec, dependency, content
22
- )
23
- end
24
-
25
- content
26
- end
27
-
28
- private
29
-
30
- attr_reader :dependencies, :gemspec
31
-
32
- def replace_gemspec_version_requirement(gemspec, dependency, content)
33
- return content unless requirement_changed?(gemspec, dependency)
34
-
35
- updated_requirement =
36
- dependency.requirements.
37
- find { |r| r[:file] == gemspec.name }.
38
- fetch(:requirement)
39
-
40
- previous_requirement =
41
- dependency.previous_requirements.
42
- find { |r| r[:file] == gemspec.name }.
43
- fetch(:requirement)
44
-
45
- RequirementReplacer.new(
46
- dependency: dependency,
47
- file_type: :gemspec,
48
- updated_requirement: updated_requirement,
49
- previous_requirement: previous_requirement
50
- ).rewrite(content)
51
- end
52
-
53
- def requirement_changed?(file, dependency)
54
- changed_requirements =
55
- dependency.requirements - dependency.previous_requirements
56
-
57
- changed_requirements.any? { |f| f[:file] == file.name }
58
- end
59
- end
60
- end
61
- end
62
- end
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "parser/current"
4
- require "dependabot/bundler/file_updater"
5
-
6
- module Dependabot
7
- module Bundler
8
- class FileUpdater
9
- class GitPinReplacer
10
- attr_reader :dependency, :new_pin
11
-
12
- def initialize(dependency:, new_pin:)
13
- @dependency = dependency
14
- @new_pin = new_pin
15
- end
16
-
17
- def rewrite(content)
18
- buffer = Parser::Source::Buffer.new("(gemfile_content)")
19
- buffer.source = content
20
- ast = Parser::CurrentRuby.new.parse(buffer)
21
-
22
- Rewriter.
23
- new(dependency: dependency, new_pin: new_pin).
24
- rewrite(buffer, ast)
25
- end
26
-
27
- class Rewriter < Parser::TreeRewriter
28
- PIN_KEYS = %i(ref tag).freeze
29
- attr_reader :dependency, :new_pin
30
-
31
- def initialize(dependency:, new_pin:)
32
- @dependency = dependency
33
- @new_pin = new_pin
34
- end
35
-
36
- def on_send(node)
37
- return unless declares_targeted_gem?(node)
38
- return unless node.children.last.type == :hash
39
-
40
- kwargs_node = node.children.last
41
- kwargs_node.children.each do |hash_pair|
42
- next unless PIN_KEYS.include?(key_from_hash_pair(hash_pair))
43
-
44
- update_value(hash_pair)
45
- end
46
- end
47
-
48
- private
49
-
50
- def declares_targeted_gem?(node)
51
- return false unless node.children[1] == :gem
52
-
53
- node.children[2].children.first == dependency.name
54
- end
55
-
56
- def key_from_hash_pair(node)
57
- node.children.first.children.first.to_sym
58
- end
59
-
60
- def update_value(hash_pair)
61
- value_node = hash_pair.children.last
62
- open_quote_character, close_quote_character =
63
- extract_quote_characters_from(value_node)
64
-
65
- replace(
66
- value_node.loc.expression,
67
- %(#{open_quote_character}#{new_pin}#{close_quote_character})
68
- )
69
- end
70
-
71
- def extract_quote_characters_from(value_node)
72
- [value_node.loc.begin.source, value_node.loc.end.source]
73
- end
74
- end
75
- end
76
- end
77
- end
78
- end
@@ -1,100 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "parser/current"
4
- require "dependabot/bundler/file_updater"
5
-
6
- module Dependabot
7
- module Bundler
8
- class FileUpdater
9
- class GitSourceRemover
10
- attr_reader :dependency
11
-
12
- def initialize(dependency:)
13
- @dependency = dependency
14
- end
15
-
16
- def rewrite(content)
17
- buffer = Parser::Source::Buffer.new("(gemfile_content)")
18
- buffer.source = content
19
- ast = Parser::CurrentRuby.new.parse(buffer)
20
-
21
- Rewriter.new(dependency: dependency).rewrite(buffer, ast)
22
- end
23
-
24
- class Rewriter < Parser::TreeRewriter
25
- # TODO: Hack until Bundler 1.16.0 is available on Heroku
26
- GOOD_KEYS = %i(
27
- group groups path glob name require platform platforms type
28
- source install_if
29
- ).freeze
30
-
31
- attr_reader :dependency
32
-
33
- def initialize(dependency:)
34
- @dependency = dependency
35
- end
36
-
37
- def on_send(node)
38
- return unless declares_targeted_gem?(node)
39
- return unless node.children.last.type == :hash
40
-
41
- kwargs_node = node.children.last
42
- keys = kwargs_node.children.map do |hash_pair|
43
- key_from_hash_pair(hash_pair)
44
- end
45
-
46
- if keys.none? { |key| GOOD_KEYS.include?(key) }
47
- remove_all_kwargs(node)
48
- else
49
- remove_git_related_kwargs(kwargs_node)
50
- end
51
- end
52
-
53
- private
54
-
55
- def declares_targeted_gem?(node)
56
- return false unless node.children[1] == :gem
57
-
58
- node.children[2].children.first == dependency.name
59
- end
60
-
61
- def key_from_hash_pair(node)
62
- node.children.first.children.first.to_sym
63
- end
64
-
65
- def remove_all_kwargs(node)
66
- kwargs_node = node.children.last
67
-
68
- range_to_remove =
69
- kwargs_node.loc.expression.join(node.children[-2].loc.end.end)
70
-
71
- remove(range_to_remove)
72
- end
73
-
74
- def remove_git_related_kwargs(kwargs_node)
75
- good_key_index = nil
76
- hash_pairs = kwargs_node.children
77
-
78
- hash_pairs.each_with_index do |hash_pair, index|
79
- if GOOD_KEYS.include?(key_from_hash_pair(hash_pair))
80
- good_key_index = index
81
- next
82
- end
83
-
84
- range_to_remove =
85
- if good_key_index.nil?
86
- next_arg_start = hash_pairs[index + 1].loc.expression.begin
87
- hash_pair.loc.expression.join(next_arg_start)
88
- else
89
- last_arg_end = hash_pairs[good_key_index].loc.expression.end
90
- hash_pair.loc.expression.join(last_arg_end)
91
- end
92
-
93
- remove(range_to_remove)
94
- end
95
- end
96
- end
97
- end
98
- end
99
- end
100
- end
@@ -1,387 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "bundler"
4
-
5
- require "dependabot/monkey_patches/bundler/definition_ruby_version_patch"
6
- require "dependabot/monkey_patches/bundler/definition_bundler_version_patch"
7
- require "dependabot/monkey_patches/bundler/git_source_patch"
8
-
9
- require "dependabot/shared_helpers"
10
- require "dependabot/errors"
11
- require "dependabot/bundler/file_updater"
12
- require "dependabot/git_commit_checker"
13
-
14
- # rubocop:disable Metrics/ClassLength
15
- module Dependabot
16
- module Bundler
17
- class FileUpdater
18
- class LockfileUpdater
19
- require_relative "gemfile_updater"
20
- require_relative "gemspec_updater"
21
- require_relative "gemspec_sanitizer"
22
- require_relative "gemspec_dependency_name_finder"
23
-
24
- LOCKFILE_ENDING =
25
- /(?<ending>\s*(?:RUBY VERSION|BUNDLED WITH).*)/m.freeze
26
- GIT_DEPENDENCIES_SECTION = /GIT\n.*?\n\n(?!GIT)/m.freeze
27
- GIT_DEPENDENCY_DETAILS = /GIT\n.*?\n\n/m.freeze
28
- GEM_NOT_FOUND_ERROR_REGEX =
29
- /locked to (?<name>[^\s]+) \(|not find (?<name>[^\s]+)-\d/.freeze
30
- RETRYABLE_ERRORS = [::Bundler::HTTPError].freeze
31
-
32
- # Can't be a constant because some of these don't exist in bundler
33
- # 1.15, which Heroku uses, which causes an exception on boot.
34
- def gemspec_sources
35
- [
36
- ::Bundler::Source::Path,
37
- ::Bundler::Source::Gemspec
38
- ]
39
- end
40
-
41
- def initialize(dependencies:, dependency_files:, credentials:)
42
- @dependencies = dependencies
43
- @dependency_files = dependency_files
44
- @credentials = credentials
45
- end
46
-
47
- def updated_lockfile_content
48
- @updated_lockfile_content ||=
49
- begin
50
- updated_content = build_updated_lockfile
51
-
52
- if lockfile.content == updated_content
53
- raise "Expected content to change!"
54
- end
55
-
56
- updated_content
57
- end
58
- end
59
-
60
- private
61
-
62
- attr_reader :dependencies, :dependency_files, :credentials
63
-
64
- def build_updated_lockfile
65
- base_dir = dependency_files.first.directory
66
- lockfile_body =
67
- SharedHelpers.in_a_temporary_directory(base_dir) do |tmp_dir|
68
- write_temporary_dependency_files
69
-
70
- SharedHelpers.in_a_forked_process do
71
- # Set the path for path gemspec correctly
72
- ::Bundler.instance_variable_set(:@root, tmp_dir)
73
-
74
- # Remove installed gems from the default Rubygems index
75
- ::Gem::Specification.all = []
76
-
77
- # Set auth details
78
- relevant_credentials.each do |cred|
79
- token = cred["token"] ||
80
- "#{cred['username']}:#{cred['password']}"
81
-
82
- ::Bundler.settings.set_command_option(
83
- cred.fetch("host"),
84
- token.gsub("@", "%40F").gsub("?", "%3F")
85
- )
86
- end
87
-
88
- generate_lockfile
89
- end
90
- end
91
- post_process_lockfile(lockfile_body)
92
- end
93
-
94
- def write_temporary_dependency_files
95
- File.write(gemfile.name, updated_gemfile_content(gemfile))
96
- File.write(lockfile.name, sanitized_lockfile_body)
97
-
98
- top_level_gemspecs.each do |gemspec|
99
- path = gemspec.name
100
- FileUtils.mkdir_p(Pathname.new(path).dirname)
101
- updated_content = updated_gemspec_content(gemspec)
102
- File.write(path, sanitized_gemspec_content(updated_content))
103
- end
104
-
105
- write_ruby_version_file
106
- write_path_gemspecs
107
- write_imported_ruby_files
108
-
109
- evaled_gemfiles.each do |file|
110
- path = file.name
111
- FileUtils.mkdir_p(Pathname.new(path).dirname)
112
- File.write(path, updated_gemfile_content(file))
113
- end
114
- end
115
-
116
- def generate_lockfile
117
- dependencies_to_unlock = dependencies.map(&:name)
118
-
119
- begin
120
- definition = build_definition(dependencies_to_unlock)
121
-
122
- old_reqs = lock_deps_being_updated_to_exact_versions(definition)
123
-
124
- definition.resolve_remotely!
125
-
126
- old_reqs.each do |dep_name, old_req|
127
- d_dep = definition.dependencies.find { |d| d.name == dep_name }
128
- if old_req == :none then definition.dependencies.delete(d_dep)
129
- else d_dep.instance_variable_set(:@requirement, old_req)
130
- end
131
- end
132
-
133
- definition.to_lock
134
- rescue ::Bundler::GemNotFound => error
135
- unlock_yanked_gem(dependencies_to_unlock, error) && retry
136
- rescue ::Bundler::VersionConflict => error
137
- unlock_blocking_subdeps(dependencies_to_unlock, error) && retry
138
- rescue *RETRYABLE_ERRORS
139
- raise if @retrying
140
-
141
- @retrying = true
142
- sleep(rand(1.0..5.0))
143
- retry
144
- end
145
- end
146
-
147
- def unlock_yanked_gem(dependencies_to_unlock, error)
148
- raise unless error.message.match?(GEM_NOT_FOUND_ERROR_REGEX)
149
-
150
- gem_name = error.message.match(GEM_NOT_FOUND_ERROR_REGEX).
151
- named_captures["name"]
152
- raise if dependencies_to_unlock.include?(gem_name)
153
-
154
- dependencies_to_unlock << gem_name
155
- end
156
-
157
- def unlock_blocking_subdeps(dependencies_to_unlock, error)
158
- all_deps = ::Bundler::LockfileParser.new(sanitized_lockfile_body).
159
- specs.map(&:name).map(&:to_s)
160
- top_level = build_definition([]).dependencies.
161
- map(&:name).map(&:to_s)
162
- allowed_new_unlocks = all_deps - top_level - dependencies_to_unlock
163
-
164
- # Unlock any sub-dependencies that Bundler reports caused the
165
- # conflict
166
- potentials_deps =
167
- error.cause.conflicts.values.
168
- flat_map(&:requirement_trees).
169
- map do |tree|
170
- tree.find { |req| allowed_new_unlocks.include?(req.name) }
171
- end.compact.map(&:name)
172
-
173
- # If there's nothing more we can unlock, give up
174
- raise if potentials_deps.none?
175
-
176
- dependencies_to_unlock.append(*potentials_deps)
177
- end
178
-
179
- def build_definition(dependencies_to_unlock)
180
- defn = ::Bundler::Definition.build(
181
- gemfile.name,
182
- lockfile.name,
183
- gems: dependencies_to_unlock
184
- )
185
-
186
- # Bundler unlocks the sub-dependencies of gems it is passed even
187
- # if those sub-deps are top-level dependencies. We only want true
188
- # subdeps unlocked, like they were in the UpdateChecker, so we
189
- # mutate the unlocked gems array.
190
- unlocked = defn.instance_variable_get(:@unlock).fetch(:gems)
191
- must_not_unlock = defn.dependencies.map(&:name).map(&:to_s) -
192
- dependencies_to_unlock
193
- unlocked.reject! { |n| must_not_unlock.include?(n) }
194
-
195
- defn
196
- end
197
-
198
- def lock_deps_being_updated_to_exact_versions(definition)
199
- dependencies.each_with_object({}) do |dep, old_reqs|
200
- defn_dep = definition.dependencies.find { |d| d.name == dep.name }
201
-
202
- if defn_dep.nil?
203
- definition.dependencies <<
204
- ::Bundler::Dependency.new(dep.name, dep.version)
205
- old_reqs[dep.name] = :none
206
- elsif git_dependency?(dep) &&
207
- defn_dep.source.is_a?(::Bundler::Source::Git)
208
- defn_dep.source.unlock!
209
- elsif Gem::Version.correct?(dep.version)
210
- new_req = Gem::Requirement.create("= #{dep.version}")
211
- old_reqs[dep.name] = defn_dep.requirement
212
- defn_dep.instance_variable_set(:@requirement, new_req)
213
- end
214
- end
215
- end
216
-
217
- def write_ruby_version_file
218
- return unless ruby_version_file
219
-
220
- path = ruby_version_file.name
221
- FileUtils.mkdir_p(Pathname.new(path).dirname)
222
- File.write(path, ruby_version_file.content)
223
- end
224
-
225
- def write_path_gemspecs
226
- path_gemspecs.each do |file|
227
- path = file.name
228
- FileUtils.mkdir_p(Pathname.new(path).dirname)
229
- File.write(path, sanitized_gemspec_content(file.content))
230
- end
231
- end
232
-
233
- def write_imported_ruby_files
234
- imported_ruby_files.each do |file|
235
- path = file.name
236
- FileUtils.mkdir_p(Pathname.new(path).dirname)
237
- File.write(path, file.content)
238
- end
239
- end
240
-
241
- def path_gemspecs
242
- all = dependency_files.select { |f| f.name.end_with?(".gemspec") }
243
- all - top_level_gemspecs
244
- end
245
-
246
- def imported_ruby_files
247
- dependency_files.
248
- select { |f| f.name.end_with?(".rb") }.
249
- reject { |f| f.name == "gems.rb" }
250
- end
251
-
252
- def top_level_gemspecs
253
- dependency_files.
254
- select { |file| file.name.end_with?(".gemspec") }.
255
- reject(&:support_file?)
256
- end
257
-
258
- def ruby_version_file
259
- dependency_files.find { |f| f.name == ".ruby-version" }
260
- end
261
-
262
- def post_process_lockfile(lockfile_body)
263
- lockfile_body = reorder_git_dependencies(lockfile_body)
264
- replace_lockfile_ending(lockfile_body)
265
- end
266
-
267
- def reorder_git_dependencies(lockfile_body)
268
- new_section = lockfile_body.match(GIT_DEPENDENCIES_SECTION)&.to_s
269
- old_section = lockfile.content.match(GIT_DEPENDENCIES_SECTION)&.to_s
270
-
271
- return lockfile_body unless new_section && old_section
272
-
273
- new_deps = new_section.scan(GIT_DEPENDENCY_DETAILS)
274
- old_deps = old_section.scan(GIT_DEPENDENCY_DETAILS)
275
-
276
- return lockfile_body unless new_deps.count == old_deps.count
277
-
278
- reordered_new_section = new_deps.sort_by do |new_dep_details|
279
- remote = new_dep_details.match(/remote: (?<remote>.*\n)/)[:remote]
280
- i = old_deps.index { |details| details.include?(remote) }
281
-
282
- # If this dependency isn't in the old lockfile then we can't rely
283
- # on that (presumably outdated) lockfile to do reordering.
284
- # Instead, we just return the default-ordered content just
285
- # generated.
286
- return lockfile_body unless i
287
-
288
- i
289
- end.join
290
-
291
- lockfile_body.gsub(new_section, reordered_new_section)
292
- end
293
-
294
- def replace_lockfile_ending(lockfile_body)
295
- # Re-add the old `BUNDLED WITH` version (and remove the RUBY VERSION
296
- # if it wasn't previously present in the lockfile)
297
- lockfile_body.gsub(
298
- LOCKFILE_ENDING,
299
- lockfile.content.match(LOCKFILE_ENDING)&.[](:ending) || "\n"
300
- )
301
- end
302
-
303
- def sanitized_gemspec_content(gemspec_content)
304
- new_version = replacement_version_for_gemspec(gemspec_content)
305
-
306
- GemspecSanitizer.
307
- new(replacement_version: new_version).
308
- rewrite(gemspec_content)
309
- end
310
-
311
- def replacement_version_for_gemspec(gemspec_content)
312
- return "0.0.1" unless lockfile
313
-
314
- gemspec_specs =
315
- ::Bundler::LockfileParser.new(sanitized_lockfile_body).specs.
316
- select { |s| gemspec_sources.include?(s.source.class) }
317
-
318
- gem_name =
319
- GemspecDependencyNameFinder.new(gemspec_content: gemspec_content).
320
- dependency_name
321
-
322
- return gemspec_specs.first&.version || "0.0.1" unless gem_name
323
-
324
- spec = gemspec_specs.find { |s| s.name == gem_name }
325
- spec&.version || gemspec_specs.first&.version || "0.0.1"
326
- end
327
-
328
- def relevant_credentials
329
- credentials.select do |cred|
330
- next true if cred["type"] == "git_source"
331
- next true if cred["type"] == "rubygems_server"
332
-
333
- false
334
- end
335
- end
336
-
337
- def updated_gemfile_content(file)
338
- GemfileUpdater.new(
339
- dependencies: dependencies,
340
- gemfile: file
341
- ).updated_gemfile_content
342
- end
343
-
344
- def updated_gemspec_content(gemspec)
345
- GemspecUpdater.new(
346
- dependencies: dependencies,
347
- gemspec: gemspec
348
- ).updated_gemspec_content
349
- end
350
-
351
- def gemfile
352
- @gemfile ||= dependency_files.find { |f| f.name == "Gemfile" } ||
353
- dependency_files.find { |f| f.name == "gems.rb" }
354
- end
355
-
356
- def lockfile
357
- @lockfile ||=
358
- dependency_files.find { |f| f.name == "Gemfile.lock" } ||
359
- dependency_files.find { |f| f.name == "gems.locked" }
360
- end
361
-
362
- def sanitized_lockfile_body
363
- lockfile.content.gsub(LOCKFILE_ENDING, "")
364
- end
365
-
366
- def evaled_gemfiles
367
- @evaled_gemfiles ||=
368
- dependency_files.
369
- reject { |f| f.name.end_with?(".gemspec") }.
370
- reject { |f| f.name.end_with?(".lock") }.
371
- reject { |f| f.name.end_with?(".ruby-version") }.
372
- reject { |f| f.name == "Gemfile" }.
373
- reject { |f| f.name == "gems.rb" }.
374
- reject { |f| f.name == "gems.locked" }
375
- end
376
-
377
- def git_dependency?(dep)
378
- GitCommitChecker.new(
379
- dependency: dep,
380
- credentials: credentials
381
- ).git_dependency?
382
- end
383
- end
384
- end
385
- end
386
- end
387
- # rubocop:enable Metrics/ClassLength