dependabot-uv 0.331.0 → 0.333.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.
@@ -1,8 +1,9 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "excon"
5
5
  require "toml-rb"
6
+ require "sorbet-runtime"
6
7
 
7
8
  require "dependabot/dependency"
8
9
  require "dependabot/errors"
@@ -17,6 +18,8 @@ require "dependabot/update_checkers/base"
17
18
  module Dependabot
18
19
  module Uv
19
20
  class UpdateChecker < Dependabot::UpdateCheckers::Base
21
+ extend T::Sig
22
+
20
23
  require_relative "update_checker/pip_compile_version_resolver"
21
24
  require_relative "update_checker/pip_version_resolver"
22
25
  require_relative "update_checker/requirements_updater"
@@ -29,12 +32,17 @@ module Dependabot
29
32
  ).freeze
30
33
  VERSION_REGEX = /[0-9]+(?:\.[A-Za-z0-9\-_]+)*/
31
34
 
35
+ sig { override.returns(T.nilable(Gem::Version)) }
32
36
  def latest_version
33
- @latest_version ||= fetch_latest_version
37
+ @latest_version ||= T.let(
38
+ fetch_latest_version,
39
+ T.nilable(Gem::Version)
40
+ )
34
41
  end
35
42
 
43
+ sig { override.returns(T.nilable(Gem::Version)) }
36
44
  def latest_resolvable_version
37
- @latest_resolvable_version ||=
45
+ @latest_resolvable_version ||= T.let(
38
46
  if resolver_type == :requirements
39
47
  resolver.latest_resolvable_version
40
48
  elsif resolver_type == :pip_compile && resolver.resolvable?(version: latest_version)
@@ -43,33 +51,41 @@ module Dependabot
43
51
  resolver.latest_resolvable_version(
44
52
  requirement: unlocked_requirement_string
45
53
  )
46
- end
54
+ end,
55
+ T.nilable(Gem::Version)
56
+ )
47
57
  end
48
58
 
59
+ sig { override.returns(T.nilable(Gem::Version)) }
49
60
  def latest_resolvable_version_with_no_unlock
50
- @latest_resolvable_version_with_no_unlock ||=
61
+ @latest_resolvable_version_with_no_unlock ||= T.let(
51
62
  if resolver_type == :requirements
52
63
  resolver.latest_resolvable_version_with_no_unlock
53
64
  else
54
65
  resolver.latest_resolvable_version(
55
66
  requirement: current_requirement_string
56
67
  )
57
- end
68
+ end,
69
+ T.nilable(Gem::Version)
70
+ )
58
71
  end
59
72
 
73
+ sig { override.returns(T.nilable(Gem::Version)) }
60
74
  def lowest_security_fix_version
61
75
  latest_version_finder.lowest_security_fix_version
62
76
  end
63
77
 
78
+ sig { override.returns(T.nilable(Gem::Version)) }
64
79
  def lowest_resolvable_security_fix_version
65
80
  raise "Dependency not vulnerable!" unless vulnerable?
66
81
 
67
- return @lowest_resolvable_security_fix_version if defined?(@lowest_resolvable_security_fix_version)
68
-
69
- @lowest_resolvable_security_fix_version =
70
- fetch_lowest_resolvable_security_fix_version
82
+ @lowest_resolvable_security_fix_version ||= T.let(
83
+ fetch_lowest_resolvable_security_fix_version,
84
+ T.nilable(Gem::Version)
85
+ )
71
86
  end
72
87
 
88
+ sig { override.returns(T::Array[T::Hash[Symbol, T.untyped]]) }
73
89
  def updated_requirements
74
90
  RequirementsUpdater.new(
75
91
  requirements: requirements,
@@ -79,10 +95,12 @@ module Dependabot
79
95
  ).updated_requirements
80
96
  end
81
97
 
98
+ sig { override.returns(T::Boolean) }
82
99
  def requirements_unlocked_or_can_be?
83
100
  !requirements_update_strategy.lockfile_only?
84
101
  end
85
102
 
103
+ sig { override.returns(Dependabot::RequirementsUpdateStrategy) }
86
104
  def requirements_update_strategy
87
105
  # If passed in as an option (in the base class) honour that option
88
106
  return @requirements_update_strategy if @requirements_update_strategy
@@ -93,15 +111,18 @@ module Dependabot
93
111
 
94
112
  private
95
113
 
114
+ sig { override.returns(T::Boolean) }
96
115
  def latest_version_resolvable_with_full_unlock?
97
116
  # Full unlock checks aren't implemented for Python (yet)
98
117
  false
99
118
  end
100
119
 
120
+ sig { override.returns(T::Array[Dependabot::Dependency]) }
101
121
  def updated_dependencies_after_full_unlock
102
122
  raise NotImplementedError
103
123
  end
104
124
 
125
+ sig { returns(T.nilable(Gem::Version)) }
105
126
  def fetch_lowest_resolvable_security_fix_version
106
127
  fix_version = lowest_security_fix_version
107
128
  return latest_resolvable_version if fix_version.nil?
@@ -111,6 +132,7 @@ module Dependabot
111
132
  resolver.resolvable?(version: fix_version) ? fix_version : nil
112
133
  end
113
134
 
135
+ sig { returns(T.untyped) }
114
136
  def resolver
115
137
  case resolver_type
116
138
  when :pip_compile then pip_compile_version_resolver
@@ -120,6 +142,7 @@ module Dependabot
120
142
  end
121
143
  end
122
144
 
145
+ sig { returns(Symbol) }
123
146
  def resolver_type
124
147
  reqs = requirements
125
148
 
@@ -141,6 +164,7 @@ module Dependabot
141
164
  end
142
165
  end
143
166
 
167
+ sig { returns(Symbol) }
144
168
  def subdependency_resolver
145
169
  return :pip_compile if pip_compile_files.any?
146
170
  return :lock_file if uv_lock.any?
@@ -148,6 +172,7 @@ module Dependabot
148
172
  raise "Claimed to be a sub-dependency, but no lockfile exists!"
149
173
  end
150
174
 
175
+ sig { params(reqs: T::Array[T::Hash[Symbol, T.untyped]]).returns(T::Boolean) }
151
176
  def exact_requirement?(reqs)
152
177
  reqs = reqs.map { |r| r.fetch(:requirement) }
153
178
  reqs = reqs.compact
@@ -155,27 +180,49 @@ module Dependabot
155
180
  reqs.any? { |r| Uv::Requirement.new(r).exact? }
156
181
  end
157
182
 
183
+ sig { returns(PipCompileVersionResolver) }
158
184
  def pip_compile_version_resolver
159
- @pip_compile_version_resolver ||=
160
- PipCompileVersionResolver.new(**resolver_args)
185
+ @pip_compile_version_resolver ||= T.let(
186
+ PipCompileVersionResolver.new(
187
+ dependency: dependency,
188
+ dependency_files: dependency_files,
189
+ credentials: credentials,
190
+ repo_contents_path: repo_contents_path
191
+ ),
192
+ T.nilable(PipCompileVersionResolver)
193
+ )
161
194
  end
162
195
 
196
+ sig { returns(PipVersionResolver) }
163
197
  def pip_version_resolver
164
- @pip_version_resolver ||= PipVersionResolver.new(
165
- dependency: dependency,
166
- dependency_files: dependency_files,
167
- credentials: credentials,
168
- ignored_versions: ignored_versions,
169
- raise_on_ignored: @raise_on_ignored,
170
- update_cooldown: @update_cooldown,
171
- security_advisories: security_advisories
198
+ @pip_version_resolver ||= T.let(
199
+ PipVersionResolver.new(
200
+ dependency: dependency,
201
+ dependency_files: dependency_files,
202
+ credentials: credentials,
203
+ ignored_versions: ignored_versions,
204
+ raise_on_ignored: @raise_on_ignored,
205
+ update_cooldown: @update_cooldown,
206
+ security_advisories: security_advisories
207
+ ),
208
+ T.nilable(PipVersionResolver)
172
209
  )
173
210
  end
174
211
 
212
+ sig { returns(LockFileResolver) }
175
213
  def lock_file_resolver
176
- @lock_file_resolver ||= LockFileResolver.new(**resolver_args)
214
+ @lock_file_resolver ||= T.let(
215
+ LockFileResolver.new(
216
+ dependency: dependency,
217
+ dependency_files: dependency_files,
218
+ credentials: credentials,
219
+ repo_contents_path: repo_contents_path
220
+ ),
221
+ T.nilable(LockFileResolver)
222
+ )
177
223
  end
178
224
 
225
+ sig { returns(T::Hash[Symbol, T.untyped]) }
179
226
  def resolver_args
180
227
  {
181
228
  dependency: dependency,
@@ -185,6 +232,7 @@ module Dependabot
185
232
  }
186
233
  end
187
234
 
235
+ sig { returns(T.nilable(String)) }
188
236
  def current_requirement_string
189
237
  reqs = requirements
190
238
  return if reqs.none?
@@ -198,6 +246,7 @@ module Dependabot
198
246
  requirement&.fetch(:requirement)
199
247
  end
200
248
 
249
+ sig { returns(String) }
201
250
  def unlocked_requirement_string
202
251
  lower_bound_req = updated_version_req_lower_bound
203
252
 
@@ -214,6 +263,7 @@ module Dependabot
214
263
  lower_bound_req + ",<=#{latest_version}"
215
264
  end
216
265
 
266
+ sig { returns(String) }
217
267
  def updated_version_req_lower_bound
218
268
  return ">=#{dependency.version}" if dependency.version
219
269
 
@@ -228,99 +278,133 @@ module Dependabot
228
278
  ">=#{version_for_requirement || 0}"
229
279
  end
230
280
 
281
+ sig { returns(T.nilable(Gem::Version)) }
231
282
  def fetch_latest_version
232
283
  latest_version_finder.latest_version
233
284
  end
234
285
 
286
+ sig { returns(LatestVersionFinder) }
235
287
  def latest_version_finder
236
- @latest_version_finder ||= LatestVersionFinder.new(
237
- dependency: dependency,
238
- dependency_files: dependency_files,
239
- credentials: credentials,
240
- ignored_versions: ignored_versions,
241
- raise_on_ignored: @raise_on_ignored,
242
- cooldown_options: @update_cooldown,
243
- security_advisories: security_advisories
288
+ @latest_version_finder ||= T.let(
289
+ LatestVersionFinder.new(
290
+ dependency: dependency,
291
+ dependency_files: dependency_files,
292
+ credentials: credentials,
293
+ ignored_versions: ignored_versions,
294
+ raise_on_ignored: @raise_on_ignored,
295
+ cooldown_options: @update_cooldown,
296
+ security_advisories: security_advisories
297
+ ),
298
+ T.nilable(LatestVersionFinder)
244
299
  )
245
300
  end
246
301
 
302
+ sig { returns(T::Boolean) }
247
303
  def library?
248
304
  return false unless updating_pyproject?
305
+ return false unless library_details
249
306
 
250
- return false if library_details["name"].nil?
307
+ return false if T.must(library_details)["name"].nil?
251
308
 
252
309
  # Hit PyPi and check whether there are details for a library with a
253
310
  # matching name and description
254
311
  index_response = Dependabot::RegistryClient.get(
255
- url: "https://pypi.org/pypi/#{normalised_name(library_details['name'])}/json/"
312
+ url: "https://pypi.org/pypi/#{normalised_name(T.must(library_details)['name'])}/json/"
256
313
  )
257
314
 
258
315
  return false unless index_response.status == 200
259
316
 
260
317
  pypi_info = JSON.parse(index_response.body)["info"] || {}
261
- pypi_info["summary"] == library_details["description"]
318
+ pypi_info["summary"] == T.must(library_details)["description"]
262
319
  rescue Excon::Error::Timeout, Excon::Error::Socket
263
320
  false
264
321
  rescue URI::InvalidURIError
265
322
  false
266
323
  end
267
324
 
325
+ sig { returns(T::Boolean) }
268
326
  def updating_pyproject?
269
327
  requirement_files.any?("pyproject.toml")
270
328
  end
271
329
 
330
+ sig { returns(T::Boolean) }
272
331
  def updating_in_file?
273
332
  requirement_files.any? { |f| f.end_with?(".in") }
274
333
  end
275
334
 
335
+ sig { returns(T::Boolean) }
276
336
  def updating_uv_lock?
277
337
  requirement_files.any?("uv.lock")
278
338
  end
279
339
 
340
+ sig { returns(T::Boolean) }
280
341
  def requirements_text_file?
281
342
  requirement_files.any? { |f| f.end_with?("requirements.txt") }
282
343
  end
283
344
 
345
+ sig { returns(T::Boolean) }
284
346
  def updating_requirements_file?
285
347
  requirement_files.any? { |f| f =~ /\.txt$|\.in$/ }
286
348
  end
287
349
 
350
+ sig { returns(T::Array[String]) }
288
351
  def requirement_files
289
352
  requirements.map { |r| r.fetch(:file) }
290
353
  end
291
354
 
355
+ sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
292
356
  def requirements
293
357
  dependency.requirements
294
358
  end
295
359
 
360
+ sig { params(name: String).returns(String) }
296
361
  def normalised_name(name)
297
362
  NameNormaliser.normalise(name)
298
363
  end
299
364
 
365
+ sig { returns(T.nilable(Dependabot::DependencyFile)) }
300
366
  def pyproject
301
367
  dependency_files.find { |f| f.name == "pyproject.toml" }
302
368
  end
303
369
 
370
+ sig { returns(T.nilable(T::Hash[String, T.untyped])) }
304
371
  def library_details
305
- @library_details ||= standard_details || build_system_details
372
+ @library_details ||= T.let(
373
+ standard_details || build_system_details,
374
+ T.nilable(T::Hash[String, T.untyped])
375
+ )
306
376
  end
307
377
 
378
+ sig { returns(T.nilable(T::Hash[String, T.untyped])) }
308
379
  def standard_details
309
- @standard_details ||= toml_content["project"]
380
+ @standard_details ||= T.let(
381
+ toml_content["project"],
382
+ T.nilable(T::Hash[String, T.untyped])
383
+ )
310
384
  end
311
385
 
386
+ sig { returns(T.nilable(T::Hash[String, T.untyped])) }
312
387
  def build_system_details
313
- @build_system_details ||= toml_content["build-system"]
388
+ @build_system_details ||= T.let(
389
+ toml_content["build-system"],
390
+ T.nilable(T::Hash[String, T.untyped])
391
+ )
314
392
  end
315
393
 
394
+ sig { returns(T::Hash[String, T.untyped]) }
316
395
  def toml_content
317
- @toml_content ||= TomlRB.parse(pyproject.content)
396
+ @toml_content ||= T.let(
397
+ TomlRB.parse(T.must(pyproject).content),
398
+ T.nilable(T::Hash[String, T.untyped])
399
+ )
318
400
  end
319
401
 
402
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
320
403
  def pip_compile_files
321
404
  dependency_files.select { |f| f.name.end_with?(".in") }
322
405
  end
323
406
 
407
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
324
408
  def uv_lock
325
409
  dependency_files.select { |f| f.name == "uv.lock" }
326
410
  end
@@ -1,6 +1,8 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "sorbet-runtime"
5
+
4
6
  require "dependabot/version"
5
7
  require "dependabot/utils"
6
8
 
@@ -9,6 +11,8 @@ require "dependabot/utils"
9
11
  module Dependabot
10
12
  module Uv
11
13
  class Version < Dependabot::Version
14
+ extend T::Sig
15
+
12
16
  sig { returns(Integer) }
13
17
  attr_reader :epoch
14
18
 
@@ -27,8 +31,8 @@ module Dependabot
27
31
  sig { returns(T.nilable(T::Array[T.any(String, Integer)])) }
28
32
  attr_reader :local
29
33
 
30
- INFINITY = 1000
31
- NEGATIVE_INFINITY = -INFINITY
34
+ INFINITY = T.let(1000, Integer)
35
+ NEGATIVE_INFINITY = T.let(-INFINITY, Integer)
32
36
 
33
37
  # See https://peps.python.org/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions
34
38
  VERSION_PATTERN = /
@@ -72,10 +76,10 @@ module Dependabot
72
76
  end
73
77
 
74
78
  sig { override.params(version: VersionParameter).void }
75
- def initialize(version)
79
+ def initialize(version) # rubocop:disable Metrics/AbcSize
76
80
  raise Dependabot::BadRequirementError, "Malformed version string - string is nil" if version.nil?
77
81
 
78
- @version_string = version.to_s
82
+ @version_string = T.let(version.to_s, String)
79
83
 
80
84
  raise Dependabot::BadRequirementError, "Malformed version string - string is empty" if @version_string.empty?
81
85
 
@@ -86,12 +90,17 @@ module Dependabot
86
90
  "Malformed version string - #{@version_string} does not match regex"
87
91
  end
88
92
 
89
- @epoch = matches["epoch"].to_i
90
- @release_segment = matches["release"]&.split(".")&.map(&:to_i) || []
91
- @pre = parse_letter_version(matches["pre_l"], matches["pre_n"])
92
- @post = parse_letter_version(matches["post_l"], matches["post_n1"] || matches["post_n2"])
93
- @dev = parse_letter_version(matches["dev_l"], matches["dev_n"])
94
- @local = parse_local_version(matches["local"])
93
+ @epoch = T.let(matches["epoch"].to_i, Integer)
94
+ @release_segment = T.let(matches["release"]&.split(".")&.map(&:to_i) || [], T::Array[Integer])
95
+ @pre = T.let(parse_letter_version(matches["pre_l"], matches["pre_n"]),
96
+ T.nilable(T::Array[T.any(String, Integer)]))
97
+ @post = T.let(
98
+ parse_letter_version(matches["post_l"], matches["post_n1"] || matches["post_n2"]),
99
+ T.nilable(T::Array[T.any(String, Integer)])
100
+ )
101
+ @dev = T.let(parse_letter_version(matches["dev_l"], matches["dev_n"]),
102
+ T.nilable(T::Array[T.any(String, Integer)]))
103
+ @local = T.let(parse_local_version(matches["local"]), T.nilable(T::Array[T.any(String, Integer)]))
95
104
  super(matches["release"] || "")
96
105
  end
97
106
 
@@ -123,7 +132,6 @@ module Dependabot
123
132
  sig { params(other: VersionParameter).returns(Integer) }
124
133
  def <=>(other)
125
134
  other = Dependabot::Uv::Version.new(other.to_s) unless other.is_a?(Dependabot::Uv::Version)
126
- other = T.cast(other, Dependabot::Uv::Version)
127
135
 
128
136
  epoch_comparison = epoch <=> other.epoch
129
137
  return epoch_comparison unless epoch_comparison.zero?
@@ -183,13 +191,13 @@ module Dependabot
183
191
  # - Alphanumeric segments sort lexicographically
184
192
  # - Numeric segments sort numerically
185
193
  # - Shorter versions sort before longer versions when the prefixes match exactly
186
- local&.map do |token|
194
+ T.must(local).map do |token|
187
195
  if token.is_a?(Integer)
188
196
  [token, ""]
189
197
  else
190
198
  [NEGATIVE_INFINITY, token]
191
199
  end
192
- end
200
+ end.flatten
193
201
  end
194
202
  end
195
203
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-uv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.331.0
4
+ version: 0.333.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.331.0
18
+ version: 0.333.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - '='
24
24
  - !ruby/object:Gem::Version
25
- version: 0.331.0
25
+ version: 0.333.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: debug
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -211,14 +211,14 @@ dependencies:
211
211
  requirements:
212
212
  - - "~>"
213
213
  - !ruby/object:Gem::Version
214
- version: '3.18'
214
+ version: '3.25'
215
215
  type: :development
216
216
  prerelease: false
217
217
  version_requirements: !ruby/object:Gem::Requirement
218
218
  requirements:
219
219
  - - "~>"
220
220
  - !ruby/object:Gem::Version
221
- version: '3.18'
221
+ version: '3.25'
222
222
  - !ruby/object:Gem::Dependency
223
223
  name: webrick
224
224
  requirement: !ruby/object:Gem::Requirement
@@ -284,7 +284,7 @@ licenses:
284
284
  - MIT
285
285
  metadata:
286
286
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
287
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.331.0
287
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.333.0
288
288
  rdoc_options: []
289
289
  require_paths:
290
290
  - lib