dependabot-core 0.94.13 → 0.95.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. metadata +13 -337
  3. data/CHANGELOG.md +0 -7079
  4. data/LICENSE +0 -39
  5. data/README.md +0 -114
  6. data/helpers/test/run.rb +0 -18
  7. data/helpers/utils/git-credential-store-immutable +0 -10
  8. data/lib/dependabot/clients/bitbucket.rb +0 -105
  9. data/lib/dependabot/clients/github_with_retries.rb +0 -121
  10. data/lib/dependabot/clients/gitlab.rb +0 -72
  11. data/lib/dependabot/dependency.rb +0 -115
  12. data/lib/dependabot/dependency_file.rb +0 -60
  13. data/lib/dependabot/errors.rb +0 -179
  14. data/lib/dependabot/file_fetchers/README.md +0 -65
  15. data/lib/dependabot/file_fetchers/base.rb +0 -368
  16. data/lib/dependabot/file_fetchers.rb +0 -18
  17. data/lib/dependabot/file_parsers/README.md +0 -45
  18. data/lib/dependabot/file_parsers/base/dependency_set.rb +0 -77
  19. data/lib/dependabot/file_parsers/base.rb +0 -31
  20. data/lib/dependabot/file_parsers.rb +0 -18
  21. data/lib/dependabot/file_updaters/README.md +0 -58
  22. data/lib/dependabot/file_updaters/base.rb +0 -52
  23. data/lib/dependabot/file_updaters.rb +0 -18
  24. data/lib/dependabot/git_commit_checker.rb +0 -412
  25. data/lib/dependabot/metadata_finders/README.md +0 -53
  26. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +0 -321
  27. data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +0 -177
  28. data/lib/dependabot/metadata_finders/base/commits_finder.rb +0 -221
  29. data/lib/dependabot/metadata_finders/base/release_finder.rb +0 -255
  30. data/lib/dependabot/metadata_finders/base.rb +0 -117
  31. data/lib/dependabot/metadata_finders.rb +0 -18
  32. data/lib/dependabot/pull_request_creator/branch_namer.rb +0 -170
  33. data/lib/dependabot/pull_request_creator/commit_signer.rb +0 -63
  34. data/lib/dependabot/pull_request_creator/github.rb +0 -277
  35. data/lib/dependabot/pull_request_creator/gitlab.rb +0 -136
  36. data/lib/dependabot/pull_request_creator/labeler.rb +0 -373
  37. data/lib/dependabot/pull_request_creator/message_builder.rb +0 -906
  38. data/lib/dependabot/pull_request_creator.rb +0 -153
  39. data/lib/dependabot/pull_request_updater/github.rb +0 -165
  40. data/lib/dependabot/pull_request_updater.rb +0 -43
  41. data/lib/dependabot/shared_helpers.rb +0 -224
  42. data/lib/dependabot/source.rb +0 -120
  43. data/lib/dependabot/update_checkers/README.md +0 -67
  44. data/lib/dependabot/update_checkers/base.rb +0 -220
  45. data/lib/dependabot/update_checkers.rb +0 -18
  46. data/lib/dependabot/utils.rb +0 -33
  47. data/lib/dependabot/version.rb +0 -5
  48. data/lib/dependabot.rb +0 -4
  49. data/lib/rubygems_version_patch.rb +0 -14
@@ -1,179 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/shared_helpers"
4
-
5
- module Dependabot
6
- class DependabotError < StandardError
7
- def initialize(msg = nil)
8
- msg = sanitize_message(msg)
9
- super(msg)
10
- end
11
-
12
- private
13
-
14
- def sanitize_message(message)
15
- return unless message
16
-
17
- path_regex =
18
- Regexp.escape(SharedHelpers::BUMP_TMP_DIR_PATH) + "\/" +
19
- Regexp.escape(SharedHelpers::BUMP_TMP_FILE_PREFIX) + "[^/]*"
20
-
21
- message.gsub(/#{path_regex}/, "dependabot_tmp_dir")
22
- end
23
- end
24
-
25
- class OutOfMemory < DependabotError; end
26
-
27
- #####################
28
- # Repo leval errors #
29
- #####################
30
-
31
- class BranchNotFound < DependabotError
32
- attr_reader :branch_name
33
-
34
- def initialize(branch_name, msg = nil)
35
- @branch_name = branch_name
36
- msg = sanitize_message(msg)
37
- super(msg)
38
- end
39
- end
40
-
41
- class RepoNotFound < DependabotError
42
- attr_reader :source
43
-
44
- def initialize(source, msg = nil)
45
- @source = source
46
- super(msg)
47
- end
48
- end
49
-
50
- #####################
51
- # File level errors #
52
- #####################
53
-
54
- class DependencyFileNotFound < DependabotError
55
- attr_reader :file_path
56
-
57
- def initialize(file_path, msg = nil)
58
- @file_path = file_path
59
- super(msg)
60
- end
61
-
62
- def file_name
63
- file_path.split("/").last
64
- end
65
-
66
- def directory
67
- # Directory should always start with a `/`
68
- file_path.split("/")[0..-2].join("/").sub(%r{^/*}, "/")
69
- end
70
- end
71
-
72
- class DependencyFileNotParseable < DependabotError
73
- attr_reader :file_path
74
-
75
- def initialize(file_path, msg = nil)
76
- @file_path = file_path
77
- super(msg)
78
- end
79
-
80
- def file_name
81
- file_path.split("/").last
82
- end
83
-
84
- def directory
85
- # Directory should always start with a `/`
86
- file_path.split("/")[0..-2].join("/").sub(%r{^/*}, "/")
87
- end
88
- end
89
-
90
- class DependencyFileNotEvaluatable < DependabotError; end
91
- class DependencyFileNotResolvable < DependabotError; end
92
-
93
- #######################
94
- # Source level errors #
95
- #######################
96
-
97
- class PrivateSourceAuthenticationFailure < DependabotError
98
- attr_reader :source
99
-
100
- def initialize(source)
101
- @source = source
102
- msg = "The following source could not be reached as it requires "\
103
- "authentication (and any provided details were invalid or lacked "\
104
- "the required permissions): #{source}"
105
- super(msg)
106
- end
107
- end
108
-
109
- class PrivateSourceTimedOut < DependabotError
110
- attr_reader :source
111
-
112
- def initialize(source)
113
- @source = source
114
- super("The following source timed out: #{source}")
115
- end
116
- end
117
-
118
- class PrivateSourceCertificateFailure < DependabotError
119
- attr_reader :source
120
-
121
- def initialize(source)
122
- @source = source
123
- super("Could not verify the SSL certificate for #{source}")
124
- end
125
- end
126
-
127
- class MissingEnvironmentVariable < DependabotError
128
- attr_reader :environment_variable
129
-
130
- def initialize(environment_variable)
131
- @environment_variable = environment_variable
132
- super("Missing environment variable #{environment_variable}")
133
- end
134
- end
135
-
136
- # Useful for JS file updaters, where the registry API sometimes returns
137
- # different results to the actual update process
138
- class InconsistentRegistryResponse < DependabotError; end
139
-
140
- ###########################
141
- # Dependency level errors #
142
- ###########################
143
-
144
- class GitDependenciesNotReachable < DependabotError
145
- attr_reader :dependency_urls
146
-
147
- def initialize(*dependency_urls)
148
- @dependency_urls =
149
- dependency_urls.flatten.map { |uri| uri.gsub(/x-access-token.*?@/, "") }
150
-
151
- msg = "The following git URLs could not be retrieved: "\
152
- "#{dependency_urls.join(', ')}"
153
- super(msg)
154
- end
155
- end
156
-
157
- class GitDependencyReferenceNotFound < DependabotError
158
- attr_reader :dependency
159
-
160
- def initialize(dependency)
161
- @dependency = dependency
162
-
163
- msg = "The branch or reference specified for #{dependency} could not "\
164
- "be retrieved"
165
- super(msg)
166
- end
167
- end
168
-
169
- class PathDependenciesNotReachable < DependabotError
170
- attr_reader :dependencies
171
-
172
- def initialize(*dependencies)
173
- @dependencies = dependencies.flatten
174
- msg = "The following path based dependencies could not be retrieved: "\
175
- "#{dependencies.join(', ')}"
176
- super(msg)
177
- end
178
- end
179
- end
@@ -1,65 +0,0 @@
1
- # File fetchers
2
-
3
- File fetchers are used to fetch the relevant dependency files for a project
4
- (e.g., the `Gemfile` and `Gemfile.lock`). They are also responsible for checking
5
- whether a repo has an admissable set of requirement files.
6
-
7
- There is a `Dependabot::FileFetchers` class for each language Dependabot
8
- supports.
9
-
10
- ## Public API
11
-
12
- Each `Dependabot::FileFetchers` class implements the following methods:
13
-
14
- | Method | Description |
15
- |----------------------------------|-----------------------------------------------------------------------------------------------|
16
- | `.required_files_in?` | Checks an array of filenames (string) and returns a boolean describing whether the language-specific dependency files required for an update run are present. |
17
- | `.required_files_message` | Returns a static error message which can be displayed to a user if `required_files_in?` returns false. |
18
- | `#files` | Fetches the language-specific dependency files for the repo this instance was created with. Returns an array of `Dependabot::DependencyFile` instances. |
19
- | `#commit` | Returns the commit SHA-1 hash at the time the dependency files were fetched. If called before `files`, the returned value will be used in subsequent calls to `files`. |
20
-
21
-
22
- An integration might look as follows:
23
-
24
- ```ruby
25
- require 'octokit'
26
- require 'dependabot/file_fetchers'
27
- require 'dependabot/source'
28
-
29
- target_repo_name = 'dependabot/dependabot-core'
30
- source = Dependabot::Source.new(provider: 'github', repo: target_repo_name)
31
-
32
- client = Octokit::Client.new
33
- fetcher_class = Dependabot::FileFetchers::Ruby::Bundler
34
- filenames = client.contents(target_repo_name).map(&:name)
35
-
36
- unless fetcher_class.required_files_in?(filenames)
37
- raise fetcher_class.required_files_message
38
- end
39
-
40
- fetcher = fetcher_class.new(source: source, credentials: [])
41
-
42
- puts "Fetched #{fetcher.files.map(&:name)}, at commit SHA-1 '#{fetcher.commit}'"
43
- ```
44
-
45
- ## Writing a file fetcher for a new language
46
-
47
- All new file fetchers should inherit from `Dependabot::FileFetchers::Base` and
48
- implement the following methods:
49
-
50
- | Method | Description |
51
- |----------------------------------|-----------------------------------------------------------------------------------------------|
52
- | `.required_files_in?` | See Public API section. |
53
- | `.required_files_message` | See Public API section. |
54
- | `#fetch_files` | Private method to fetch the required files from GitHub. For each required file, you can use the `fetch_file_from_host(filename)` method from `Dependabot::FileFetchers::Base` to do the fetching. |
55
-
56
- To ensure the above are implemented, you should include
57
- `it_behaves_like "a dependency file fetcher"` in your specs for the new file
58
- fetcher.
59
-
60
- File fetchers tend to get complicated when the file requirements for an update
61
- to run are non-trivial - for example, for Ruby we could accept
62
- [`Gemfile`, `Gemfile.lock`] or [`Gemfile`, `example.gemspec`],
63
- but not just [`Gemfile.lock`]. When adding a new lanugage, it's normally easiest
64
- to pick a single case and implement it for all the update steps (parsing, update
65
- checking, etc.). You can then return and add other cases later.
@@ -1,368 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "dependabot/dependency_file"
4
- require "dependabot/source"
5
- require "dependabot/errors"
6
- require "dependabot/clients/github_with_retries"
7
- require "dependabot/clients/bitbucket"
8
- require "dependabot/clients/gitlab"
9
- require "dependabot/shared_helpers"
10
-
11
- # rubocop:disable Metrics/ClassLength
12
- module Dependabot
13
- module FileFetchers
14
- class Base
15
- attr_reader :source, :credentials
16
-
17
- CLIENT_NOT_FOUND_ERRORS = [
18
- Octokit::NotFound,
19
- Gitlab::Error::NotFound,
20
- Dependabot::Clients::Bitbucket::NotFound
21
- ].freeze
22
-
23
- def self.required_files_in?(_filename_array)
24
- raise NotImplementedError
25
- end
26
-
27
- def self.required_files_message
28
- raise NotImplementedError
29
- end
30
-
31
- def initialize(source:, credentials:)
32
- @source = source
33
- @credentials = credentials
34
-
35
- @submodule_directories = {}
36
- end
37
-
38
- def repo
39
- source.repo
40
- end
41
-
42
- def directory
43
- source.directory || "/"
44
- end
45
-
46
- def target_branch
47
- source.branch
48
- end
49
-
50
- def files
51
- @files ||= fetch_files
52
- end
53
-
54
- def commit
55
- branch = target_branch || default_branch_for_repo
56
-
57
- @commit ||= client_for_provider.fetch_commit(repo, branch)
58
- rescue *CLIENT_NOT_FOUND_ERRORS
59
- raise Dependabot::BranchNotFound, branch
60
- rescue Octokit::Conflict => error
61
- raise unless error.message.include?("Repository is empty")
62
- end
63
-
64
- private
65
-
66
- def fetch_file_if_present(filename, fetch_submodules: false)
67
- dir = File.dirname(filename)
68
- basename = File.basename(filename)
69
-
70
- repo_includes_basename =
71
- repo_contents(dir: dir, fetch_submodules: fetch_submodules).
72
- reject { |f| f.type == "dir" }.
73
- map(&:name).include?(basename)
74
- return unless repo_includes_basename
75
-
76
- fetch_file_from_host(filename, fetch_submodules: fetch_submodules)
77
- rescue *CLIENT_NOT_FOUND_ERRORS
78
- path = Pathname.new(File.join(directory, filename)).cleanpath.to_path
79
- raise Dependabot::DependencyFileNotFound, path
80
- end
81
-
82
- def fetch_file_from_host(filename, type: "file", fetch_submodules: false)
83
- path = Pathname.new(File.join(directory, filename)).cleanpath.to_path
84
-
85
- DependencyFile.new(
86
- name: Pathname.new(filename).cleanpath.to_path,
87
- directory: directory,
88
- type: type,
89
- content: _fetch_file_content(path, fetch_submodules: fetch_submodules)
90
- )
91
- rescue *CLIENT_NOT_FOUND_ERRORS
92
- raise Dependabot::DependencyFileNotFound, path
93
- end
94
-
95
- def repo_contents(dir: ".", ignore_base_directory: false,
96
- raise_errors: true, fetch_submodules: false)
97
- dir = File.join(directory, dir) unless ignore_base_directory
98
- path = Pathname.new(File.join(dir)).cleanpath.to_path.gsub(%r{^/*}, "")
99
-
100
- @repo_contents ||= {}
101
- @repo_contents[dir] ||= _fetch_repo_contents(
102
- path,
103
- raise_errors: raise_errors,
104
- fetch_submodules: fetch_submodules
105
- )
106
- end
107
-
108
- #################################################
109
- # INTERNAL METHODS (not for use by sub-classes) #
110
- #################################################
111
-
112
- def _fetch_repo_contents(path, fetch_submodules: false,
113
- raise_errors: true)
114
- path = path.gsub(" ", "%20")
115
- provider, repo, tmp_path, commit =
116
- _full_specification_for(path, fetch_submodules: fetch_submodules).
117
- values_at(:provider, :repo, :path, :commit)
118
-
119
- _fetch_repo_contents_fully_specified(provider, repo, tmp_path, commit)
120
- rescue *CLIENT_NOT_FOUND_ERRORS
121
- result = raise_errors ? -> { raise } : -> { [] }
122
- retrying ||= false
123
-
124
- # If the path changes after calling _fetch_repo_contents_fully_specified
125
- # it's because we've found a sub-module (and are fetching them). Trigger
126
- # a retry to get its contents.
127
- updated_path =
128
- _full_specification_for(path, fetch_submodules: fetch_submodules).
129
- fetch(:path)
130
- retry if updated_path != tmp_path
131
-
132
- return result.call unless fetch_submodules && !retrying
133
-
134
- _find_submodules(path)
135
- return result.call unless _submodule_for(path)
136
-
137
- retrying = true
138
- retry
139
- end
140
-
141
- def _fetch_repo_contents_fully_specified(provider, repo, path, commit)
142
- case provider
143
- when "github"
144
- _github_repo_contents(repo, path, commit)
145
- when "gitlab"
146
- _gitlab_repo_contents(repo, path, commit)
147
- when "bitbucket"
148
- _bitbucket_repo_contents(repo, path, commit)
149
- else raise "Unsupported provider '#{provider}'."
150
- end
151
- end
152
-
153
- def _github_repo_contents(repo, path, commit)
154
- path = path.gsub(" ", "%20")
155
- github_response = github_client.contents(repo, path: path, ref: commit)
156
-
157
- if github_response.respond_to?(:type) &&
158
- github_response.type == "submodule"
159
- @submodule_directories[path] = github_response
160
- raise Octokit::NotFound
161
- elsif github_response.respond_to?(:type)
162
- raise Octokit::NotFound
163
- end
164
-
165
- github_response.map { |f| _build_github_file_struct(f) }
166
- end
167
-
168
- def _build_github_file_struct(file)
169
- OpenStruct.new(
170
- name: file.name,
171
- path: file.path,
172
- type: file.type,
173
- sha: file.sha,
174
- size: file.size
175
- )
176
- end
177
-
178
- def _gitlab_repo_contents(repo, path, commit)
179
- gitlab_client.
180
- repo_tree(repo, path: path, ref_name: commit, per_page: 100).
181
- map do |file|
182
- OpenStruct.new(
183
- name: file.name,
184
- path: file.path,
185
- type: file.type == "blob" ? "file" : file.type,
186
- size: 0 # GitLab doesn't return file size
187
- )
188
- end
189
- end
190
-
191
- def _bitbucket_repo_contents(repo, path, commit)
192
- response = bitbucket_client.fetch_repo_contents(
193
- repo,
194
- commit,
195
- path
196
- )
197
-
198
- response.map do |file|
199
- type = case file.fetch("type")
200
- when "commit_file" then "file"
201
- when "commit_directory" then "dir"
202
- else file.fetch("type")
203
- end
204
-
205
- OpenStruct.new(
206
- name: File.basename(file.fetch("path")),
207
- path: file.fetch("path"),
208
- type: type,
209
- size: file.fetch("size", 0)
210
- )
211
- end
212
- end
213
-
214
- def _full_specification_for(path, fetch_submodules:)
215
- if fetch_submodules && _submodule_for(path) &&
216
- Source.from_url(
217
- @submodule_directories[_submodule_for(path)].submodule_git_url
218
- )
219
- submodule_details = @submodule_directories[_submodule_for(path)]
220
- sub_source = Source.from_url(submodule_details.submodule_git_url)
221
- {
222
- repo: sub_source.repo,
223
- commit: submodule_details.sha,
224
- provider: sub_source.provider,
225
- path: path.gsub(%r{^#{Regexp.quote(_submodule_for(path))}(/|$)}, "")
226
- }
227
- else
228
- {
229
- repo: source.repo,
230
- path: path,
231
- commit: commit,
232
- provider: source.provider
233
- }
234
- end
235
- end
236
-
237
- def _fetch_file_content(path, fetch_submodules: false)
238
- path = path.gsub(%r{^/*}, "")
239
-
240
- provider, repo, path, commit =
241
- _full_specification_for(path, fetch_submodules: fetch_submodules).
242
- values_at(:provider, :repo, :path, :commit)
243
-
244
- _fetch_file_content_fully_specified(provider, repo, path, commit)
245
- rescue *CLIENT_NOT_FOUND_ERRORS
246
- retrying ||= false
247
-
248
- raise unless fetch_submodules && !retrying && !_submodule_for(path)
249
-
250
- _find_submodules(path)
251
- raise unless _submodule_for(path)
252
-
253
- retrying = true
254
- retry
255
- end
256
-
257
- def _fetch_file_content_fully_specified(provider, repo, path, commit)
258
- case provider
259
- when "github"
260
- _fetch_file_content_from_github(path, repo, commit)
261
- when "gitlab"
262
- tmp = gitlab_client.get_file(repo, path, commit).content
263
- Base64.decode64(tmp).force_encoding("UTF-8").encode
264
- when "bitbucket"
265
- bitbucket_client.fetch_file_contents(repo, commit, path)
266
- else raise "Unsupported provider '#{source.provider}'."
267
- end
268
- end
269
-
270
- # rubocop:disable Metrics/AbcSize
271
- def _fetch_file_content_from_github(path, repo, commit)
272
- tmp = github_client.contents(repo, path: path, ref: commit)
273
-
274
- raise Octokit::NotFound if tmp.is_a?(Array)
275
-
276
- if tmp.type == "symlink"
277
- tmp = github_client.contents(
278
- repo,
279
- path: tmp.target,
280
- ref: commit
281
- )
282
- end
283
-
284
- Base64.decode64(tmp.content).force_encoding("UTF-8").encode
285
- rescue Octokit::Forbidden => error
286
- raise unless error.message.include?("too_large")
287
-
288
- # Fall back to Git Data API to fetch the file
289
- prefix_dir = directory.gsub(%r{(^/|/$)}, "")
290
- dir = File.dirname(path).gsub(%r{^/?#{Regexp.escape(prefix_dir)}/?}, "")
291
- basename = File.basename(path)
292
- file_details = repo_contents(dir: dir).find { |f| f.name == basename }
293
- raise unless file_details
294
-
295
- tmp = github_client.blob(repo, file_details.sha)
296
- return tmp.content if tmp.encoding == "utf-8"
297
-
298
- Base64.decode64(tmp.content).force_encoding("UTF-8").encode
299
- end
300
- # rubocop:enable Metrics/AbcSize
301
-
302
- def default_branch_for_repo
303
- @default_branch_for_repo ||= client_for_provider.
304
- fetch_default_branch(repo)
305
- rescue *CLIENT_NOT_FOUND_ERRORS
306
- raise Dependabot::RepoNotFound, source
307
- end
308
-
309
- # Update the @submodule_directories hash by exploiting a side-effect of
310
- # recursively calling `repo_contents` for each directory up the tree
311
- # until a submodule is found
312
- def _find_submodules(path)
313
- path = Pathname.new(path).cleanpath.to_path.gsub(%r{^/*}, "")
314
- dir = File.dirname(path)
315
-
316
- return if [directory, "."].include?(dir)
317
-
318
- repo_contents(
319
- dir: dir,
320
- ignore_base_directory: true,
321
- fetch_submodules: true,
322
- raise_errors: false
323
- )
324
- end
325
-
326
- def _submodule_for(path)
327
- submodules = @submodule_directories.keys
328
- submodules.
329
- select { |k| path.match?(%r{^#{Regexp.quote(k)}(/|$)}) }.
330
- max_by(&:length)
331
- end
332
-
333
- def client_for_provider
334
- case source.provider
335
- when "github" then github_client
336
- when "gitlab" then gitlab_client
337
- when "bitbucket" then bitbucket_client
338
- else raise "Unsupported provider '#{source.provider}'."
339
- end
340
- end
341
-
342
- def github_client
343
- @github_client ||=
344
- Dependabot::Clients::GithubWithRetries.for_source(
345
- source: source,
346
- credentials: credentials
347
- )
348
- end
349
-
350
- def gitlab_client
351
- @gitlab_client ||=
352
- Dependabot::Clients::Gitlab.for_source(
353
- source: source,
354
- credentials: credentials
355
- )
356
- end
357
-
358
- def bitbucket_client
359
- # TODO: When self-hosted Bitbucket is supported this should use
360
- # `Bitbucket.for_source`
361
- @bitbucket_client ||=
362
- Dependabot::Clients::Bitbucket.
363
- for_bitbucket_dot_org(credentials: credentials)
364
- end
365
- end
366
- end
367
- end
368
- # rubocop:enable Metrics/ClassLength
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Dependabot
4
- module FileFetchers
5
- @file_fetchers = {}
6
-
7
- def self.for_package_manager(package_manager)
8
- file_fetcher = @file_fetchers[package_manager]
9
- return file_fetcher if file_fetcher
10
-
11
- raise "Unsupported package_manager #{package_manager}"
12
- end
13
-
14
- def self.register(package_manager, file_fetcher)
15
- @file_fetchers[package_manager] = file_fetcher
16
- end
17
- end
18
- end
@@ -1,45 +0,0 @@
1
- # File parsers
2
-
3
- File parsers take a set of dependency files and extract a list of dependencies
4
- for the project.
5
-
6
- There is a `Dependabot::FileParsers` class for each language Dependabot
7
- supports.
8
-
9
- ## Public API
10
-
11
- Each `Dependabot::FileParsers` class implements the following methods:
12
-
13
- | Method | Description |
14
- |---------------------|-----------------------------------------------------------------------------------------------|
15
- | `#parse` | Returns an array of `Dependabot::Dependency` instances, representing the dependencies for the project. Each `Dependabot::Dependency` has a `name`, `version` and a `requirements` array |
16
-
17
- An integration might look as follows:
18
-
19
- ```ruby
20
- require 'dependabot/file_parsers'
21
-
22
- files = fetcher.files
23
-
24
- parser_class = Dependabot::FileParsers::Ruby::Bundler
25
- source = Dependabot::Source.new(provider: 'github', repo: "gocardless/business")
26
- parser = parser_class.new(dependency_files: files, source: source)
27
-
28
- dependencies = parser.parse
29
-
30
- puts "Found the following dependencies: #{dependencies.map(&:name)}"
31
- ```
32
-
33
- ## Writing a file parser for a new language
34
-
35
- All new file parsers should inherit from `Dependabot::FileParsers::Base` and
36
- implement the following methods:
37
-
38
- | Method | Description |
39
- |-------------------------|-----------------------------------------------------------------------------------------------|
40
- | `#parse` | See Public API section. |
41
- | `#check_required_files` | Raise a runtime error unless an appropriate set of files is provided. Private. |
42
-
43
- To ensure the above are implemented, you should include
44
- `it_behaves_like "a dependency file parser"` in your specs for the new file
45
- parser.