dependabot-common 0.333.0 → 0.335.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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot/clients/azure.rb +108 -60
  3. data/lib/dependabot/clients/bitbucket.rb +17 -4
  4. data/lib/dependabot/clients/codecommit.rb +17 -7
  5. data/lib/dependabot/config/file.rb +31 -28
  6. data/lib/dependabot/dependency.rb +18 -7
  7. data/lib/dependabot/dependency_file.rb +17 -6
  8. data/lib/dependabot/dependency_graphers/README.md +54 -0
  9. data/lib/dependabot/dependency_graphers/base.rb +118 -0
  10. data/lib/dependabot/dependency_graphers/generic.rb +76 -0
  11. data/lib/dependabot/dependency_graphers.rb +33 -0
  12. data/lib/dependabot/file_fetchers/base.rb +11 -4
  13. data/lib/dependabot/file_filtering.rb +9 -5
  14. data/lib/dependabot/file_parsers/base.rb +8 -2
  15. data/lib/dependabot/file_updaters/artifact_updater.rb +1 -0
  16. data/lib/dependabot/git_commit_checker.rb +17 -10
  17. data/lib/dependabot/git_metadata_fetcher.rb +4 -2
  18. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +6 -2
  19. data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +4 -2
  20. data/lib/dependabot/notices.rb +7 -3
  21. data/lib/dependabot/package/release_cooldown_options.rb +6 -2
  22. data/lib/dependabot/pull_request_creator/azure.rb +15 -3
  23. data/lib/dependabot/pull_request_creator/bitbucket.rb +13 -3
  24. data/lib/dependabot/pull_request_creator/branch_namer/base.rb +8 -2
  25. data/lib/dependabot/pull_request_creator/branch_namer/dependency_group_strategy.rb +15 -5
  26. data/lib/dependabot/pull_request_creator/branch_namer/multi_ecosystem_strategy.rb +15 -5
  27. data/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb +11 -7
  28. data/lib/dependabot/pull_request_creator/branch_namer.rb +11 -2
  29. data/lib/dependabot/pull_request_creator/codecommit.rb +20 -7
  30. data/lib/dependabot/pull_request_creator/commit_signer.rb +10 -4
  31. data/lib/dependabot/pull_request_creator/github.rb +18 -5
  32. data/lib/dependabot/pull_request_creator/gitlab.rb +16 -4
  33. data/lib/dependabot/pull_request_creator/labeler.rb +35 -19
  34. data/lib/dependabot/pull_request_creator/message_builder/issue_linker.rb +15 -10
  35. data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +7 -2
  36. data/lib/dependabot/pull_request_creator/message_builder.rb +16 -6
  37. data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +7 -2
  38. data/lib/dependabot/pull_request_creator.rb +31 -12
  39. data/lib/dependabot/pull_request_updater/azure.rb +9 -2
  40. data/lib/dependabot/pull_request_updater/github.rb +10 -3
  41. data/lib/dependabot/pull_request_updater/gitlab.rb +9 -2
  42. data/lib/dependabot/pull_request_updater.rb +11 -4
  43. data/lib/dependabot/security_advisory.rb +12 -6
  44. data/lib/dependabot/shared_helpers.rb +36 -19
  45. data/lib/dependabot/source.rb +14 -4
  46. data/lib/dependabot/update_checkers/base.rb +13 -5
  47. data/lib/dependabot.rb +1 -1
  48. metadata +16 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97cacde3bd9b1e5403604eb71363db435ab78fec1a794f0e75c264822033fa8d
4
- data.tar.gz: 84122d41a73c7c439ff2cfccb58200ccabed7a76577814f856fb63fcc7c599d8
3
+ metadata.gz: ca29ec928a5e569aa377708755f29f998ca87ddb68ed2722a5171386427e3f87
4
+ data.tar.gz: 206f507ef450d40f3a002187a7890dc5b5abc88c7d8df5e53a87a27a14aa9f71
5
5
  SHA512:
6
- metadata.gz: 849fb16bfa7ce8d2b90185214d609ac3b505001069fc86ba9ace6d8794e80f9a8dfabe6e15153e1ce2f2a50bc2a4622d4aa593da5dbbda23c1f0fe822690ee4b
7
- data.tar.gz: 9b0dc17ff63aac4c32f086e18b5deaaf28a9a216c5bf533fe5766b94d10add47a9597d26c97aaa6de625015eeae74d1b5af44c8425e75ba8a9f82d125d800a9a
6
+ metadata.gz: 3a3baf81472a1b7528fb6f95f9c5ed76f79186fd4aa442e073b2f0bc60e676186f592ab16a18f1f6bb747e652e522d0f1af2a7ac077a3dbce0d89001c001fc93
7
+ data.tar.gz: 26a4aaa04570ec094267b7e2739a394fe4d279807ad03453ac6cec8c766d18cb3b13e73665923cf8e58ca64ab6fad7b8b8a20656a0feaa93b80bcdaed6119503
@@ -65,10 +65,12 @@ module Dependabot
65
65
 
66
66
  sig { params(_repo: T.nilable(String), branch: String).returns(String) }
67
67
  def fetch_commit(_repo, branch)
68
- response = get(T.must(source.api_endpoint) +
69
- source.organization + "/" + source.project +
70
- "/_apis/git/repositories/" + source.unscoped_repo +
71
- "/stats/branches?name=" + branch)
68
+ response = get(
69
+ T.must(source.api_endpoint) +
70
+ source.organization + "/" + source.project +
71
+ "/_apis/git/repositories/" + source.unscoped_repo +
72
+ "/stats/branches?name=" + branch
73
+ )
72
74
 
73
75
  raise NotFound if response.status == 400
74
76
 
@@ -77,9 +79,11 @@ module Dependabot
77
79
 
78
80
  sig { params(_repo: String).returns(String) }
79
81
  def fetch_default_branch(_repo)
80
- response = get(T.must(source.api_endpoint) +
81
- source.organization + "/" + source.project +
82
- "/_apis/git/repositories/" + source.unscoped_repo)
82
+ response = get(
83
+ T.must(source.api_endpoint) +
84
+ source.organization + "/" + source.project +
85
+ "/_apis/git/repositories/" + source.unscoped_repo
86
+ )
83
87
 
84
88
  JSON.parse(response.body).fetch("defaultBranch").gsub("refs/heads/", "")
85
89
  end
@@ -94,10 +98,12 @@ module Dependabot
94
98
  def fetch_repo_contents(commit = nil, path = nil)
95
99
  tree = fetch_repo_contents_treeroot(commit, path)
96
100
 
97
- response = get(T.must(source.api_endpoint) +
98
- source.organization + "/" + source.project +
99
- "/_apis/git/repositories/" + source.unscoped_repo +
100
- "/trees/" + tree + "?recursive=false")
101
+ response = get(
102
+ T.must(source.api_endpoint) +
103
+ source.organization + "/" + source.project +
104
+ "/_apis/git/repositories/" + source.unscoped_repo +
105
+ "/trees/" + tree + "?recursive=false"
106
+ )
101
107
 
102
108
  JSON.parse(response.body).fetch("treeEntries")
103
109
  end
@@ -124,12 +130,14 @@ module Dependabot
124
130
 
125
131
  sig { params(commit: String, path: String).returns(String) }
126
132
  def fetch_file_contents(commit, path)
127
- response = get(T.must(source.api_endpoint) +
128
- source.organization + "/" + source.project +
129
- "/_apis/git/repositories/" + source.unscoped_repo +
130
- "/items?path=" + path +
131
- "&versionDescriptor.versionType=commit" \
132
- "&versionDescriptor.version=" + commit)
133
+ response = get(
134
+ T.must(source.api_endpoint) +
135
+ source.organization + "/" + source.project +
136
+ "/_apis/git/repositories/" + source.unscoped_repo +
137
+ "/items?path=" + path +
138
+ "&versionDescriptor.versionType=commit" \
139
+ "&versionDescriptor.version=" + commit
140
+ )
133
141
 
134
142
  response.body
135
143
  end
@@ -150,22 +158,26 @@ module Dependabot
150
158
 
151
159
  sig { params(branch_name: String).returns(T.nilable(T::Hash[String, T.untyped])) }
152
160
  def branch(branch_name)
153
- response = get(T.must(source.api_endpoint) +
154
- source.organization + "/" + source.project +
155
- "/_apis/git/repositories/" + source.unscoped_repo +
156
- "/refs?filter=heads/" + branch_name)
161
+ response = get(
162
+ T.must(source.api_endpoint) +
163
+ source.organization + "/" + source.project +
164
+ "/_apis/git/repositories/" + source.unscoped_repo +
165
+ "/refs?filter=heads/" + branch_name
166
+ )
157
167
 
158
168
  JSON.parse(response.body).fetch("value").first
159
169
  end
160
170
 
161
171
  sig { params(source_branch: String, target_branch: String).returns(T::Array[T::Hash[String, T.untyped]]) }
162
172
  def pull_requests(source_branch, target_branch)
163
- response = get(T.must(source.api_endpoint) +
164
- source.organization + "/" + source.project +
165
- "/_apis/git/repositories/" + source.unscoped_repo +
166
- "/pullrequests?searchCriteria.status=all" \
167
- "&searchCriteria.sourceRefName=refs/heads/" + source_branch +
168
- "&searchCriteria.targetRefName=refs/heads/" + target_branch)
173
+ response = get(
174
+ T.must(source.api_endpoint) +
175
+ source.organization + "/" + source.project +
176
+ "/_apis/git/repositories/" + source.unscoped_repo +
177
+ "/pullrequests?searchCriteria.status=all" \
178
+ "&searchCriteria.sourceRefName=refs/heads/" + source_branch +
179
+ "&searchCriteria.targetRefName=refs/heads/" + target_branch
180
+ )
169
181
 
170
182
  JSON.parse(response.body).fetch("value")
171
183
  end
@@ -180,8 +192,13 @@ module Dependabot
180
192
  )
181
193
  .returns(T.untyped)
182
194
  end
183
- def create_commit(branch_name, base_commit, commit_message, files,
184
- author_details)
195
+ def create_commit(
196
+ branch_name,
197
+ base_commit,
198
+ commit_message,
199
+ files,
200
+ author_details
201
+ )
185
202
  content = {
186
203
  refUpdates: [
187
204
  { name: "refs/heads/" + branch_name, oldObjectId: base_commit }
@@ -204,9 +221,12 @@ module Dependabot
204
221
  ]
205
222
  }
206
223
 
207
- post(T.must(source.api_endpoint) + source.organization + "/" + source.project +
208
- "/_apis/git/repositories/" + source.unscoped_repo +
209
- "/pushes?api-version=5.0", content.to_json)
224
+ post(
225
+ T.must(source.api_endpoint) + source.organization + "/" + source.project +
226
+ "/_apis/git/repositories/" + source.unscoped_repo +
227
+ "/pushes?api-version=5.0",
228
+ content.to_json
229
+ )
210
230
  end
211
231
 
212
232
  # rubocop:disable Metrics/ParameterLists
@@ -223,9 +243,16 @@ module Dependabot
223
243
  )
224
244
  .returns(T.untyped)
225
245
  end
226
- def create_pull_request(pr_name, source_branch, target_branch,
227
- pr_description, labels,
228
- reviewers = nil, assignees = nil, work_item = nil)
246
+ def create_pull_request(
247
+ pr_name,
248
+ source_branch,
249
+ target_branch,
250
+ pr_description,
251
+ labels,
252
+ reviewers = nil,
253
+ assignees = nil,
254
+ work_item = nil
255
+ )
229
256
  content = {
230
257
  sourceRefName: "refs/heads/" + source_branch,
231
258
  targetRefName: "refs/heads/" + target_branch,
@@ -236,10 +263,13 @@ module Dependabot
236
263
  workItemRefs: [{ id: work_item }]
237
264
  }
238
265
 
239
- post(T.must(source.api_endpoint) +
240
- source.organization + "/" + source.project +
241
- "/_apis/git/repositories/" + source.unscoped_repo +
242
- "/pullrequests?api-version=5.0", content.to_json)
266
+ post(
267
+ T.must(source.api_endpoint) +
268
+ source.organization + "/" + source.project +
269
+ "/_apis/git/repositories/" + source.unscoped_repo +
270
+ "/pullrequests?api-version=5.0",
271
+ content.to_json
272
+ )
243
273
  end
244
274
 
245
275
  sig do
@@ -255,9 +285,16 @@ module Dependabot
255
285
  )
256
286
  .returns(T.untyped)
257
287
  end
258
- def autocomplete_pull_request(pull_request_id, auto_complete_set_by, merge_commit_message,
259
- delete_source_branch = true, squash_merge = true, merge_strategy = "squash",
260
- trans_work_items = true, ignore_config_ids = [])
288
+ def autocomplete_pull_request(
289
+ pull_request_id,
290
+ auto_complete_set_by,
291
+ merge_commit_message,
292
+ delete_source_branch = true,
293
+ squash_merge = true,
294
+ merge_strategy = "squash",
295
+ trans_work_items = true,
296
+ ignore_config_ids = []
297
+ )
261
298
  content = {
262
299
  autoCompleteSetBy: {
263
300
  id: auto_complete_set_by
@@ -272,19 +309,24 @@ module Dependabot
272
309
  }
273
310
  }
274
311
 
275
- response = patch(T.must(source.api_endpoint) +
276
- source.organization + "/" + source.project +
277
- "/_apis/git/repositories/" + source.unscoped_repo +
278
- "/pullrequests/" + pull_request_id.to_s + "?api-version=5.1", content.to_json)
312
+ response = patch(
313
+ T.must(source.api_endpoint) +
314
+ source.organization + "/" + source.project +
315
+ "/_apis/git/repositories/" + source.unscoped_repo +
316
+ "/pullrequests/" + pull_request_id.to_s + "?api-version=5.1",
317
+ content.to_json
318
+ )
279
319
 
280
320
  JSON.parse(response.body)
281
321
  end
282
322
 
283
323
  sig { params(pull_request_id: String).returns(T::Hash[String, T.untyped]) }
284
324
  def pull_request(pull_request_id)
285
- response = get(T.must(source.api_endpoint) +
286
- source.organization + "/" + source.project +
287
- "/_apis/git/pullrequests/" + pull_request_id)
325
+ response = get(
326
+ T.must(source.api_endpoint) +
327
+ source.organization + "/" + source.project +
328
+ "/_apis/git/pullrequests/" + pull_request_id
329
+ )
288
330
 
289
331
  JSON.parse(response.body)
290
332
  end
@@ -299,9 +341,12 @@ module Dependabot
299
341
  }
300
342
  ]
301
343
 
302
- response = post(T.must(source.api_endpoint) + source.organization + "/" + source.project +
303
- "/_apis/git/repositories/" + source.unscoped_repo +
304
- "/refs?api-version=5.0", content.to_json)
344
+ response = post(
345
+ T.must(source.api_endpoint) + source.organization + "/" + source.project +
346
+ "/_apis/git/repositories/" + source.unscoped_repo +
347
+ "/refs?api-version=5.0",
348
+ content.to_json
349
+ )
305
350
 
306
351
  JSON.parse(response.body).fetch("value").first
307
352
  end
@@ -309,19 +354,22 @@ module Dependabot
309
354
 
310
355
  sig do
311
356
  params(
312
- previous_tag: T.nilable(String), new_tag: T.nilable(String),
357
+ previous_tag: T.nilable(String),
358
+ new_tag: T.nilable(String),
313
359
  type: String
314
360
  )
315
361
  .returns(T::Array[T::Hash[String, T.untyped]])
316
362
  end
317
363
  def compare(previous_tag, new_tag, type)
318
- response = get(T.must(source.api_endpoint) +
319
- source.organization + "/" + source.project +
320
- "/_apis/git/repositories/" + source.unscoped_repo +
321
- "/commits?searchCriteria.itemVersion.versionType=#{type}" \
322
- "&searchCriteria.itemVersion.version=#{previous_tag}" \
323
- "&searchCriteria.compareVersion.versionType=#{type}" \
324
- "&searchCriteria.compareVersion.version=#{new_tag}")
364
+ response = get(
365
+ T.must(source.api_endpoint) +
366
+ source.organization + "/" + source.project +
367
+ "/_apis/git/repositories/" + source.unscoped_repo +
368
+ "/commits?searchCriteria.itemVersion.versionType=#{type}" \
369
+ "&searchCriteria.itemVersion.version=#{previous_tag}" \
370
+ "&searchCriteria.compareVersion.versionType=#{type}" \
371
+ "&searchCriteria.compareVersion.version=#{new_tag}"
372
+ )
325
373
 
326
374
  JSON.parse(response.body).fetch("value")
327
375
  end
@@ -168,8 +168,14 @@ module Dependabot
168
168
  )
169
169
  .void
170
170
  end
171
- def create_commit(repo, branch_name, base_commit, commit_message, files,
172
- author_details)
171
+ def create_commit(
172
+ repo,
173
+ branch_name,
174
+ base_commit,
175
+ commit_message,
176
+ files,
177
+ author_details
178
+ )
173
179
  parameters = {
174
180
  message: commit_message, # TODO: Format markup in commit message
175
181
  author: "#{author_details.fetch(:name)} <#{author_details.fetch(:email)}>",
@@ -201,8 +207,15 @@ module Dependabot
201
207
  )
202
208
  .void
203
209
  end
204
- def create_pull_request(repo, pr_name, source_branch, target_branch,
205
- pr_description, _labels, _work_item = nil)
210
+ def create_pull_request(
211
+ repo,
212
+ pr_name,
213
+ source_branch,
214
+ target_branch,
215
+ pr_description,
216
+ _labels,
217
+ _work_item = nil
218
+ )
206
219
  reviewers = default_reviewers(repo)
207
220
 
208
221
  content = {
@@ -79,7 +79,8 @@ module Dependabot
79
79
 
80
80
  sig do
81
81
  params(
82
- repo: String, commit: T.nilable(String),
82
+ repo: String,
83
+ commit: T.nilable(String),
83
84
  path: T.nilable(String)
84
85
  )
85
86
  # See PR 9344: should .returns(Seahorse::Client::Response)
@@ -112,8 +113,8 @@ module Dependabot
112
113
  commit_specifier: commit,
113
114
  file_path: path
114
115
  ).file_content
115
- rescue Aws::CodeCommit::Errors::FileDoesNotExistException
116
- raise NotFound
116
+ rescue Aws::CodeCommit::Errors::FileDoesNotExistException
117
+ raise NotFound
117
118
  end
118
119
 
119
120
  sig do
@@ -253,8 +254,13 @@ module Dependabot
253
254
  )
254
255
  .returns(Aws::CodeCommit::Types::CreateCommitOutput)
255
256
  end
256
- def create_commit(branch_name, author_name, base_commit, commit_message,
257
- files)
257
+ def create_commit(
258
+ branch_name,
259
+ author_name,
260
+ base_commit,
261
+ commit_message,
262
+ files
263
+ )
258
264
  cc_client.create_commit(
259
265
  repository_name: source.unscoped_repo,
260
266
  branch_name: branch_name,
@@ -280,8 +286,12 @@ module Dependabot
280
286
  )
281
287
  .returns(T.nilable(Aws::CodeCommit::Types::CreatePullRequestOutput))
282
288
  end
283
- def create_pull_request(pr_name, target_branch, source_branch,
284
- pr_description)
289
+ def create_pull_request(
290
+ pr_name,
291
+ target_branch,
292
+ source_branch,
293
+ pr_description
294
+ )
285
295
  cc_client.create_pull_request(
286
296
  title: pr_name,
287
297
  description: pr_description,
@@ -58,34 +58,37 @@ module Dependabot
58
58
 
59
59
  private
60
60
 
61
- PACKAGE_MANAGER_LOOKUP = T.let({
62
- "bun" => "bun",
63
- "bundler" => "bundler",
64
- "cargo" => "cargo",
65
- "composer" => "composer",
66
- "conda" => "conda",
67
- "devcontainer" => "devcontainers",
68
- "docker-compose" => "docker_compose",
69
- "docker" => "docker",
70
- "dotnet-sdk" => "dotnet_sdk",
71
- "elm" => "elm",
72
- "github-actions" => "github_actions",
73
- "gitsubmodule" => "submodules",
74
- "gomod" => "go_modules",
75
- "gradle" => "gradle",
76
- "helm" => "helm",
77
- "maven" => "maven",
78
- "mix" => "hex",
79
- "npm" => "npm_and_yarn",
80
- "nuget" => "nuget",
81
- "pip" => "pip",
82
- "pub" => "pub",
83
- "rust-toolchain" => "rust_toolchain",
84
- "swift" => "swift",
85
- "terraform" => "terraform",
86
- "uv" => "uv",
87
- "vcpkg" => "vcpkg"
88
- }.freeze, T::Hash[String, String])
61
+ PACKAGE_MANAGER_LOOKUP = T.let(
62
+ {
63
+ "bun" => "bun",
64
+ "bundler" => "bundler",
65
+ "cargo" => "cargo",
66
+ "composer" => "composer",
67
+ "conda" => "conda",
68
+ "devcontainer" => "devcontainers",
69
+ "docker-compose" => "docker_compose",
70
+ "docker" => "docker",
71
+ "dotnet-sdk" => "dotnet_sdk",
72
+ "elm" => "elm",
73
+ "github-actions" => "github_actions",
74
+ "gitsubmodule" => "submodules",
75
+ "gomod" => "go_modules",
76
+ "gradle" => "gradle",
77
+ "helm" => "helm",
78
+ "maven" => "maven",
79
+ "mix" => "hex",
80
+ "npm" => "npm_and_yarn",
81
+ "nuget" => "nuget",
82
+ "pip" => "pip",
83
+ "pub" => "pub",
84
+ "rust-toolchain" => "rust_toolchain",
85
+ "swift" => "swift",
86
+ "terraform" => "terraform",
87
+ "uv" => "uv",
88
+ "vcpkg" => "vcpkg"
89
+ }.freeze,
90
+ T::Hash[String, String]
91
+ )
89
92
 
90
93
  REVERSE_PACKAGE_MANAGER_LOOKUP = T.let(
91
94
  PACKAGE_MANAGER_LOOKUP.invert.freeze,
@@ -118,9 +118,18 @@ module Dependabot
118
118
  metadata: T.nilable(T::Hash[T.any(Symbol, String), String])
119
119
  ).void
120
120
  end
121
- def initialize(name:, requirements:, package_manager:, version: nil,
122
- previous_version: nil, previous_requirements: nil, directory: nil,
123
- subdependency_metadata: [], removed: false, metadata: {})
121
+ def initialize(
122
+ name:,
123
+ requirements:,
124
+ package_manager:,
125
+ version: nil,
126
+ previous_version: nil,
127
+ previous_requirements: nil,
128
+ directory: nil,
129
+ subdependency_metadata: [],
130
+ removed: false,
131
+ metadata: {}
132
+ )
124
133
  @name = name
125
134
  @version = T.let(
126
135
  case version
@@ -239,6 +248,7 @@ module Dependabot
239
248
  sig { returns(T.nilable(String)) }
240
249
  def humanized_version
241
250
  return "removed" if removed?
251
+ return nil if version.nil?
242
252
 
243
253
  if T.must(version).match?(/^[0-9a-f]{40}/)
244
254
  return new_ref if ref_changed? && new_ref
@@ -399,10 +409,11 @@ module Dependabot
399
409
  optional_keys = %i(metadata)
400
410
  unless requirement_fields.flatten
401
411
  .all? { |r| required_keys.sort == (r.keys - optional_keys).sort }
402
- raise ArgumentError, "each requirement must have the following " \
403
- "required keys: #{required_keys.join(', ')}." \
404
- "Optionally, it may have the following keys: " \
405
- "#{optional_keys.join(', ')}."
412
+ raise ArgumentError,
413
+ "each requirement must have the following " \
414
+ "required keys: #{required_keys.join(', ')}." \
415
+ "Optionally, it may have the following keys: " \
416
+ "#{optional_keys.join(', ')}."
406
417
  end
407
418
 
408
419
  return if requirement_fields.flatten.none? { |r| r[:requirement] == "" }
@@ -60,8 +60,10 @@ module Dependabot
60
60
  end
61
61
 
62
62
  # See https://github.com/git/git/blob/a36e024e989f4d35f35987a60e3af8022cac3420/object.h#L144-L153
63
- VALID_MODES = T.let([Mode::FILE, Mode::EXECUTABLE, Mode::TREE, Mode::SUBMODULE, Mode::SYMLINK].freeze,
64
- T::Array[String])
63
+ VALID_MODES = T.let(
64
+ [Mode::FILE, Mode::EXECUTABLE, Mode::TREE, Mode::SUBMODULE, Mode::SYMLINK].freeze,
65
+ T::Array[String]
66
+ )
65
67
 
66
68
  sig do
67
69
  params(
@@ -79,10 +81,19 @@ module Dependabot
79
81
  )
80
82
  .void
81
83
  end
82
- def initialize(name:, content:, directory: "/", type: "file",
83
- support_file: false, vendored_file: false, symlink_target: nil,
84
- content_encoding: ContentEncoding::UTF_8, deleted: false,
85
- operation: Operation::UPDATE, mode: nil)
84
+ def initialize(
85
+ name:,
86
+ content:,
87
+ directory: "/",
88
+ type: "file",
89
+ support_file: false,
90
+ vendored_file: false,
91
+ symlink_target: nil,
92
+ content_encoding: ContentEncoding::UTF_8,
93
+ deleted: false,
94
+ operation: Operation::UPDATE,
95
+ mode: nil
96
+ )
86
97
  @name = name
87
98
  @content = content
88
99
  @directory = T.let(clean_directory(directory), String)
@@ -0,0 +1,54 @@
1
+ # Dependency Graphers
2
+
3
+ Dependency graphers are used to convert a set of parsed dependencies into a data structure we can use to output the dependency graph of a project in a generic data structure based on GitHub's [Dependency submission API](https://docs.github.com/en/rest/dependency-graph/dependency-submission).
4
+
5
+ We will expect each language Dependabot supports to implement a `Dependabot::DependencyGraphers` class in future, but for now any modules that do not implement a specific class fail over to a 'best effort' generic implementation that works in most cases.
6
+
7
+ ## Public API
8
+
9
+ Each `Dependabot::DependencyGraphers` class implements the following methods:
10
+
11
+ | Method | Description |
12
+ |-----------------------------|-----------------------------------------------------------------------------------------------|
13
+ | `.relevant_dependency_file` | Checks the list of `Dependabot::DependencyFile` objects assigned and determines which one the dependency list should be reported against. In most languages this will be the lockfile, if present, and the manifest otherwise. |
14
+ | `.resolved_dependencies` | Processes the assigned `Dependabot::Dependency` objects into an informational hash |
15
+
16
+ An example of a `.resolved_dependencies` hash for a Bundler project:
17
+
18
+ ```ruby
19
+ "addressable": {
20
+ "package_url": "pkg:gem/addressable@2.8.6",
21
+ "relationship": "indirect",
22
+ "scope": "runtime",
23
+ "dependencies": [],
24
+ "metadata": {}
25
+ },
26
+ "ast": {
27
+ "package_url": "pkg:gem/ast@2.4.2",
28
+ "relationship": "indirect",
29
+ "scope": "runtime",
30
+ "dependencies": [],
31
+ "metadata": {}
32
+ },
33
+ "aws-eventstream": {
34
+ "package_url": "pkg:gem/aws-eventstream@1.3.0",
35
+ "relationship": "indirect",
36
+ "scope": "runtime",
37
+ "dependencies": [],
38
+ "metadata": {}
39
+ }
40
+ ```
41
+
42
+ ## Writing a file fetcher for a new language
43
+
44
+ All new file fetchers should inherit from `Dependabot::DependencyGraphers::Base` and
45
+ implement the following methods:
46
+
47
+ | Method | Description |
48
+ |----------------------------------|-----------------------------------------------------------------------------------------------|
49
+ | `.relevant_dependency_file` | See Public API section. |
50
+ | `.fetch_subdependencies` | Private method to fetch a list of package names, or PURLs, that are subdependencies of a given `Dependabot::Dependency`. It is expected that some languages will need to perform additional native commands to obtain this data. |
51
+ | `.purl_pkg_for` | Private method to map the given `Dependabot::Dependency` to the correct [Package-URL type](https://github.com/package-url/purl-spec/blob/main/PURL-TYPES.rst) for the package manager involved. |
52
+
53
+ > [!WARNING]
54
+ > While PURLs are preferred in all languages for `.fetch_subdependencies`, for languages where multiple versions of a single dependency are permitted they _must_ be provided to be precise.