dependabot-core 0.93.17 → 0.94.0

Sign up to get free protection for your applications and to get access to all the features.
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