dependabot-common 0.388.0 → 0.389.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29f29c96dbb5e187d5cdecfe015ecd60456ea004a7553a97b812416034451ebf
4
- data.tar.gz: 1d6e5d04baaf18853476f074e742eb8a60113e2fdfa457db4b3019b1055b30ea
3
+ metadata.gz: b9781413c952e486c9417d63fc70301e7ba10d4283555831df79a6e9b5f2067d
4
+ data.tar.gz: f54e1d3bda0a1126fefa4246c4a7f0f30951bf5995711b4b376fdd152a81352b
5
5
  SHA512:
6
- metadata.gz: 2c2d09853e0044b7dd6ed6ca9f56501ee8436f113eecec3d85506d1543b79994cb3544cb5718b6f55960f7257af74848e33bc330d956275f98a2d8220f09d4d6
7
- data.tar.gz: 343ab8ddca784ef0e497987de868f0b405aeeb3bfb8f11c92ad24da3b6d067981fde09397e4d6a5633e2556bfa527f594f432dc4ca9aa79cd9b2b556be930e52
6
+ metadata.gz: 48591da2ac8712a8f2db6f9a8cd8c7c5debe954fa1470d7e6a625f18d5249e668cf5d48a338813c4c9ffe080d43628bf168d1dc81e463fa8753fc4edb819568e
7
+ data.tar.gz: 276ee23ea7c643fb0daac14664c83dea4c4fd4070bda5d616278d94eb01cad4722bd32d022667e5f9affe802dcb986c1131dbcb4c5a5eebef359854f0b83d136
@@ -1,4 +1,4 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
@@ -9,9 +9,17 @@ module Dependabot
9
9
  class Dependency
10
10
  extend T::Sig
11
11
 
12
+ Metadata = T.type_alias { T::Hash[Symbol, Object] }
13
+ ProductionCheck = T.type_alias do
14
+ T.proc.params(groups: T::Array[String]).returns(T::Boolean)
15
+ end
16
+ RequirementInput = T.type_alias { DependencyRequirement::Input }
17
+ ObjectHash = T.type_alias { DependencyRequirement::ObjectHash }
18
+ RequirementSource = T.type_alias { DependencyRequirement::Source }
19
+
12
20
  @production_checks = T.let(
13
21
  {},
14
- T::Hash[String, T.proc.params(arg0: T::Array[T.untyped]).returns(T::Boolean)]
22
+ T::Hash[String, ProductionCheck]
15
23
  )
16
24
  @display_name_builders = T.let({}, T::Hash[String, T.proc.params(arg0: String).returns(String)])
17
25
  @name_normalisers = T.let({}, T::Hash[String, T.proc.params(arg0: String).returns(String)])
@@ -19,9 +27,13 @@ module Dependabot
19
27
  {},
20
28
  T::Hash[String, T.proc.params(arg0: Dependency).returns(T.nilable(String))]
21
29
  )
30
+ IDENTITY_NAME_NORMALISER = T.let(
31
+ ->(name) { name },
32
+ T.proc.params(name: String).returns(String)
33
+ )
22
34
 
23
35
  sig do
24
- params(package_manager: String).returns(T.proc.params(arg0: T::Array[T.untyped]).returns(T::Boolean))
36
+ params(package_manager: String).returns(ProductionCheck)
25
37
  end
26
38
  def self.production_check_for_package_manager(package_manager)
27
39
  production_check = @production_checks[package_manager]
@@ -33,9 +45,9 @@ module Dependabot
33
45
  sig do
34
46
  params(
35
47
  package_manager: String,
36
- production_check: T.proc.params(arg0: T::Array[T.untyped]).returns(T::Boolean)
48
+ production_check: ProductionCheck
37
49
  )
38
- .returns(T.proc.params(arg0: T::Array[T.untyped]).returns(T::Boolean))
50
+ .returns(ProductionCheck)
39
51
  end
40
52
  def self.register_production_check(package_manager, production_check)
41
53
  @production_checks[package_manager] = production_check
@@ -53,7 +65,7 @@ module Dependabot
53
65
 
54
66
  sig { params(package_manager: String).returns(T.nilable(T.proc.params(arg0: String).returns(String))) }
55
67
  def self.name_normaliser_for_package_manager(package_manager)
56
- @name_normalisers[package_manager] || ->(name) { name }
68
+ @name_normalisers[package_manager] || IDENTITY_NAME_NORMALISER
57
69
  end
58
70
 
59
71
  sig do
@@ -106,10 +118,10 @@ module Dependabot
106
118
  sig { returns(T.nilable(String)) }
107
119
  attr_accessor :directory
108
120
 
109
- sig { returns(T.nilable(T::Array[T::Hash[Symbol, T.untyped]])) }
121
+ sig { returns(T.nilable(T::Array[Metadata])) }
110
122
  attr_reader :subdependency_metadata
111
123
 
112
- sig { returns(T::Hash[Symbol, T.untyped]) }
124
+ sig { returns(Metadata) }
113
125
  attr_reader :metadata
114
126
 
115
127
  # Attribution metadata for group membership tracking
@@ -129,16 +141,16 @@ module Dependabot
129
141
  sig do
130
142
  params(
131
143
  name: String,
132
- requirements: T::Array[T::Hash[T.any(Symbol, String), T.untyped]],
144
+ requirements: T::Array[RequirementInput],
133
145
  package_manager: String,
134
146
  # TODO: Make version a Dependabot::Version everywhere
135
147
  version: T.nilable(T.any(String, Dependabot::Version)),
136
148
  previous_version: T.nilable(String),
137
- previous_requirements: T.nilable(T::Array[T::Hash[T.any(Symbol, String), T.untyped]]),
149
+ previous_requirements: T.nilable(T::Array[RequirementInput]),
138
150
  directory: T.nilable(String),
139
- subdependency_metadata: T.nilable(T::Array[T::Hash[T.any(Symbol, String), String]]),
151
+ subdependency_metadata: T.nilable(T::Array[ObjectHash]),
140
152
  removed: T::Boolean,
141
- metadata: T.nilable(T::Hash[T.any(Symbol, String), String])
153
+ metadata: T.nilable(ObjectHash)
142
154
  ).void
143
155
  end
144
156
  def initialize(
@@ -174,14 +186,16 @@ module Dependabot
174
186
  )
175
187
  @package_manager = package_manager
176
188
  @directory = directory
189
+ @subdependency_metadata = T.let(nil, T.nilable(T::Array[Metadata]))
177
190
  unless top_level? || subdependency_metadata == []
178
191
  @subdependency_metadata = T.let(
179
192
  subdependency_metadata&.map { |h| symbolize_keys(h) },
180
- T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
193
+ T.nilable(T::Array[Metadata])
181
194
  )
182
195
  end
183
196
  @removed = removed
184
- @metadata = T.let(symbolize_keys(metadata || {}), T::Hash[Symbol, T.untyped])
197
+ @metadata = T.let(symbolize_keys(metadata || {}), Metadata)
198
+ @numeric_version = T.let(nil, T.nilable(Dependabot::Version))
185
199
  check_values
186
200
  end
187
201
  # rubocop:enable Metrics/PerceivedComplexity
@@ -203,7 +217,7 @@ module Dependabot
203
217
  @numeric_version ||= T.let(version_class.new(T.must(version)), T.nilable(Dependabot::Version))
204
218
  end
205
219
 
206
- sig { returns(T::Hash[String, T.untyped]) }
220
+ sig { returns(T::Hash[String, Object]) }
207
221
  def to_h
208
222
  {
209
223
  "name" => name,
@@ -227,7 +241,12 @@ module Dependabot
227
241
  def production?
228
242
  return subdependency_production_check unless top_level?
229
243
 
230
- groups = requirements.flat_map { |r| r.fetch(:groups).map(&:to_s) }
244
+ groups = requirements.flat_map do |requirement|
245
+ requirement_groups = requirement.groups
246
+ raise TypeError, "groups must be an array of strings or symbols" unless requirement_groups
247
+
248
+ requirement_groups.map(&:to_s)
249
+ end
231
250
 
232
251
  self.class
233
252
  .production_check_for_package_manager(package_manager)
@@ -277,7 +296,10 @@ module Dependabot
277
296
  sig { params(requirements: T::Array[Dependabot::DependencyRequirement]).returns(T.nilable(String)) }
278
297
  def docker_digest_from_reqs(requirements)
279
298
  requirements
280
- .filter_map { |r| r.dig(:source, "digest") || r.dig(:source, :digest) }
299
+ .filter_map do |requirement|
300
+ source = requirement.source
301
+ optional_source_string(source, "digest") if source.is_a?(Hash)
302
+ end
281
303
  .first
282
304
  end
283
305
 
@@ -286,7 +308,8 @@ module Dependabot
286
308
  return nil if previous_requirements.nil?
287
309
 
288
310
  previous_refs = T.must(previous_requirements).filter_map do |r|
289
- r.dig(:source, "ref") || r.dig(:source, :ref)
311
+ source = r.source
312
+ optional_source_string(source, "ref") if source.is_a?(Hash)
290
313
  end.uniq
291
314
  previous_refs.first if previous_refs.one?
292
315
  end
@@ -294,7 +317,8 @@ module Dependabot
294
317
  sig { returns(T.nilable(String)) }
295
318
  def new_ref
296
319
  new_refs = requirements.filter_map do |r|
297
- r.dig(:source, "ref") || r.dig(:source, :ref)
320
+ source = r.source
321
+ optional_source_string(source, "ref") if source.is_a?(Hash)
298
322
  end.uniq
299
323
  new_refs.first if new_refs.one?
300
324
  end
@@ -308,10 +332,10 @@ module Dependabot
308
332
  # support this feature will return more than the current version.
309
333
  sig { returns(T::Array[T.nilable(String)]) }
310
334
  def all_versions
311
- all_versions = metadata[:all_versions]
312
- return [version].compact unless all_versions
335
+ versions = metadata_dependencies(:all_versions)
336
+ return [version].compact unless versions
313
337
 
314
- all_versions.filter_map(&:version)
338
+ versions.filter_map(&:version)
315
339
  end
316
340
 
317
341
  # This dependency is being indirectly updated by an update to another
@@ -319,10 +343,63 @@ module Dependabot
319
343
  # surface it to the user in the PR.
320
344
  sig { returns(T.nilable(T::Boolean)) }
321
345
  def informational_only?
322
- metadata[:information_only]
346
+ metadata_boolean(:information_only)
347
+ end
348
+
349
+ sig { params(key: Symbol).returns(T.nilable(String)) }
350
+ def metadata_string(key)
351
+ value = metadata[key]
352
+ return if value.nil?
353
+ return value if value.is_a?(String)
354
+
355
+ raise TypeError, "#{key} metadata must be a string or nil"
323
356
  end
324
357
 
325
- sig { params(other: T.anything).returns(T::Boolean) }
358
+ sig { params(key: Symbol).returns(T.nilable(T::Array[String])) }
359
+ def metadata_string_array(key)
360
+ value = metadata[key]
361
+ return if value.nil?
362
+ raise TypeError, "#{key} metadata must be an array of strings or nil" unless value.is_a?(Array)
363
+
364
+ value.map do |raw_entry|
365
+ entry = T.cast(raw_entry, Object)
366
+ raise TypeError, "#{key} metadata must be an array of strings or nil" unless entry.is_a?(String)
367
+
368
+ entry
369
+ end
370
+ end
371
+
372
+ sig { params(key: Symbol).returns(T.nilable(T::Array[Dependency])) }
373
+ def metadata_dependencies(key)
374
+ value = metadata_array(key)
375
+ return unless value
376
+
377
+ value.map do |raw_dependency|
378
+ raise TypeError, "#{key} metadata must be an array of dependencies" unless raw_dependency.is_a?(Dependency)
379
+
380
+ raw_dependency
381
+ end
382
+ end
383
+
384
+ sig { params(key: Symbol).returns(T.nilable(T::Array[Object])) }
385
+ def metadata_array(key)
386
+ value = metadata[key]
387
+ return if value.nil?
388
+ raise TypeError, "#{key} metadata must be an array" unless value.is_a?(Array)
389
+
390
+ value.map { |entry| T.cast(entry, Object) }
391
+ end
392
+
393
+ sig { params(key: Symbol).returns(T.nilable(T::Boolean)) }
394
+ def metadata_boolean(key)
395
+ value = metadata[key]
396
+ return if value.nil?
397
+ return value if value == true || value == false
398
+
399
+ raise TypeError, "#{key} metadata must be a boolean or nil"
400
+ end
401
+
402
+ sig { params(other: Object).returns(T::Boolean) }
326
403
  def ==(other)
327
404
  case other
328
405
  when Dependency
@@ -337,7 +414,7 @@ module Dependabot
337
414
  to_h.hash
338
415
  end
339
416
 
340
- sig { params(other: T.anything).returns(T::Boolean) }
417
+ sig { params(other: Object).returns(T::Boolean) }
341
418
  def eql?(other)
342
419
  self == other
343
420
  end
@@ -361,19 +438,27 @@ module Dependabot
361
438
  params(
362
439
  allowed_types: T.nilable(T::Array[String])
363
440
  )
364
- .returns(T.nilable(T::Hash[T.any(String, Symbol), T.untyped]))
441
+ .returns(T.nilable(ObjectHash))
365
442
  end
366
443
  def source_details(allowed_types: nil)
367
444
  sources = all_sources.uniq.compact
368
- sources.select! { |source| allowed_types.include?(source[:type].to_s) } if allowed_types
445
+ source_hashes = sources.map do |source|
446
+ raise TypeError, "source details must be a hash with string or symbol keys" unless source.is_a?(Hash)
447
+
448
+ source
449
+ end
450
+ if allowed_types
451
+ source_hashes.select! { |source| allowed_types.include?(optional_source_string(source, "type").to_s) }
452
+ end
369
453
 
370
454
  git = allowed_types == ["git"]
371
455
 
372
- if (git && sources.map { |s| s[:url] }.uniq.count > 1) || (!git && sources.count > 1)
373
- raise "Multiple sources! #{sources.join(', ')}"
456
+ if (git && source_hashes.map { |source| optional_source_string(source, "url") }.uniq.count > 1) ||
457
+ (!git && source_hashes.count > 1)
458
+ raise "Multiple sources! #{source_hashes.join(', ')}"
374
459
  end
375
460
 
376
- sources.first
461
+ source_hashes.first
377
462
  end
378
463
 
379
464
  sig { returns(T.nilable(String)) }
@@ -381,15 +466,26 @@ module Dependabot
381
466
  details = source_details
382
467
  return "default" if details.nil?
383
468
 
384
- details[:type] || details.fetch("type")
469
+ required_source_string(details, "type")
385
470
  end
386
471
 
387
- sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
472
+ sig do
473
+ params(
474
+ key: String,
475
+ allowed_types: T.nilable(T::Array[String])
476
+ ).returns(T.nilable(String))
477
+ end
478
+ def source_string(key, allowed_types: nil)
479
+ details = source_details(allowed_types: allowed_types)
480
+ optional_source_string(details, key) if details
481
+ end
482
+
483
+ sig { returns(T::Array[T.nilable(RequirementSource)]) }
388
484
  def all_sources
389
485
  if top_level?
390
- requirements.map { |requirement| requirement.fetch(:source) }
486
+ requirements.map(&:source)
391
487
  elsif subdependency_metadata
392
- T.must(subdependency_metadata).filter_map { |data| data[:source] }
488
+ T.must(subdependency_metadata).filter_map { |data| source_from_metadata(data) }
393
489
  else
394
490
  []
395
491
  end
@@ -461,7 +557,7 @@ module Dependabot
461
557
  "#{optional_keys.join(', ')}."
462
558
  end
463
559
 
464
- return if requirement_fields.flatten.none? { |r| r[:requirement] == "" }
560
+ return if requirement_fields.flatten.none? { |r| r.requirement == "" }
465
561
 
466
562
  raise ArgumentError, "blank strings must not be provided as requirements"
467
563
  end
@@ -476,9 +572,44 @@ module Dependabot
476
572
  end
477
573
  end
478
574
 
479
- sig { params(hash: T::Hash[T.any(Symbol, String), T.untyped]).returns(T::Hash[Symbol, T.untyped]) }
575
+ sig { params(hash: ObjectHash).returns(Metadata) }
480
576
  def symbolize_keys(hash)
481
577
  hash.keys.to_h { |k| [k.to_sym, hash[k]] }
482
578
  end
579
+
580
+ sig { params(metadata: Metadata).returns(T.nilable(RequirementSource)) }
581
+ def source_from_metadata(metadata)
582
+ raw_source = metadata[:source]
583
+ return if raw_source.nil?
584
+ return raw_source if raw_source.is_a?(String)
585
+ unless raw_source.is_a?(Hash)
586
+ raise TypeError, "source must be a string or hash with string or symbol keys, or nil"
587
+ end
588
+
589
+ raw_source.each_key do |raw_key|
590
+ key = T.cast(raw_key, Object)
591
+ next if key.is_a?(String) || key.is_a?(Symbol)
592
+
593
+ raise TypeError, "source must be a string or hash with string or symbol keys, or nil"
594
+ end
595
+ raw_source
596
+ end
597
+
598
+ sig { params(source: ObjectHash, key: String).returns(T.nilable(String)) }
599
+ def optional_source_string(source, key)
600
+ value = source[key.to_sym] || source[key]
601
+ return if value.nil?
602
+ return value if value.is_a?(String)
603
+
604
+ raise TypeError, "source #{key} must be a string or nil"
605
+ end
606
+
607
+ sig { params(source: ObjectHash, key: String).returns(String) }
608
+ def required_source_string(source, key)
609
+ raw_value = source.key?(key.to_sym) ? source[key.to_sym] : source.fetch(key)
610
+ return raw_value if raw_value.is_a?(String)
611
+
612
+ raise TypeError, "source #{key} must be a string"
613
+ end
483
614
  end
484
615
  end
@@ -1,4 +1,4 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
@@ -32,7 +32,7 @@ module Dependabot
32
32
  # metadata, but in most cases this will be empty.
33
33
  sig { override.params(dependency: Dependabot::Dependency).returns(T::Array[String]) }
34
34
  def fetch_subdependencies(dependency)
35
- dependency.metadata.fetch(:depends_on, [])
35
+ dependency.metadata_string_array(:depends_on) || []
36
36
  end
37
37
 
38
38
  # TODO: Delegate this to ecosystem-specific base classes
@@ -36,6 +36,7 @@ module Dependabot
36
36
  Group = T.type_alias { T.any(String, Symbol) }
37
37
  ObjectHash = T.type_alias { T::Hash[T.any(Symbol, String), Object] }
38
38
  Requirement = T.type_alias { T.any(String, Symbol) }
39
+ Source = T.type_alias { T.any(String, ObjectHash) }
39
40
  Input = T.type_alias { T.any(DependencyRequirement, ObjectHash) }
40
41
 
41
42
  K = type_member { { fixed: Symbol } }
@@ -98,9 +99,13 @@ module Dependabot
98
99
  # { type: "git", url: "https://github.com/..." }. Keys may be symbols
99
100
  # or strings depending on whether the requirement was built by a file
100
101
  # parser or deserialised from a job definition.
101
- sig { returns(T.nilable(ObjectHash)) }
102
+ sig { returns(T.nilable(Source)) }
102
103
  def source
103
- optional_object_hash(:source)
104
+ value = T.cast(self[:source], T.nilable(Object))
105
+ return if value.nil?
106
+ return value if value.is_a?(String)
107
+
108
+ object_hash(value, :source)
104
109
  end
105
110
 
106
111
  # Optional ecosystem-specific metadata about the requirement, e.g.
@@ -125,15 +130,29 @@ module Dependabot
125
130
  def optional_object_hash(key)
126
131
  value = T.cast(self[key], T.nilable(Object))
127
132
  return if value.nil?
128
- raise TypeError, "#{key} must be a hash with string or symbol keys, or nil" unless value.is_a?(Hash)
133
+
134
+ object_hash(value, key)
135
+ end
136
+
137
+ sig { params(value: Object, key: Symbol).returns(ObjectHash) }
138
+ def object_hash(value, key)
139
+ message = object_hash_message(key)
140
+ raise TypeError, "#{key} must be #{message}" unless value.is_a?(Hash)
129
141
 
130
142
  value.each_key do |raw_nested_key|
131
143
  nested_key = T.cast(raw_nested_key, Object)
132
144
  next if nested_key.is_a?(String) || nested_key.is_a?(Symbol)
133
145
 
134
- raise TypeError, "#{key} must be a hash with string or symbol keys, or nil"
146
+ raise TypeError, "#{key} must be #{message}"
135
147
  end
136
148
  value
137
149
  end
150
+
151
+ sig { params(key: Symbol).returns(String) }
152
+ def object_hash_message(key)
153
+ return "a string or hash with string or symbol keys, or nil" if key == :source
154
+
155
+ "a hash with string or symbol keys, or nil"
156
+ end
138
157
  end
139
158
  end
@@ -398,7 +398,7 @@ module Dependabot
398
398
  sig { params(requirement: Dependabot::DependencyRequirement).returns(T.nilable(String)) }
399
399
  def requirement_ref(requirement)
400
400
  source = requirement.source
401
- return unless source
401
+ return unless source.is_a?(Hash)
402
402
 
403
403
  symbol_ref = source[:ref]
404
404
  return symbol_ref if symbol_ref.is_a?(String)
@@ -279,7 +279,7 @@ module Dependabot
279
279
  sig { returns(String) }
280
280
  def dependency_name_group_pr_name
281
281
  dep = T.must(dependencies.first)
282
- directories = dep.metadata[:updated_directories] || [dep.metadata[:directory]].compact
282
+ directories = dep.metadata_string_array(:updated_directories) || [dep.metadata_string(:directory)].compact
283
283
 
284
284
  if directories.count > 1
285
285
  "bump #{dep.name} across #{directories.count} directories"
@@ -571,7 +571,7 @@ module Dependabot
571
571
  sig { returns(String) }
572
572
  def dependency_name_group_intro
573
573
  dep = T.must(dependencies.first)
574
- directories = dep.metadata[:updated_directories] || [dep.metadata[:directory]].compact
574
+ directories = dep.metadata_string_array(:updated_directories) || [dep.metadata_string(:directory)].compact
575
575
 
576
576
  msg = "Bumps #{dependency_links.first}"
577
577
 
@@ -801,6 +801,9 @@ module Dependabot
801
801
  vulnerabilities_fixed: vulnerabilities_fixed[dependency.name],
802
802
  github_redirection_service: github_redirection_service
803
803
  ).to_s
804
+ rescue StandardError => e
805
+ suppress_error("metadata cascades for #{dependency.name}", e)
806
+ ""
804
807
  end
805
808
 
806
809
  sig { returns(String) }
data/lib/dependabot.rb CHANGED
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module Dependabot
5
- VERSION = "0.388.0"
5
+ VERSION = "0.389.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-common
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.388.0
4
+ version: 0.389.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -77,14 +77,14 @@ dependencies:
77
77
  requirements:
78
78
  - - "~>"
79
79
  - !ruby/object:Gem::Version
80
- version: '1.18'
80
+ version: '1.19'
81
81
  type: :runtime
82
82
  prerelease: false
83
83
  version_requirements: !ruby/object:Gem::Requirement
84
84
  requirements:
85
85
  - - "~>"
86
86
  - !ruby/object:Gem::Version
87
- version: '1.18'
87
+ version: '1.19'
88
88
  - !ruby/object:Gem::Dependency
89
89
  name: excon
90
90
  requirement: !ruby/object:Gem::Requirement
@@ -625,7 +625,7 @@ licenses:
625
625
  - MIT
626
626
  metadata:
627
627
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
628
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.388.0
628
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.389.0
629
629
  rdoc_options: []
630
630
  require_paths:
631
631
  - lib