Class: Dependabot::Dependency

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

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.



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/dependabot/dependency.rb', line 108

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| symbolize_keys(req) }, T::Array[T::Hash[Symbol, T.untyped]])
  @previous_version = previous_version
  @previous_version = nil if @previous_version == ""
  @previous_requirements = T.let(
    previous_requirements&.map { |req| symbolize_keys(req) },
    T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
  )
  @package_manager = package_manager
  @directory = directory
  unless top_level? ||  == []
    @subdependency_metadata = T.let(
      &.map { |h| symbolize_keys(h) },
      T.nilable(T::Array[T::Hash[Symbol, T.untyped]])
    )
  end
  @removed = removed
  @metadata = T.let(symbolize_keys( || {}), T::Hash[Symbol, T.untyped])

  check_values
end

Instance Attribute Details

#directoryObject

Returns the value of attribute directory.



83
84
85
# File 'lib/dependabot/dependency.rb', line 83

def directory
  @directory
end

#metadataObject (readonly)

Returns the value of attribute metadata.



89
90
91
# File 'lib/dependabot/dependency.rb', line 89

def 
  @metadata
end

#nameObject (readonly)

Returns the value of attribute name.



65
66
67
# File 'lib/dependabot/dependency.rb', line 65

def name
  @name
end

#package_managerObject (readonly)

Returns the value of attribute package_manager.



74
75
76
# File 'lib/dependabot/dependency.rb', line 74

def package_manager
  @package_manager
end

#previous_requirementsObject (readonly)

Returns the value of attribute previous_requirements.



80
81
82
# File 'lib/dependabot/dependency.rb', line 80

def previous_requirements
  @previous_requirements
end

#previous_versionObject (readonly)

Returns the value of attribute previous_version.



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

def previous_version
  @previous_version
end

#requirementsObject (readonly)

Returns the value of attribute requirements.



71
72
73
# File 'lib/dependabot/dependency.rb', line 71

def requirements
  @requirements
end

#subdependency_metadataObject (readonly)

Returns the value of attribute subdependency_metadata.



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

def 
  @subdependency_metadata
end

#versionObject (readonly)

Returns the value of attribute version.



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

def version
  @version
end

Class Method Details

.display_name_builder_for_package_manager(package_manager) ⇒ Object



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

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

.name_normaliser_for_package_manager(package_manager) ⇒ Object



50
51
52
# File 'lib/dependabot/dependency.rb', line 50

def self.name_normaliser_for_package_manager(package_manager)
  @name_normalisers[package_manager] || ->(name) { name }
end

.production_check_for_package_manager(package_manager) ⇒ Object



21
22
23
24
25
26
# File 'lib/dependabot/dependency.rb', line 21

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



45
46
47
# File 'lib/dependabot/dependency.rb', line 45

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

.register_name_normaliser(package_manager, name_builder) ⇒ Object



60
61
62
# File 'lib/dependabot/dependency.rb', line 60

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

.register_production_check(package_manager, production_check) ⇒ Object



35
36
37
# File 'lib/dependabot/dependency.rb', line 35

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

Instance Method Details

#==(other) ⇒ Object



293
294
295
296
297
298
299
300
# File 'lib/dependabot/dependency.rb', line 293

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

#all_sourcesObject



355
356
357
358
359
360
361
362
363
# File 'lib/dependabot/dependency.rb', line 355

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

#all_versionsObject



277
278
279
280
281
282
# File 'lib/dependabot/dependency.rb', line 277

def all_versions
  all_versions = [:all_versions]
  return [version].compact unless all_versions

  all_versions.filter_map(&:version)
end

#appears_in_lockfile?Boolean

Returns:

  • (Boolean)


176
177
178
# File 'lib/dependabot/dependency.rb', line 176

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

#display_nameObject



197
198
199
200
201
202
203
# File 'lib/dependabot/dependency.rb', line 197

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



245
246
247
248
249
# File 'lib/dependabot/dependency.rb', line 245

def docker_digest_from_reqs(requirements)
  requirements
    .filter_map { |r| r.dig(:source, "digest") || r.dig(:source, :digest) }
    .first
end

#eql?(other) ⇒ Boolean

Returns:

  • (Boolean)


308
309
310
# File 'lib/dependabot/dependency.rb', line 308

def eql?(other)
  self == other
end

#hashObject



303
304
305
# File 'lib/dependabot/dependency.rb', line 303

def hash
  to_h.hash
end

#humanized_previous_versionObject



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
# File 'lib/dependabot/dependency.rb', line 206

def humanized_previous_version
  # If we don't have a previous version, we *may* still be able to figure
  # one out if a ref was provided and has been changed (in which case the
  # previous ref was essentially the version).
  if previous_version.nil?
    return ref_changed? ? previous_ref : nil
  end

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

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

#humanized_versionObject



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/dependabot/dependency.rb', line 228

def humanized_version
  return "removed" if removed?

  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)


288
289
290
# File 'lib/dependabot/dependency.rb', line 288

def informational_only?
  [:information_only]
end

#new_refObject



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

def new_ref
  new_refs = requirements.filter_map do |r|
    r.dig(:source, "ref") || r.dig(:source, :ref)
  end.uniq
  new_refs.first if new_refs.count == 1
end

#numeric_versionObject



154
155
156
157
158
# File 'lib/dependabot/dependency.rb', line 154

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



252
253
254
255
256
257
258
259
# File 'lib/dependabot/dependency.rb', line 252

def previous_ref
  return nil if previous_requirements.nil?

  previous_refs = T.must(previous_requirements).filter_map do |r|
    r.dig(:source, "ref") || r.dig(:source, :ref)
  end.uniq
  previous_refs.first if previous_refs.count == 1
end

#production?Boolean

Returns:

  • (Boolean)


181
182
183
184
185
186
187
188
189
# File 'lib/dependabot/dependency.rb', line 181

def production?
  return subdependency_production_check unless top_level?

  groups = requirements.flat_map { |r| r.fetch(:groups).map(&:to_s) }

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

#ref_changed?Boolean

Returns:

  • (Boolean)


270
271
272
# File 'lib/dependabot/dependency.rb', line 270

def ref_changed?
  previous_ref != new_ref
end

#removed?Boolean

Returns:

  • (Boolean)


149
150
151
# File 'lib/dependabot/dependency.rb', line 149

def removed?
  @removed
end

#requirement_classObject



318
319
320
# File 'lib/dependabot/dependency.rb', line 318

def requirement_class
  Utils.requirement_class_for_package_manager(package_manager)
end

#requirements_changed?Boolean

Returns:

  • (Boolean)


366
367
368
# File 'lib/dependabot/dependency.rb', line 366

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

#source_details(allowed_types: nil) ⇒ Object



333
334
335
336
337
338
339
340
341
342
343
344
# File 'lib/dependabot/dependency.rb', line 333

def source_details(allowed_types: nil)
  sources = all_sources.uniq.compact
  sources.select! { |source| allowed_types.include?(source[:type].to_s) } if allowed_types

  git = allowed_types == ["git"]

  if (git && sources.map { |s| s[:url] }.uniq.count > 1) || (!git && sources.count > 1)
    raise "Multiple sources! #{sources.join(', ')}"
  end

  sources.first
end

#source_typeObject



347
348
349
350
351
352
# File 'lib/dependabot/dependency.rb', line 347

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

  details[:type] || details.fetch("type")
end

#specific_requirementsObject



313
314
315
# File 'lib/dependabot/dependency.rb', line 313

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

#subdependency_production_checkObject



192
193
194
# File 'lib/dependabot/dependency.rb', line 192

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

#to_hObject



161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/dependabot/dependency.rb', line 161

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? ? true : nil
  }.compact
end

#top_level?Boolean

Returns:

  • (Boolean)


144
145
146
# File 'lib/dependabot/dependency.rb', line 144

def top_level?
  requirements.any?
end

#version_classObject



323
324
325
# File 'lib/dependabot/dependency.rb', line 323

def version_class
  Utils.version_class_for_package_manager(package_manager)
end