dependabot-common 0.390.0 → 0.392.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/dependabot/clients/azure.rb +1 -1
  3. data/lib/dependabot/command_helpers.rb +11 -3
  4. data/lib/dependabot/config/file_fetcher.rb +2 -2
  5. data/lib/dependabot/config/ignore_condition.rb +1 -1
  6. data/lib/dependabot/config/update_config.rb +1 -1
  7. data/lib/dependabot/dependency_group.rb +16 -0
  8. data/lib/dependabot/dependency_requirement.rb +80 -14
  9. data/lib/dependabot/ecosystem.rb +8 -8
  10. data/lib/dependabot/errors.rb +8 -1
  11. data/lib/dependabot/file_fetchers/base.rb +1 -1
  12. data/lib/dependabot/file_updaters/artifact_updater.rb +1 -1
  13. data/lib/dependabot/file_updaters/base.rb +2 -2
  14. data/lib/dependabot/metadata_finders/base/changelog_finder.rb +4 -7
  15. data/lib/dependabot/metadata_finders/base/changelog_pruner.rb +3 -3
  16. data/lib/dependabot/metadata_finders/base/commits_finder.rb +6 -5
  17. data/lib/dependabot/metadata_finders/base/release_finder.rb +24 -16
  18. data/lib/dependabot/metadata_finders/base.rb +1 -1
  19. data/lib/dependabot/package/package_details.rb +2 -2
  20. data/lib/dependabot/package/package_language.rb +3 -3
  21. data/lib/dependabot/package/package_latest_version_finder.rb +4 -3
  22. data/lib/dependabot/package/package_release.rb +11 -11
  23. data/lib/dependabot/pull_request_creator/branch_name_template.rb +5 -14
  24. data/lib/dependabot/pull_request_creator/branch_namer/solo_strategy.rb +18 -16
  25. data/lib/dependabot/pull_request_creator/labeler.rb +8 -15
  26. data/lib/dependabot/pull_request_creator/message_builder/issue_linker.rb +21 -2
  27. data/lib/dependabot/pull_request_creator/message_builder/link_and_mention_sanitizer.rb +53 -13
  28. data/lib/dependabot/pull_request_creator/message_builder/metadata_presenter.rb +20 -13
  29. data/lib/dependabot/pull_request_creator/message_builder.rb +13 -13
  30. data/lib/dependabot/pull_request_creator/pr_name_prefixer.rb +10 -17
  31. data/lib/dependabot/pull_request_updater/github.rb +1 -1
  32. data/lib/dependabot/shared_helpers.rb +30 -7
  33. data/lib/dependabot/source.rb +1 -4
  34. data/lib/dependabot/update_checkers/base.rb +3 -3
  35. data/lib/dependabot/version.rb +2 -5
  36. data/lib/dependabot/workspace/git.rb +2 -2
  37. data/lib/dependabot.rb +1 -1
  38. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9647e43655c1fb5b645ad6a5635c619fd681f12b926c6c2195492aba565b9401
4
- data.tar.gz: b50b9ac87807039b87a1c2c34fe2620bf332ceb607cd0c1acfb32189e78e3705
3
+ metadata.gz: 6a574e02b5e7a33f7f245c56ae3df5942505a73cee3c1f32b8a07c1b36ba13a2
4
+ data.tar.gz: 4ee0767b57e78681464704b7e41557692d57cf240f40f2577d0313a87f78d371
5
5
  SHA512:
6
- metadata.gz: '0749c51d303699690aa4e89b2f29084d4082a83f1e1f986c023ad4089284a4a1b145729be61d8759f267c8951878a8c36537eb87037c59278f0fbd249daf71bb'
7
- data.tar.gz: 8de0c799f886104e9cd1bedd0fad7ca6e004dec5adb6f939ada8b496d37b41e324a89065542f9603b011d3ef60a9105d397f22e1c24440c029752ce94b52a56d
6
+ metadata.gz: b63a271847067f6adf096dcbbd9e97e0e986defc09125f55afa8be96cb820660c76551982b46d7c613e29ff93093d87bb1c1849d99c6e7bd75fab3f9abcc3a28
7
+ data.tar.gz: 28753fa5c276536d7cb8e16cc7bf183796bdd968e31c0efcb92ded66fd8b07a6e05304d0da3eba70a64fc1bd990f9167a073a072791655bdeb47cfb2f8c01d14
@@ -473,7 +473,7 @@ module Dependabot
473
473
  private
474
474
 
475
475
  sig { params(blk: T.proc.void).void }
476
- def retry_connection_failures(&blk) # rubocop:disable Lint/UnusedMethodArgument
476
+ def retry_connection_failures(&blk)
477
477
  retry_attempt = 0
478
478
 
479
479
  begin
@@ -26,6 +26,7 @@ module Dependabot
26
26
  EnvCmdItem = T.type_alias do
27
27
  T.any(
28
28
  String,
29
+ T::Array[String],
29
30
  T::Hash[T.any(String, Symbol), T.anything]
30
31
  )
31
32
  end
@@ -35,7 +36,7 @@ module Dependabot
35
36
 
36
37
  sig { params(process_status: T.nilable(Process::Status), custom_exitstatus: T.nilable(Integer)).void }
37
38
  def initialize(process_status, custom_exitstatus = nil)
38
- @process_status = T.let(process_status, T.nilable(Process::Status))
39
+ @process_status = process_status
39
40
  @custom_exitstatus = custom_exitstatus
40
41
  end
41
42
 
@@ -109,7 +110,7 @@ module Dependabot
109
110
  else
110
111
  env_cmd
111
112
  end
112
- command_for_log = sanitized_env_cmd.join(" ")
113
+ command_for_log = sanitized_env_cmd.map { |item| item.is_a?(Array) ? item.first : item }.join(" ")
113
114
  Dependabot.logger.public_send(log_level, "Started process PID: #{pid} with command: #{command_for_log}")
114
115
 
115
116
  # Write to stdin if input data is provided
@@ -263,7 +264,14 @@ module Dependabot
263
264
 
264
265
  sig { params(env_cmd: T::Array[EnvCmdItem]).returns(T.nilable(String)) }
265
266
  def self.command_string_for_logging(env_cmd)
266
- T.cast(env_cmd.find { |item| item.is_a?(String) }, T.nilable(String))
267
+ command_parts = env_cmd.filter_map do |item|
268
+ case item
269
+ when Array then item.first
270
+ when String then item
271
+ end
272
+ end
273
+
274
+ command_parts.join(" ") unless command_parts.empty?
267
275
  end
268
276
  private_class_method :command_string_for_logging
269
277
 
@@ -10,11 +10,11 @@ module Dependabot
10
10
  class FileFetcher < FileFetchers::Base
11
11
  extend T::Sig
12
12
 
13
- CONFIG_FILE_PATHS = T.let(%w(.github/dependabot.yml .github/dependabot.yaml).freeze, T::Array[String])
13
+ CONFIG_FILE_PATHS = %w(.github/dependabot.yml .github/dependabot.yaml).freeze
14
14
 
15
15
  sig { override.params(filenames: T::Array[String]).returns(T::Boolean) }
16
16
  def self.required_files_in?(filenames)
17
- CONFIG_FILE_PATHS.any? { |file| filenames.include?(file) }
17
+ CONFIG_FILE_PATHS.intersect?(filenames)
18
18
  end
19
19
 
20
20
  sig { override.returns(String) }
@@ -32,7 +32,7 @@ module Dependabot
32
32
  ).void
33
33
  end
34
34
  def initialize(dependency_name:, versions: nil, update_types: nil)
35
- @dependency_name = T.let(dependency_name, String)
35
+ @dependency_name = dependency_name
36
36
  @versions = T.let(versions || [], T::Array[String])
37
37
  @update_types = T.let(update_types || [], T::Array[String])
38
38
  end
@@ -52,7 +52,7 @@ module Dependabot
52
52
  sig { params(dependency: Dependency).returns(Dependency) }
53
53
  def extract_base_version_from_requirement(dependency)
54
54
  requirements = dependency.requirements
55
- requirement = T.must(requirements.first)[:requirement]
55
+ requirement = T.must(requirements.first).requirement_string
56
56
  version = requirement&.match(/\d+\.\d+\.\d+/)&.to_s
57
57
  Dependabot::Dependency.new(
58
58
  name: dependency.name,
@@ -87,6 +87,22 @@ module Dependabot
87
87
  }.to_yaml.delete_prefix("---\n")
88
88
  end
89
89
 
90
+ sig { params(parent_name: String, dependency_name: String).returns(String) }
91
+ def self.subgroup_name(parent_name:, dependency_name:)
92
+ "#{parent_name}/#{dependency_name}"
93
+ end
94
+
95
+ sig do
96
+ params(subgroup_name: String, dependency_name: String)
97
+ .returns(T.nilable(String))
98
+ end
99
+ def self.parent_name_from_subgroup(subgroup_name:, dependency_name:)
100
+ suffix = "/#{dependency_name}"
101
+ return unless subgroup_name.end_with?(suffix)
102
+
103
+ subgroup_name.delete_suffix(suffix)
104
+ end
105
+
90
106
  private
91
107
 
92
108
  sig { params(dependency_name: String).returns(T::Boolean) }
@@ -16,7 +16,7 @@ module Dependabot
16
16
  #
17
17
  # Subclasses Hash so it is a drop-in replacement at call sites (and in
18
18
  # type annotations) that treat requirement entries as
19
- # T::Hash[Symbol, T.untyped], while exposing typed readers for the
19
+ # T::Hash[Symbol, Object], while exposing typed readers for the
20
20
  # well-known keys. New code should prefer the typed readers; hash-style
21
21
  # access remains supported while call sites are migrated gradually.
22
22
  #
@@ -37,15 +37,11 @@ module Dependabot
37
37
  ObjectHash = T.type_alias { T::Hash[T.any(Symbol, String), Object] }
38
38
  Requirement = T.type_alias { T.any(String, Symbol) }
39
39
  Source = T.type_alias { T.any(String, ObjectHash) }
40
- Input = T.type_alias { T.any(DependencyRequirement, ObjectHash) }
40
+ Input = T.type_alias { T::Hash[T.any(Symbol, String), T.anything] }
41
41
 
42
42
  K = type_member { { fixed: Symbol } }
43
- # Hash-style access remains dynamic until ecosystem callers migrate to the
44
- # typed readers. Keeping that compatibility here avoids a flag-day change.
45
- # rubocop:disable Sorbet/ForbidTUntyped
46
- V = type_member { { fixed: T.untyped } }
47
- Elem = type_member { { fixed: [Symbol, T.untyped] } }
48
- # rubocop:enable Sorbet/ForbidTUntyped
43
+ V = type_member { { fixed: Object } }
44
+ Elem = type_member { { fixed: [Symbol, Object] } }
49
45
 
50
46
  # Builds a DependencyRequirement from a requirement hash, symbolising
51
47
  # top-level keys. Accepts both plain hashes and existing
@@ -53,7 +49,12 @@ module Dependabot
53
49
  sig { params(hash: Input).returns(DependencyRequirement) }
54
50
  def self.create(hash)
55
51
  requirement = new
56
- requirement.replace(hash.keys.to_h { |k| [k.to_sym, hash[k]] })
52
+ hash.each do |key, value|
53
+ case value
54
+ when Object then requirement[key.to_sym] = value
55
+ else raise TypeError, "requirement values must inherit Object"
56
+ end
57
+ end
57
58
  requirement
58
59
  end
59
60
 
@@ -62,7 +63,7 @@ module Dependabot
62
63
  # or :unfixable when no valid updated requirement can be generated.
63
64
  sig { returns(T.nilable(Requirement)) }
64
65
  def requirement
65
- value = T.cast(self[:requirement], T.nilable(Object))
66
+ value = self[:requirement]
66
67
  return if value.nil?
67
68
  return value if value.is_a?(String) || value == :unfixable
68
69
 
@@ -82,7 +83,7 @@ module Dependabot
82
83
  # the underlying hash access under sorbet-runtime.
83
84
  sig { returns(T.nilable(T::Array[Group])) }
84
85
  def groups
85
- value = T.cast(self[:groups], T.nilable(Object))
86
+ value = self[:groups]
86
87
  return if value.nil?
87
88
  raise TypeError, "groups must be an array of strings or symbols, or nil" unless value.is_a?(Array)
88
89
 
@@ -101,7 +102,7 @@ module Dependabot
101
102
  # parser or deserialised from a job definition.
102
103
  sig { returns(T.nilable(Source)) }
103
104
  def source
104
- value = T.cast(self[:source], T.nilable(Object))
105
+ value = self[:source]
105
106
  return if value.nil?
106
107
  return value if value.is_a?(String)
107
108
 
@@ -153,11 +154,76 @@ module Dependabot
153
154
  raise TypeError, "requirement must be a string or nil"
154
155
  end
155
156
 
157
+ # Reads a known metadata field such as "property_name". Accepts either key
158
+ # style for the same reason as `source_string`. Returns nil when the
159
+ # requirement carries no metadata or the key is absent.
160
+ sig { params(key: String).returns(T.nilable(String)) }
161
+ def metadata_string(key)
162
+ value = metadata_value(key)
163
+ return if value.nil?
164
+ return value if value.is_a?(String)
165
+
166
+ raise TypeError, "metadata #{key} must be a string or nil"
167
+ end
168
+
169
+ # Reads a known symbol-valued metadata field such as Helm's "type".
170
+ sig { params(key: String).returns(T.nilable(Symbol)) }
171
+ def metadata_symbol(key)
172
+ value = metadata_value(key)
173
+ return if value.nil?
174
+ return value if value.is_a?(Symbol)
175
+
176
+ raise TypeError, "metadata #{key} must be a symbol or nil"
177
+ end
178
+
179
+ # Reads a boolean metadata field such as "include_debug_script".
180
+ sig { params(key: String).returns(T.nilable(T::Boolean)) }
181
+ def metadata_boolean(key)
182
+ value = metadata_value(key)
183
+ return if value.nil?
184
+ return value if value == true || value == false
185
+
186
+ raise TypeError, "metadata #{key} must be a boolean or nil"
187
+ end
188
+
189
+ # Reads a nested metadata hash whose values are all strings, such as
190
+ # "dependency_set" (`{ group: "my.group", version: "1.4.0" }`). Keys are
191
+ # symbolised so callers can read them with symbols regardless of how the
192
+ # requirement was built.
193
+ sig { params(key: String).returns(T.nilable(T::Hash[Symbol, String])) }
194
+ def metadata_string_hash(key)
195
+ value = metadata_value(key)
196
+ return if value.nil?
197
+ raise TypeError, "metadata #{key} must be a hash of strings or nil" unless value.is_a?(Hash)
198
+
199
+ value.to_h do |raw_entry_key, raw_entry_value|
200
+ entry_key = T.cast(raw_entry_key, Object)
201
+ entry_value = T.cast(raw_entry_value, Object)
202
+ unless (entry_key.is_a?(Symbol) || entry_key.is_a?(String)) && entry_value.is_a?(String)
203
+ raise TypeError, "metadata #{key} must be a hash of strings or nil"
204
+ end
205
+
206
+ [entry_key.to_sym, entry_value]
207
+ end
208
+ end
209
+
156
210
  private
157
211
 
212
+ # Reads a raw metadata field, accepting either key style. Nil when the
213
+ # requirement carries no metadata or the key is absent.
214
+ sig { params(key: String).returns(T.nilable(Object)) }
215
+ def metadata_value(key)
216
+ details = metadata
217
+ return if details.nil?
218
+
219
+ return details[key.to_sym] if details.key?(key.to_sym)
220
+
221
+ details[key]
222
+ end
223
+
158
224
  sig { params(key: Symbol).returns(T.nilable(String)) }
159
225
  def optional_string(key)
160
- value = T.cast(self[key], T.nilable(Object))
226
+ value = self[key]
161
227
  return if value.nil?
162
228
  return value if value.is_a?(String)
163
229
 
@@ -166,7 +232,7 @@ module Dependabot
166
232
 
167
233
  sig { params(key: Symbol).returns(T.nilable(ObjectHash)) }
168
234
  def optional_object_hash(key)
169
- value = T.cast(self[key], T.nilable(Object))
235
+ value = self[key]
170
236
  return if value.nil?
171
237
 
172
238
  object_hash(value, key)
@@ -46,12 +46,12 @@ module Dependabot
46
46
  supported_versions: [],
47
47
  requirement: nil
48
48
  )
49
- @name = T.let(name, String)
49
+ @name = name
50
50
  @detected_version = T.let(detected_version || version, T.nilable(Dependabot::Version))
51
- @version = T.let(version, T.nilable(Dependabot::Version))
52
- @deprecated_versions = T.let(deprecated_versions, T::Array[Dependabot::Version])
53
- @supported_versions = T.let(supported_versions, T::Array[Dependabot::Version])
54
- @requirement = T.let(requirement, T.nilable(Dependabot::Requirement))
51
+ @version = version
52
+ @deprecated_versions = deprecated_versions
53
+ @supported_versions = supported_versions
54
+ @requirement = requirement
55
55
  end
56
56
 
57
57
  # The name of the package manager (e.g., "bundler", "npm").
@@ -177,9 +177,9 @@ module Dependabot
177
177
  package_manager:,
178
178
  language: nil
179
179
  )
180
- @name = T.let(name, String)
181
- @package_manager = T.let(package_manager, VersionManager)
182
- @language = T.let(language, T.nilable(VersionManager))
180
+ @name = name
181
+ @package_manager = package_manager
182
+ @language = language
183
183
  end
184
184
 
185
185
  # The name of the ecosystem (mandatory).
@@ -246,6 +246,11 @@ module Dependabot
246
246
  "error-type": "dependency_file_not_resolvable",
247
247
  "error-detail": { message: error.message }
248
248
  }
249
+ when Dependabot::BranchNameFormattingError
250
+ {
251
+ "error-type": "branch_name_formatting_error",
252
+ "error-detail": { message: error.message }
253
+ }
249
254
  when Dependabot::BlockedDependencyVersion
250
255
  {
251
256
  "error-type": "blocked_dependency_version",
@@ -483,7 +488,7 @@ module Dependabot
483
488
 
484
489
  sig { params(error_type: String, message: T.any(T.nilable(String), MatchData)).void }
485
490
  def initialize(error_type, message = nil)
486
- @error_type = T.let(error_type, String)
491
+ @error_type = error_type
487
492
 
488
493
  super(message || error_type)
489
494
  end
@@ -509,6 +514,8 @@ module Dependabot
509
514
 
510
515
  class RefNamespaceConflictError < DependabotError; end
511
516
 
517
+ class BranchNameFormattingError < DependabotError; end
518
+
512
519
  #####################
513
520
  # Repo level errors #
514
521
  #####################
@@ -325,7 +325,7 @@ module Dependabot
325
325
 
326
326
  sig { params(path: String).returns(T::Boolean) }
327
327
  def in_submodule?(path)
328
- subpaths(path.delete_prefix("/")).any? { |subpath| @submodules.include?(subpath) }
328
+ subpaths(path.delete_prefix("/")).intersect?(@submodules)
329
329
  end
330
330
 
331
331
  # Given a "foo/bar/baz" path, returns ["foo", "foo/bar", "foo/bar/baz"]
@@ -78,7 +78,7 @@ module Dependabot
78
78
 
79
79
  private
80
80
 
81
- TEXT_ENCODINGS = T.let(%w(us-ascii utf-8).freeze, T::Array[String])
81
+ TEXT_ENCODINGS = %w(us-ascii utf-8).freeze
82
82
 
83
83
  sig { returns(T.nilable(String)) }
84
84
  attr_reader :repo_contents_path
@@ -1,4 +1,4 @@
1
- # typed: strict
1
+ # typed: strong
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "sorbet-runtime"
@@ -79,7 +79,7 @@ module Dependabot
79
79
  def requirement_changed?(file, dependency)
80
80
  changed_requirements = dependency.requirements - T.must(dependency.previous_requirements)
81
81
 
82
- changed_requirements.any? { |f| f[:file] == file.name }
82
+ changed_requirements.any? { |f| f.file == file.name }
83
83
  end
84
84
 
85
85
  sig { params(file: Dependabot::DependencyFile, content: String).returns(Dependabot::DependencyFile) }
@@ -62,10 +62,7 @@ module Dependabot
62
62
  require_relative "commits_finder"
63
63
 
64
64
  # Earlier entries are preferred
65
- CHANGELOG_NAMES = T.let(
66
- %w(changelog news changes history release whatsnew releases).freeze,
67
- T::Array[String]
68
- )
65
+ CHANGELOG_NAMES = %w(changelog news changes history release whatsnew releases).freeze
69
66
 
70
67
  sig { returns(T.nilable(Dependabot::Source)) }
71
68
  attr_reader :source
@@ -452,7 +449,7 @@ module Dependabot
452
449
  sig { returns(T.nilable(String)) }
453
450
  def previous_ref
454
451
  previous_refs = dependency.previous_requirements&.filter_map do |r|
455
- r.dig(:source, "ref") || r.dig(:source, :ref)
452
+ r.source_string("ref")
456
453
  end&.uniq
457
454
  previous_refs.first if previous_refs&.one?
458
455
  end
@@ -460,7 +457,7 @@ module Dependabot
460
457
  sig { returns(T.nilable(String)) }
461
458
  def new_ref
462
459
  new_refs = dependency.requirements.filter_map do |r|
463
- r.dig(:source, "ref") || r.dig(:source, :ref)
460
+ r.source_string("ref")
464
461
  end.uniq
465
462
  new_refs.first if new_refs.one?
466
463
  end
@@ -479,7 +476,7 @@ module Dependabot
479
476
  return false if dependency.package_manager == "composer"
480
477
 
481
478
  requirements = dependency.requirements
482
- sources = requirements.map { |r| r.fetch(:source) }.uniq.compact
479
+ sources = requirements.map(&:source_hash).uniq.compact
483
480
  return false if sources.empty?
484
481
 
485
482
  sources.all? { |s| s[:type] == "git" || s["type"] == "git" }
@@ -169,7 +169,7 @@ module Dependabot
169
169
  sig { returns(T.nilable(String)) }
170
170
  def previous_ref
171
171
  previous_refs = T.must(dependency.previous_requirements).filter_map do |r|
172
- r.dig(:source, "ref") || r.dig(:source, :ref)
172
+ r.source_string("ref")
173
173
  end.uniq
174
174
  previous_refs.first if previous_refs.one?
175
175
  end
@@ -177,7 +177,7 @@ module Dependabot
177
177
  sig { returns(T.nilable(String)) }
178
178
  def new_ref
179
179
  new_refs = dependency.requirements.filter_map do |r|
180
- r.dig(:source, "ref") || r.dig(:source, :ref)
180
+ r.source_string("ref")
181
181
  end.uniq
182
182
  new_refs.first if new_refs.one?
183
183
  end
@@ -190,7 +190,7 @@ module Dependabot
190
190
  return false if dependency.package_manager == "composer"
191
191
 
192
192
  requirements = dependency.requirements
193
- sources = requirements.map { |r| r.fetch(:source) }.uniq.compact
193
+ sources = requirements.map(&:source_hash).uniq.compact
194
194
  return false if sources.empty?
195
195
 
196
196
  sources.all? { |s| s[:type] == "git" || s["type"] == "git" }
@@ -136,10 +136,11 @@ module Dependabot
136
136
  sig { params(version: T.nilable(Dependabot::Version)).returns(T::Boolean) }
137
137
  def satisfies_previous_reqs?(version)
138
138
  T.must(dependency.previous_requirements).all? do |req|
139
- next true unless req.fetch(:requirement)
139
+ requirement = req.requirement_string
140
+ next true unless requirement
140
141
 
141
142
  requirement_class
142
- .requirements_array(req.fetch(:requirement))
143
+ .requirements_array(requirement)
143
144
  .all? { |r| r.satisfied_by?(version) }
144
145
  end
145
146
  end
@@ -151,7 +152,7 @@ module Dependabot
151
152
  # internally
152
153
  return false if dependency.package_manager == "composer"
153
154
 
154
- sources = requirements&.map { |r| r.fetch(:source) }&.uniq&.compact
155
+ sources = requirements&.map(&:source_hash)&.uniq&.compact
155
156
  return false if sources.nil? || sources.empty?
156
157
 
157
158
  sources.all? { |s| s[:type] == "git" || s["type"] == "git" }
@@ -168,7 +169,7 @@ module Dependabot
168
169
  return unless git_source?(dependency.previous_requirements)
169
170
 
170
171
  previous_refs = T.must(dependency.previous_requirements).filter_map do |r|
171
- r.dig(:source, "ref") || r.dig(:source, :ref)
172
+ r.source_string("ref")
172
173
  end.uniq
173
174
  previous_refs.first if previous_refs.one?
174
175
  end
@@ -178,7 +179,7 @@ module Dependabot
178
179
  return unless git_source?(dependency.previous_requirements)
179
180
 
180
181
  new_refs = dependency.requirements.filter_map do |r|
181
- r.dig(:source, "ref") || r.dig(:source, :ref)
182
+ r.source_string("ref")
182
183
  end.uniq
183
184
  new_refs.first if new_refs.one?
184
185
  end
@@ -198,15 +198,9 @@ module Dependabot
198
198
  sig { params(releases: T::Array[ReleaseType], conservative: T::Boolean).returns(T::Array[ReleaseType]) }
199
199
  def filter_releases_using_previous_version(releases, conservative:)
200
200
  releases.reject do |release|
201
- cleaned_tag = release.tag_name.gsub(/^[^0-9]*/, "")
202
- cleaned_name = release.name&.gsub(/^[^0-9]*/, "")
203
- dot_count = [cleaned_tag, cleaned_name].compact.reject(&:empty?)
204
- .map { |nm| nm.chars.count(".") }.max
201
+ next false if release_tag_matches_version?(release, new_version)
205
202
 
206
- tag_version = [cleaned_tag, cleaned_name].compact.reject(&:empty?)
207
- .select { |nm| version_class.correct?(nm) }
208
- .select { |nm| nm.chars.count(".") == dot_count }
209
- .map { |nm| version_class.new(nm) }.max
203
+ tag_version = possible_versions(release).max
210
204
 
211
205
  next conservative unless tag_version
212
206
 
@@ -221,15 +215,9 @@ module Dependabot
221
215
  updated_version = version_class.new(new_version)
222
216
 
223
217
  releases.reject do |release|
224
- cleaned_tag = release.tag_name.gsub(/^[^0-9]*/, "")
225
- cleaned_name = release.name&.gsub(/^[^0-9]*/, "")
226
- dot_count = [cleaned_tag, cleaned_name].compact.reject(&:empty?)
227
- .map { |nm| nm.chars.count(".") }.max
218
+ next false if release_tag_matches_version?(release, new_version)
228
219
 
229
- tag_version = [cleaned_tag, cleaned_name].compact.reject(&:empty?)
230
- .select { |nm| version_class.correct?(nm) }
231
- .select { |nm| nm.chars.count(".") == dot_count }
232
- .map { |nm| version_class.new(nm) }.min
220
+ tag_version = possible_versions(release).min
233
221
 
234
222
  next conservative unless tag_version
235
223
 
@@ -239,6 +227,26 @@ module Dependabot
239
227
  end
240
228
  end
241
229
 
230
+ sig { params(release: ReleaseType).returns(T::Array[Dependabot::Version]) }
231
+ def possible_versions(release)
232
+ candidates = [release.tag_name, release.name].compact
233
+ .map { |name| name.gsub(/^[^0-9]*/, "") }
234
+ .reject(&:empty?)
235
+ .select { |name| version_class.correct?(name) }
236
+ dot_count = candidates.map { |name| name.chars.count(".") }.max
237
+ return [] unless dot_count
238
+
239
+ candidates.select { |name| name.chars.count(".") == dot_count }
240
+ .map { |name| version_class.new(name) }
241
+ end
242
+
243
+ sig { params(release: ReleaseType, version: T.nilable(String)).returns(T::Boolean) }
244
+ def release_tag_matches_version?(release, version)
245
+ return false unless version
246
+
247
+ release.tag_name.gsub(/^[^0-9]*/, "") == version.gsub(/^[^0-9]*/, "")
248
+ end
249
+
242
250
  sig { returns(T.nilable(ReleaseType)) }
243
251
  def updated_release
244
252
  release_for_version(new_version)
@@ -15,7 +15,7 @@ module Dependabot
15
15
  require "dependabot/metadata_finders/base/release_finder"
16
16
  require "dependabot/metadata_finders/base/commits_finder"
17
17
 
18
- PACKAGE_MANAGERS_WITH_RELIABLE_DIRECTORIES = T.let(%w(bun npm_and_yarn pub).freeze, T::Array[String])
18
+ PACKAGE_MANAGERS_WITH_RELIABLE_DIRECTORIES = %w(bun npm_and_yarn pub).freeze
19
19
 
20
20
  sig { returns(Dependabot::Dependency) }
21
21
  attr_reader :dependency
@@ -20,12 +20,12 @@ module Dependabot
20
20
  ).void
21
21
  end
22
22
  def initialize(dependency:, releases: [], dist_tags: nil)
23
- @dependency = T.let(dependency, Dependabot::Dependency)
23
+ @dependency = dependency
24
24
  @releases = T.let(
25
25
  releases.sort_by(&:version).reverse,
26
26
  T::Array[Dependabot::Package::PackageRelease]
27
27
  )
28
- @dist_tags = T.let(dist_tags, T.nilable(T::Hash[String, String]))
28
+ @dist_tags = dist_tags
29
29
  end
30
30
 
31
31
  sig { returns(Dependabot::Dependency) }
@@ -15,9 +15,9 @@ module Dependabot
15
15
  ).void
16
16
  end
17
17
  def initialize(name:, version: nil, requirement: nil)
18
- @name = T.let(name, String)
19
- @version = T.let(version, T.nilable(Dependabot::Version))
20
- @requirement = T.let(requirement, T.nilable(Dependabot::Requirement))
18
+ @name = name
19
+ @version = version
20
+ @requirement = requirement
21
21
  end
22
22
 
23
23
  sig { returns(String) }
@@ -290,9 +290,10 @@ module Dependabot
290
290
  end
291
291
  def filter_out_of_range_versions(releases)
292
292
  reqs = dependency.requirements.filter_map do |r|
293
- next if r.fetch(:requirement).nil?
293
+ requirement = r.requirement_string
294
+ next if requirement.nil?
294
295
 
295
- requirement_class.requirements_array(r.fetch(:requirement))
296
+ requirement_class.requirements_array(requirement)
296
297
  end
297
298
 
298
299
  releases
@@ -325,7 +326,7 @@ module Dependabot
325
326
  return true if dependency.numeric_version&.prerelease?
326
327
 
327
328
  dependency.requirements.any? do |req|
328
- req_string = req.fetch(:requirement) || ""
329
+ req_string = req.requirement_string || ""
329
330
  req_string.split(",").map(&:strip).any? do |r|
330
331
  version_str = r.gsub(/^\s*[!<>=~^]+\s*/, "").strip
331
332
  next false unless version_class.correct?(version_str)
@@ -40,17 +40,17 @@ module Dependabot
40
40
  tag: nil,
41
41
  details: {}
42
42
  )
43
- @version = T.let(version, Dependabot::Version)
44
- @released_at = T.let(released_at, T.nilable(Time))
45
- @latest = T.let(latest, T::Boolean)
46
- @yanked = T.let(yanked, T::Boolean)
47
- @yanked_reason = T.let(yanked_reason, T.nilable(String))
48
- @downloads = T.let(downloads, T.nilable(Integer))
49
- @url = T.let(url, T.nilable(String))
50
- @package_type = T.let(package_type, T.nilable(String))
51
- @language = T.let(language, T.nilable(Dependabot::Package::PackageLanguage))
52
- @tag = T.let(tag, T.nilable(String))
53
- @details = T.let(details, T::Hash[String, T.anything])
43
+ @version = version
44
+ @released_at = released_at
45
+ @latest = latest
46
+ @yanked = yanked
47
+ @yanked_reason = yanked_reason
48
+ @downloads = downloads
49
+ @url = url
50
+ @package_type = package_type
51
+ @language = language
52
+ @tag = tag
53
+ @details = details
54
54
  end
55
55
 
56
56
  sig { returns(Dependabot::Version) }