Class: Dependabot::Dependency

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Defined in:
lib/dependabot/dependency.rb

Constant Summary collapse

Metadata =
T.type_alias { T::Hash[Symbol, Object] }
ProductionCheck =
T.type_alias do
  T.proc.params(groups: T::Array[String]).returns(T::Boolean)
end
RequirementInput =
T.type_alias { DependencyRequirement::Input }
ObjectHash =
T.type_alias { DependencyRequirement::ObjectHash }
RequirementSource =
T.type_alias { DependencyRequirement::Source }
IDENTITY_NAME_NORMALISER =
T.let(
  ->(name) { name },
  T.proc.params(name: String).returns(String)
)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name:, requirements:, package_manager:, version: nil, previous_version: nil, previous_requirements: nil, directory: nil, subdependency_metadata: [], removed: false, metadata: {}) ⇒ Dependency

Returns a new instance of Dependency.



156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/dependabot/dependency.rb', line 156

def initialize(
  name:,
  requirements:,
  package_manager:,
  version: nil,
  previous_version: nil,
  previous_requirements: nil,
  directory: nil,
  subdependency_metadata: [],
  removed: false,
  metadata: {}
)
  @name = name
  @version = T.let(
    case version
    when Dependabot::Version then version.to_s
    when String then version
    end,
    T.nilable(String)
  )
  @version = nil if @version == ""
  @requirements = T.let(
    requirements.map { |req| DependencyRequirement.create(req) },
    T::Array[Dependabot::DependencyRequirement]
  )
  @previous_version = previous_version
  @previous_version = nil if @previous_version == ""
  @previous_requirements = T.let(
    previous_requirements&.map { |req| DependencyRequirement.create(req) },
    T.nilable(T::Array[Dependabot::DependencyRequirement])
  )
  @package_manager = package_manager
  @directory = directory
  @subdependency_metadata = T.let(nil, T.nilable(T::Array[Metadata]))
  unless top_level? ||  == []
    @subdependency_metadata = T.let(
      &.map { |h| symbolize_keys(h) },
      T.nilable(T::Array[Metadata])
    )
  end
  @removed = removed
  @metadata = T.let(symbolize_keys( || {}), Metadata)
  @numeric_version = T.let(nil, T.nilable(Dependabot::Version))
  check_values
end

Instance Attribute Details

#attribution_directoryObject

Returns the value of attribute attribution_directory.



135
136
137
# File 'lib/dependabot/dependency.rb', line 135

def attribution_directory
  @attribution_directory
end

#attribution_selection_reasonObject

Returns the value of attribute attribution_selection_reason.



132
133
134
# File 'lib/dependabot/dependency.rb', line 132

def attribution_selection_reason
  @attribution_selection_reason
end

#attribution_source_groupObject

Returns the value of attribute attribution_source_group.



129
130
131
# File 'lib/dependabot/dependency.rb', line 129

def attribution_source_group
  @attribution_source_group
end

#attribution_timestampObject

Returns the value of attribute attribution_timestamp.



138
139
140
# File 'lib/dependabot/dependency.rb', line 138

def attribution_timestamp
  @attribution_timestamp
end

#directoryObject

Returns the value of attribute directory.



119
120
121
# File 'lib/dependabot/dependency.rb', line 119

def directory
  @directory
end

#metadataObject (readonly)

Returns the value of attribute metadata.



125
126
127
# File 'lib/dependabot/dependency.rb', line 125

def 
  @metadata
end

#nameObject (readonly)

Returns the value of attribute name.



101
102
103
# File 'lib/dependabot/dependency.rb', line 101

def name
  @name
end

#package_managerObject (readonly)

Returns the value of attribute package_manager.



110
111
112
# File 'lib/dependabot/dependency.rb', line 110

def package_manager
  @package_manager
end

#previous_requirementsObject (readonly)

Returns the value of attribute previous_requirements.



116
117
118
# File 'lib/dependabot/dependency.rb', line 116

def previous_requirements
  @previous_requirements
end

#previous_versionObject (readonly)

Returns the value of attribute previous_version.



113
114
115
# File 'lib/dependabot/dependency.rb', line 113

def previous_version
  @previous_version
end

#requirementsObject (readonly)

Returns the value of attribute requirements.



107
108
109
# File 'lib/dependabot/dependency.rb', line 107

def requirements
  @requirements
end

#subdependency_metadataObject (readonly)

Returns the value of attribute subdependency_metadata.



122
123
124
# File 'lib/dependabot/dependency.rb', line 122

def 
  @subdependency_metadata
end

#versionObject (readonly)

Returns the value of attribute version.



104
105
106
# File 'lib/dependabot/dependency.rb', line 104

def version
  @version
end

Class Method Details

.display_name_builder_for_package_manager(package_manager) ⇒ Object



57
58
59
# File 'lib/dependabot/dependency.rb', line 57

def self.display_name_builder_for_package_manager(package_manager)
  @display_name_builders[package_manager]
end

.humanized_previous_version_builder_for_package_manager(package_manager) ⇒ Object



86
87
88
# File 'lib/dependabot/dependency.rb', line 86

def self.humanized_previous_version_builder_for_package_manager(package_manager)
  @humanized_previous_version_builders[package_manager]
end

.name_normaliser_for_package_manager(package_manager) ⇒ Object



67
68
69
# File 'lib/dependabot/dependency.rb', line 67

def self.name_normaliser_for_package_manager(package_manager)
  @name_normalisers[package_manager] || IDENTITY_NAME_NORMALISER
end

.production_check_for_package_manager(package_manager) ⇒ Object



38
39
40
41
42
43
# File 'lib/dependabot/dependency.rb', line 38

def self.production_check_for_package_manager(package_manager)
  production_check = @production_checks[package_manager]
  return production_check if production_check

  raise "Unsupported package_manager #{package_manager}"
end

.register_display_name_builder(package_manager, name_builder) ⇒ Object



62
63
64
# File 'lib/dependabot/dependency.rb', line 62

def self.register_display_name_builder(package_manager, name_builder)
  @display_name_builders[package_manager] = name_builder
end

.register_humanized_previous_version_builder(package_manager, builder) ⇒ Object



96
97
98
# File 'lib/dependabot/dependency.rb', line 96

def self.register_humanized_previous_version_builder(package_manager, builder)
  @humanized_previous_version_builders[package_manager] = builder
end

.register_name_normaliser(package_manager, name_builder) ⇒ Object



77
78
79
# File 'lib/dependabot/dependency.rb', line 77

def self.register_name_normaliser(package_manager, name_builder)
  @name_normalisers[package_manager] = name_builder
end

.register_production_check(package_manager, production_check) ⇒ Object



52
53
54
# File 'lib/dependabot/dependency.rb', line 52

def self.register_production_check(package_manager, production_check)
  @production_checks[package_manager] = production_check
end

Instance Method Details

#==(other) ⇒ Object



403
404
405
406
407
408
409
410
# File 'lib/dependabot/dependency.rb', line 403

def ==(other)
  case other
  when Dependency
    to_h == other.to_h
  else
    false
  end
end

#all_sourcesObject



484
485
486
487
488
489
490
491
492
# File 'lib/dependabot/dependency.rb', line 484

def all_sources
  if top_level?
    requirements.map(&:source)
  elsif 
    T.must().filter_map { |data| (data) }
  else
    []
  end
end

#all_versionsObject



334
335
336
337
338
339
# File 'lib/dependabot/dependency.rb', line 334

def all_versions
  versions = (:all_versions)
  return [version].compact unless versions

  versions.filter_map(&:version)
end

#appears_in_lockfile?Boolean

Returns:

  • (Boolean)


236
237
238
# File 'lib/dependabot/dependency.rb', line 236

def appears_in_lockfile?
  !!(previous_version || (version && previous_requirements.nil?))
end

#display_nameObject



262
263
264
265
266
267
268
# File 'lib/dependabot/dependency.rb', line 262

def display_name
  display_name_builder =
    self.class.display_name_builder_for_package_manager(package_manager)
  return name unless display_name_builder

  display_name_builder.call(name)
end

#docker_digest_from_reqs(requirements) ⇒ Object



297
298
299
300
301
302
303
304
# File 'lib/dependabot/dependency.rb', line 297

def docker_digest_from_reqs(requirements)
  requirements
    .filter_map do |requirement|
      source = requirement.source
      optional_source_string(source, "digest") if source.is_a?(Hash)
    end
    .first
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


418
419
420
# File 'lib/dependabot/dependency.rb', line 418

def eql?(other)
  self == other
end

#hashObject



413
414
415
# File 'lib/dependabot/dependency.rb', line 413

def hash
  to_h.hash
end

#humanized_previous_versionObject



271
272
273
274
275
276
# File 'lib/dependabot/dependency.rb', line 271

def humanized_previous_version
  custom_version = custom_humanized_previous_version
  return custom_version if custom_version

  default_humanized_previous_version
end

#humanized_versionObject



279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/dependabot/dependency.rb', line 279

def humanized_version
  return "removed" if removed?
  return nil if version.nil?

  if T.must(version).match?(/^[0-9a-f]{40}/)
    return new_ref if ref_changed? && new_ref

    "`#{T.must(version)[0..6]}`"
  elsif version == previous_version &&
        package_manager == "docker"
    digest = docker_digest_from_reqs(requirements)
    "`#{T.must(T.must(digest).split(':').last)[0..6]}`"
  else
    version
  end
end

#informational_only?Boolean

Returns:

  • (Boolean)


345
346
347
# File 'lib/dependabot/dependency.rb', line 345

def informational_only?
  (:information_only)
end

#metadata_array(key) ⇒ Object

Raises:

  • (TypeError)


385
386
387
388
389
390
391
# File 'lib/dependabot/dependency.rb', line 385

def (key)
  value = [key]
  return if value.nil?
  raise TypeError, "#{key} metadata must be an array" unless value.is_a?(Array)

  value.map { |entry| T.cast(entry, Object) }
end

#metadata_boolean(key) ⇒ Object

Raises:

  • (TypeError)


394
395
396
397
398
399
400
# File 'lib/dependabot/dependency.rb', line 394

def (key)
  value = [key]
  return if value.nil?
  return value if value == true || value == false

  raise TypeError, "#{key} metadata must be a boolean or nil"
end

#metadata_dependencies(key) ⇒ Object



373
374
375
376
377
378
379
380
381
382
# File 'lib/dependabot/dependency.rb', line 373

def (key)
  value = (key)
  return unless value

  value.map do |raw_dependency|
    raise TypeError, "#{key} metadata must be an array of dependencies" unless raw_dependency.is_a?(Dependency)

    raw_dependency
  end
end

#metadata_string(key) ⇒ Object

Raises:

  • (TypeError)


350
351
352
353
354
355
356
# File 'lib/dependabot/dependency.rb', line 350

def (key)
  value = [key]
  return if value.nil?
  return value if value.is_a?(String)

  raise TypeError, "#{key} metadata must be a string or nil"
end

#metadata_string_array(key) ⇒ Object

Raises:

  • (TypeError)


359
360
361
362
363
364
365
366
367
368
369
370
# File 'lib/dependabot/dependency.rb', line 359

def (key)
  value = [key]
  return if value.nil?
  raise TypeError, "#{key} metadata must be an array of strings or nil" unless value.is_a?(Array)

  value.map do |raw_entry|
    entry = T.cast(raw_entry, Object)
    raise TypeError, "#{key} metadata must be an array of strings or nil" unless entry.is_a?(String)

    entry
  end
end

#new_refObject



318
319
320
321
322
323
324
# File 'lib/dependabot/dependency.rb', line 318

def new_ref
  new_refs = requirements.filter_map do |r|
    source = r.source
    optional_source_string(source, "ref") if source.is_a?(Hash)
  end.uniq
  new_refs.first if new_refs.one?
end

#numeric_versionObject



214
215
216
217
218
# File 'lib/dependabot/dependency.rb', line 214

def numeric_version
  return unless version && version_class.correct?(version)

  @numeric_version ||= T.let(version_class.new(T.must(version)), T.nilable(Dependabot::Version))
end

#previous_refObject



307
308
309
310
311
312
313
314
315
# File 'lib/dependabot/dependency.rb', line 307

def previous_ref
  return nil if previous_requirements.nil?

  previous_refs = T.must(previous_requirements).filter_map do |r|
    source = r.source
    optional_source_string(source, "ref") if source.is_a?(Hash)
  end.uniq
  previous_refs.first if previous_refs.one?
end

#production?Boolean

Returns:

  • (Boolean)


241
242
243
244
245
246
247
248
249
250
251
252
253
254
# File 'lib/dependabot/dependency.rb', line 241

def production?
  return subdependency_production_check unless top_level?

  groups = requirements.flat_map do |requirement|
    requirement_groups = requirement.groups
    raise TypeError, "groups must be an array of strings or symbols" unless requirement_groups

    requirement_groups.map(&:to_s)
  end

  self.class
      .production_check_for_package_manager(package_manager)
      .call(groups)
end

#ref_changed?Boolean

Returns:

  • (Boolean)


327
328
329
# File 'lib/dependabot/dependency.rb', line 327

def ref_changed?
  previous_ref != new_ref
end

#removed?Boolean

Returns:

  • (Boolean)


209
210
211
# File 'lib/dependabot/dependency.rb', line 209

def removed?
  @removed
end

#requirement_classObject



428
429
430
# File 'lib/dependabot/dependency.rb', line 428

def requirement_class
  Utils.requirement_class_for_package_manager(package_manager)
end

#requirements_changed?Boolean

Returns:

  • (Boolean)


495
496
497
# File 'lib/dependabot/dependency.rb', line 495

def requirements_changed?
  (requirements - T.must(previous_requirements)).any?
end

#source_details(allowed_types: nil) ⇒ Object



443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
# File 'lib/dependabot/dependency.rb', line 443

def source_details(allowed_types: nil)
  sources = all_sources.uniq.compact
  source_hashes = sources.map do |source|
    raise TypeError, "source details must be a hash with string or symbol keys" unless source.is_a?(Hash)

    source
  end
  if allowed_types
    source_hashes.select! { |source| allowed_types.include?(optional_source_string(source, "type").to_s) }
  end

  git = allowed_types == ["git"]

  if (git && source_hashes.map { |source| optional_source_string(source, "url") }.uniq.count > 1) ||
     (!git && source_hashes.count > 1)
    raise "Multiple sources! #{source_hashes.join(', ')}"
  end

  source_hashes.first
end

#source_string(key, allowed_types: nil) ⇒ Object



478
479
480
481
# File 'lib/dependabot/dependency.rb', line 478

def source_string(key, allowed_types: nil)
  details = source_details(allowed_types: allowed_types)
  optional_source_string(details, key) if details
end

#source_typeObject



465
466
467
468
469
470
# File 'lib/dependabot/dependency.rb', line 465

def source_type
  details = source_details
  return "default" if details.nil?

  required_source_string(details, "type")
end

#specific_requirementsObject



423
424
425
# File 'lib/dependabot/dependency.rb', line 423

def specific_requirements
  requirements.select { |r| requirement_class.new(r.requirement).specific? }
end

#subdependency_production_checkObject



257
258
259
# File 'lib/dependabot/dependency.rb', line 257

def subdependency_production_check
  !&.all? { |h| h[:production] == false }
end

#to_hObject



221
222
223
224
225
226
227
228
229
230
231
232
233
# File 'lib/dependabot/dependency.rb', line 221

def to_h
  {
    "name" => name,
    "version" => version,
    "requirements" => requirements,
    "previous_version" => previous_version,
    "previous_requirements" => previous_requirements,
    "directory" => directory,
    "package_manager" => package_manager,
    "subdependency_metadata" => ,
    "removed" => removed? || nil
  }.compact
end

#top_level?Boolean

Returns:

  • (Boolean)


204
205
206
# File 'lib/dependabot/dependency.rb', line 204

def top_level?
  requirements.any?
end

#version_classObject



433
434
435
# File 'lib/dependabot/dependency.rb', line 433

def version_class
  Utils.version_class_for_package_manager(package_manager)
end