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,70 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pathname"
4
- require "parser/current"
5
- require "dependabot/file_fetchers/ruby/bundler"
6
- require "dependabot/errors"
7
-
8
- module Dependabot
9
- module FileFetchers
10
- module Ruby
11
- class Bundler
12
- # Finds the paths of any Gemfiles declared using `eval_gemfile` in the
13
- # passed Gemfile.
14
- class ChildGemfileFinder
15
- def initialize(gemfile:)
16
- @gemfile = gemfile
17
- end
18
-
19
- def child_gemfile_paths
20
- ast = Parser::CurrentRuby.parse(gemfile.content)
21
- find_child_gemfile_paths(ast)
22
- rescue Parser::SyntaxError
23
- raise Dependabot::DependencyFileNotParseable, gemfile.path
24
- end
25
-
26
- private
27
-
28
- attr_reader :gemfile
29
-
30
- # rubocop:disable Security/Eval
31
- def find_child_gemfile_paths(node)
32
- return [] unless node.is_a?(Parser::AST::Node)
33
-
34
- if declares_eval_gemfile?(node)
35
- # We use eval here, but we know what we're doing. The FileFetchers
36
- # helper method should only ever be run in an isolated environment
37
- source = node.children[2].loc.expression.source
38
- begin
39
- path = eval(source)
40
- rescue StandardError
41
- return []
42
- end
43
- if Pathname.new(path).absolute?
44
- base_path = Pathname.new(File.expand_path(Dir.pwd))
45
- path = Pathname.new(path).relative_path_from(base_path).to_s
46
- end
47
- path = File.join(current_dir, path) unless current_dir.nil?
48
- return [Pathname.new(path).cleanpath.to_path]
49
- end
50
-
51
- node.children.flat_map do |child_node|
52
- find_child_gemfile_paths(child_node)
53
- end
54
- end
55
- # rubocop:enable Security/Eval
56
-
57
- def current_dir
58
- @current_dir ||= gemfile.name.split("/")[0..-2].last
59
- end
60
-
61
- def declares_eval_gemfile?(node)
62
- return false unless node.is_a?(Parser::AST::Node)
63
-
64
- node.children[1] == :eval_gemfile
65
- end
66
- end
67
- end
68
- end
69
- end
70
- end
@@ -1,98 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pathname"
4
- require "parser/current"
5
- require "dependabot/file_fetchers/ruby/bundler"
6
- require "dependabot/errors"
7
-
8
- module Dependabot
9
- module FileFetchers
10
- module Ruby
11
- class Bundler
12
- # Finds the directories of any gemspecs declared using `gemspec` in the
13
- # passed Gemfile.
14
- class GemspecFinder
15
- def initialize(gemfile:)
16
- @gemfile = gemfile
17
- end
18
-
19
- def gemspec_directories
20
- ast = Parser::CurrentRuby.parse(gemfile.content)
21
- find_gemspec_paths(ast)
22
- rescue Parser::SyntaxError
23
- raise Dependabot::DependencyFileNotParseable, gemfile.path
24
- end
25
-
26
- private
27
-
28
- attr_reader :gemfile
29
-
30
- # rubocop:disable Security/Eval
31
- def find_gemspec_paths(node)
32
- return [] unless node.is_a?(Parser::AST::Node)
33
-
34
- if declares_gemspec_dependency?(node)
35
- path_node = path_node_for_gem_declaration(node)
36
- return [clean_path(".")] unless path_node
37
-
38
- begin
39
- # We use eval here, but we know what we're doing. The
40
- # FileFetchers helper method should only ever be run in an
41
- # isolated environment
42
- path = eval(path_node.loc.expression.source)
43
- rescue StandardError
44
- return []
45
- end
46
- return [clean_path(path)]
47
- end
48
-
49
- node.children.flat_map do |child_node|
50
- find_gemspec_paths(child_node)
51
- end
52
- end
53
- # rubocop:enable Security/Eval
54
-
55
- def current_dir
56
- @current_dir ||= gemfile.name.rpartition("/").first
57
- @current_dir = nil if @current_dir == ""
58
- @current_dir
59
- end
60
-
61
- def declares_gemspec_dependency?(node)
62
- return false unless node.is_a?(Parser::AST::Node)
63
-
64
- node.children[1] == :gemspec
65
- end
66
-
67
- def clean_path(path)
68
- if Pathname.new(path).absolute?
69
- base_path = Pathname.new(File.expand_path(Dir.pwd))
70
- path = Pathname.new(path).relative_path_from(base_path).to_s
71
- end
72
- path = File.join(current_dir, path) unless current_dir.nil?
73
- Pathname.new(path).cleanpath
74
- end
75
-
76
- def path_node_for_gem_declaration(node)
77
- return unless node.children.last.is_a?(Parser::AST::Node)
78
- return unless node.children.last.type == :hash
79
-
80
- kwargs_node = node.children.last
81
-
82
- path_hash_pair =
83
- kwargs_node.children.
84
- find { |hash_pair| key_from_hash_pair(hash_pair) == :path }
85
-
86
- return unless path_hash_pair
87
-
88
- path_hash_pair.children.last
89
- end
90
-
91
- def key_from_hash_pair(node)
92
- node.children.first.children.first.to_sym
93
- end
94
- end
95
- end
96
- end
97
- end
98
- end
@@ -1,114 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pathname"
4
- require "parser/current"
5
- require "dependabot/file_fetchers/ruby/bundler"
6
- require "dependabot/errors"
7
-
8
- module Dependabot
9
- module FileFetchers
10
- module Ruby
11
- class Bundler
12
- # Finds the paths of any gemspecs declared using `path: ` in the
13
- # passed Gemfile.
14
- class PathGemspecFinder
15
- def initialize(gemfile:)
16
- @gemfile = gemfile
17
- end
18
-
19
- def path_gemspec_paths
20
- ast = Parser::CurrentRuby.parse(gemfile.content)
21
- find_path_gemspec_paths(ast)
22
- rescue Parser::SyntaxError
23
- raise Dependabot::DependencyFileNotParseable, gemfile.path
24
- end
25
-
26
- private
27
-
28
- attr_reader :gemfile
29
-
30
- # rubocop:disable Security/Eval
31
- def find_path_gemspec_paths(node)
32
- return [] unless node.is_a?(Parser::AST::Node)
33
-
34
- if declares_path_dependency?(node)
35
- path_node = path_node_for_gem_declaration(node)
36
-
37
- begin
38
- # We use eval here, but we know what we're doing. The
39
- # FileFetchers helper method should only ever be run in an
40
- # isolated environment
41
- path = eval(path_node.loc.expression.source)
42
- rescue StandardError
43
- return []
44
- end
45
- return [clean_path(path)]
46
- end
47
-
48
- relevant_child_nodes(node).flat_map do |child_node|
49
- find_path_gemspec_paths(child_node)
50
- end
51
- end
52
- # rubocop:enable Security/Eval
53
-
54
- def current_dir
55
- @current_dir ||= gemfile.name.rpartition("/").first
56
- @current_dir = nil if @current_dir == ""
57
- @current_dir
58
- end
59
-
60
- def declares_path_dependency?(node)
61
- return false unless node.is_a?(Parser::AST::Node)
62
- return false unless node.children[1] == :gem
63
-
64
- !path_node_for_gem_declaration(node).nil?
65
- end
66
-
67
- def clean_path(path)
68
- if Pathname.new(path).absolute?
69
- base_path = Pathname.new(File.expand_path(Dir.pwd))
70
- path = Pathname.new(path).relative_path_from(base_path).to_s
71
- end
72
- path = File.join(current_dir, path) unless current_dir.nil?
73
- Pathname.new(path).cleanpath
74
- end
75
-
76
- # rubocop:disable Security/Eval
77
- def relevant_child_nodes(node)
78
- return [] unless node.is_a?(Parser::AST::Node)
79
- return node.children unless node.type == :if
80
-
81
- begin
82
- if eval(node.children.first.loc.expression.source)
83
- [node.children[1]]
84
- else
85
- [node.children[2]]
86
- end
87
- rescue StandardError
88
- return node.children
89
- end
90
- end
91
- # rubocop:enable Security/Eval
92
-
93
- def path_node_for_gem_declaration(node)
94
- return unless node.children.last.type == :hash
95
-
96
- kwargs_node = node.children.last
97
-
98
- path_hash_pair =
99
- kwargs_node.children.
100
- find { |hash_pair| key_from_hash_pair(hash_pair) == :path }
101
-
102
- return unless path_hash_pair
103
-
104
- path_hash_pair.children.last
105
- end
106
-
107
- def key_from_hash_pair(node)
108
- node.children.first.children.first.to_sym
109
- end
110
- end
111
- end
112
- end
113
- end
114
- end
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "pathname"
4
- require "parser/current"
5
- require "dependabot/file_fetchers/ruby/bundler"
6
- require "dependabot/errors"
7
-
8
- module Dependabot
9
- module FileFetchers
10
- module Ruby
11
- class Bundler
12
- # Finds the paths of any files included using `require_relative` in the
13
- # passed file.
14
- class RequireRelativeFinder
15
- def initialize(file:)
16
- @file = file
17
- end
18
-
19
- def require_relative_paths
20
- ast = Parser::CurrentRuby.parse(file.content)
21
- find_require_relative_paths(ast)
22
- rescue Parser::SyntaxError
23
- raise Dependabot::DependencyFileNotParseable, file.path
24
- end
25
-
26
- private
27
-
28
- attr_reader :file
29
-
30
- # rubocop:disable Security/Eval
31
- def find_require_relative_paths(node)
32
- return [] unless node.is_a?(Parser::AST::Node)
33
-
34
- if declares_require_relative?(node)
35
- # We use eval here, but we know what we're doing. The FileFetchers
36
- # helper method should only ever be run in an isolated environment
37
- source = node.children[2].loc.expression.source
38
- begin
39
- path = eval(source)
40
- rescue StandardError
41
- return []
42
- end
43
-
44
- path = File.join(current_dir, path) unless current_dir.nil?
45
- return [Pathname.new(path + ".rb").cleanpath.to_path]
46
- end
47
-
48
- node.children.flat_map do |child_node|
49
- find_require_relative_paths(child_node)
50
- end
51
- end
52
- # rubocop:enable Security/Eval
53
-
54
- def current_dir
55
- @current_dir ||= file.name.split("/")[0..-2].last
56
- end
57
-
58
- def declares_require_relative?(node)
59
- return false unless node.is_a?(Parser::AST::Node)
60
-
61
- node.children[1] == :require_relative
62
- end
63
- end
64
- end
65
- end
66
- end
67
- end
@@ -1,294 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/dependency"
4
- require "dependabot/file_parsers/base"
5
- require "dependabot/file_updaters/ruby/bundler/lockfile_updater"
6
- require "dependabot/shared_helpers"
7
- require "dependabot/errors"
8
-
9
- module Dependabot
10
- module FileParsers
11
- module Ruby
12
- class Bundler < Dependabot::FileParsers::Base
13
- require "dependabot/file_parsers/base/dependency_set"
14
- require "dependabot/file_parsers/ruby/bundler/file_preparer"
15
- require "dependabot/file_parsers/ruby/bundler/gemfile_checker"
16
-
17
- def parse
18
- dependency_set = DependencySet.new
19
- dependency_set += gemfile_dependencies
20
- dependency_set += gemspec_dependencies
21
- dependency_set += lockfile_dependencies
22
- dependency_set.dependencies
23
- end
24
-
25
- private
26
-
27
- # Can't be a constant because some of these don't exist in bundler
28
- # 1.15, which Heroku uses, which causes an exception on boot.
29
- def sources
30
- [
31
- NilClass,
32
- ::Bundler::Source::Rubygems,
33
- ::Bundler::Source::Git,
34
- ::Bundler::Source::Path,
35
- ::Bundler::Source::Gemspec,
36
- ::Bundler::Source::Metadata
37
- ]
38
- end
39
-
40
- def gemfile_dependencies
41
- dependencies = DependencySet.new
42
-
43
- return dependencies unless gemfile
44
-
45
- [gemfile, *evaled_gemfiles].each do |file|
46
- parsed_gemfile.each do |dep|
47
- next unless dependency_in_gemfile?(gemfile: file, dependency: dep)
48
-
49
- dependencies <<
50
- Dependency.new(
51
- name: dep.name,
52
- version: dependency_version(dep.name)&.to_s,
53
- requirements: [{
54
- requirement: dep.requirement.to_s,
55
- groups: dep.groups,
56
- source: source_for(dep),
57
- file: file.name
58
- }],
59
- package_manager: "bundler"
60
- )
61
- end
62
- end
63
-
64
- dependencies
65
- end
66
-
67
- def gemspec_dependencies
68
- dependencies = DependencySet.new
69
-
70
- gemspecs.each do |gemspec|
71
- parsed_gemspec(gemspec).dependencies.each do |dependency|
72
- dependencies <<
73
- Dependency.new(
74
- name: dependency.name,
75
- version: dependency_version(dependency.name)&.to_s,
76
- requirements: [{
77
- requirement: dependency.requirement.to_s,
78
- groups: dependency.runtime? ? ["runtime"] : ["development"],
79
- source: nil,
80
- file: gemspec.name
81
- }],
82
- package_manager: "bundler"
83
- )
84
- end
85
- end
86
-
87
- dependencies
88
- end
89
-
90
- def lockfile_dependencies
91
- dependencies = DependencySet.new
92
-
93
- return dependencies unless lockfile
94
-
95
- # Create a DependencySet where each element has no requirement. Any
96
- # requirements will be added when combining the DependencySet with
97
- # other DependencySets.
98
- parsed_lockfile.specs.each do |dependency|
99
- next if dependency.source.is_a?(::Bundler::Source::Path)
100
-
101
- dependencies <<
102
- Dependency.new(
103
- name: dependency.name,
104
- version: dependency_version(dependency.name)&.to_s,
105
- requirements: [],
106
- package_manager: "bundler"
107
- )
108
- end
109
-
110
- dependencies
111
- end
112
-
113
- def parsed_gemfile
114
- base_directory = dependency_files.first.directory
115
- @parsed_gemfile ||=
116
- SharedHelpers.in_a_temporary_directory(base_directory) do
117
- write_temporary_dependency_files
118
-
119
- SharedHelpers.in_a_forked_process do
120
- ::Bundler.instance_variable_set(:@root, Pathname.new(Dir.pwd))
121
-
122
- ::Bundler::Definition.build(gemfile.name, nil, {}).
123
- dependencies.
124
- select(&:current_platform?).
125
- # We can't dump gemspec sources, and we wouldn't bump them
126
- # anyway, so we filter them out.
127
- reject { |dep| dep.source.is_a?(::Bundler::Source::Gemspec) }
128
- end
129
- end
130
- rescue SharedHelpers::ChildProcessFailed => error
131
- msg = error.error_class + " with message: " +
132
- error.error_message.force_encoding("UTF-8").encode
133
- raise Dependabot::DependencyFileNotEvaluatable, msg
134
- end
135
-
136
- def parsed_gemspec(file)
137
- @parsed_gemspecs ||= {}
138
- @parsed_gemspecs[file.name] ||=
139
- SharedHelpers.in_a_temporary_directory do
140
- [file, *imported_ruby_files].each do |f|
141
- path = f.name
142
- FileUtils.mkdir_p(Pathname.new(path).dirname)
143
- File.write(path, f.content)
144
- end
145
-
146
- SharedHelpers.in_a_forked_process do
147
- ::Bundler.instance_variable_set(:@root, Pathname.new(Dir.pwd))
148
- ::Bundler.load_gemspec_uncached(file.name)
149
- end
150
- end
151
- rescue SharedHelpers::ChildProcessFailed => error
152
- msg = error.error_class + " with message: " + error.error_message
153
- raise Dependabot::DependencyFileNotEvaluatable, msg
154
- end
155
-
156
- def prepared_dependency_files
157
- @prepared_dependency_files ||=
158
- FilePreparer.new(dependency_files: dependency_files).
159
- prepared_dependency_files
160
- end
161
-
162
- def write_temporary_dependency_files
163
- prepared_dependency_files.each do |file|
164
- path = file.name
165
- FileUtils.mkdir_p(Pathname.new(path).dirname)
166
- File.write(path, file.content)
167
- end
168
- end
169
-
170
- def check_required_files
171
- file_names = dependency_files.map(&:name)
172
-
173
- return if file_names.any? do |name|
174
- name.end_with?(".gemspec") && !name.include?("/")
175
- end
176
-
177
- return if gemfile
178
-
179
- raise "A gemspec or Gemfile must be provided!"
180
- end
181
-
182
- def source_for(dependency)
183
- source = dependency.source
184
- if lockfile && default_rubygems?(source)
185
- # If there's a lockfile and the Gemfile doesn't have anything
186
- # interesting to say about the source, check that.
187
- source = source_from_lockfile(dependency.name)
188
- end
189
- raise "Bad source: #{source}" unless sources.include?(source.class)
190
-
191
- return nil if default_rubygems?(source)
192
-
193
- details = { type: source.class.name.split("::").last.downcase }
194
- if source.is_a?(::Bundler::Source::Git)
195
- details.merge!(git_source_details(source))
196
- end
197
- if source.is_a?(::Bundler::Source::Rubygems)
198
- details[:url] = source.remotes.first.to_s
199
- end
200
- details
201
- end
202
-
203
- def git_source_details(source)
204
- {
205
- url: source.uri,
206
- branch: source.branch || "master",
207
- ref: source.ref
208
- }
209
- end
210
-
211
- def default_rubygems?(source)
212
- return true if source.nil?
213
- return false unless source.is_a?(::Bundler::Source::Rubygems)
214
-
215
- source.remotes.any? { |r| r.to_s.include?("rubygems.org") }
216
- end
217
-
218
- def dependency_version(dependency_name)
219
- return unless lockfile
220
-
221
- spec = parsed_lockfile.specs.find { |s| s.name == dependency_name }
222
-
223
- # Not all files in the Gemfile will appear in the Gemfile.lock. For
224
- # instance, if a gem specifies `platform: [:windows]`, and the
225
- # Gemfile.lock is generated on a Linux machine, the gem will be not
226
- # appear in the lockfile.
227
- return unless spec
228
-
229
- # If the source is Git we're better off knowing the SHA-1 than the
230
- # version.
231
- if spec.source.instance_of?(::Bundler::Source::Git)
232
- return spec.source.revision
233
- end
234
-
235
- spec.version
236
- end
237
-
238
- def source_from_lockfile(dependency_name)
239
- parsed_lockfile.specs.find { |s| s.name == dependency_name }&.source
240
- end
241
-
242
- def dependency_in_gemfile?(gemfile:, dependency:)
243
- GemfileChecker.new(
244
- dependency: dependency,
245
- gemfile: gemfile
246
- ).includes_dependency?
247
- end
248
-
249
- def gemfile
250
- @gemfile ||= get_original_file("Gemfile") ||
251
- get_original_file("gems.rb")
252
- end
253
-
254
- def evaled_gemfiles
255
- dependency_files.
256
- reject { |f| f.name.end_with?(".gemspec") }.
257
- reject { |f| f.name.end_with?(".lock") }.
258
- reject { |f| f.name.end_with?(".ruby-version") }.
259
- reject { |f| f.name == "Gemfile" }.
260
- reject { |f| f.name == "gems.rb" }.
261
- reject { |f| f.name == "gems.locked" }
262
- end
263
-
264
- def lockfile
265
- @lockfile ||= get_original_file("Gemfile.lock") ||
266
- get_original_file("gems.locked")
267
- end
268
-
269
- def parsed_lockfile
270
- @parsed_lockfile ||=
271
- ::Bundler::LockfileParser.new(sanitized_lockfile_content)
272
- end
273
-
274
- def sanitized_lockfile_content
275
- regex = FileUpdaters::Ruby::Bundler::LockfileUpdater::LOCKFILE_ENDING
276
- lockfile.content.gsub(regex, "")
277
- end
278
-
279
- def gemspecs
280
- # Path gemspecs are excluded (they're supporting files)
281
- @gemspecs ||= prepared_dependency_files.
282
- select { |file| file.name.end_with?(".gemspec") }.
283
- reject(&:support_file?)
284
- end
285
-
286
- def imported_ruby_files
287
- dependency_files.
288
- select { |f| f.name.end_with?(".rb") }.
289
- reject { |f| f.name == "gems.rb" }
290
- end
291
- end
292
- end
293
- end
294
- end