dependabot-uv 0.370.0 → 0.372.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: a696c9fd0da0ea89a6b4bb13652c87a13536a3d6019d4c553a47d76cefc57a7f
4
- data.tar.gz: 077afc2de1293334a8a33d972d734dffcaff90ae7f63a16955f2ea1de9b38f3a
3
+ metadata.gz: 5b800f6ffdf570bc834de464268bdb32c5051b2af1f7e9e7b522430d6ce4f237
4
+ data.tar.gz: c4da6008928f94391a149957c5e13bd0274adc0bca2602bc5b0408de8b01676b
5
5
  SHA512:
6
- metadata.gz: ce87367498361f99b4e64a54e1e0d5e834dcd36f30de5bcea803573fb9bab26477f9b9bf24c10c26a7e3d80655f8539cade1e393ddb17ea9809a4c07d0d4e23d
7
- data.tar.gz: 51d3fbf8cb202ea9a6742044c103e9e0b4317e421896e94551312d945180a08879c7d84e4d024cc7b2f5005e6f0df093f550d753cac6223be64b510f6b441e9a
6
+ metadata.gz: 41b72c005c15263ccdf177000a5ced804ba43b73cf8170dfcb4f65cc4a1ef0a2d02e79146a2a94d81e859b9895a20c665c4e5d3e6fa4663e1af91c58ae858946
7
+ data.tar.gz: b086ec486967b5a6c78f29611b8fe0adbbff911a4e8f46fc3188efb48d1791d0d2a6be24c7e6c0431bc6a46306b73c95c5bc6bc1a32c254495a0bcd3727a26ba
@@ -24,6 +24,7 @@ module Dependabot
24
24
  require_relative "pyproject_preparer"
25
25
  require_relative "version_config_parser"
26
26
  require_relative "lock_file_error_handler"
27
+ require_relative "lock_index_credential_matcher"
27
28
 
28
29
  REQUIRED_FILES = %w(pyproject.toml uv.lock).freeze # At least one of these files should be present
29
30
 
@@ -285,7 +286,7 @@ module Dependabot
285
286
  command = "pyenv exec uv lock --upgrade-package #{package_spec} #{options}"
286
287
  fingerprint = "pyenv exec uv lock --upgrade-package <dependency_name> #{options_fingerprint}"
287
288
 
288
- env_vars = explicit_index_env_vars.merge(setuptools_scm_pretend_version_env_vars)
289
+ env_vars = pyproject_index_env_vars.merge(setuptools_scm_pretend_version_env_vars)
289
290
 
290
291
  run_command(command, fingerprint: fingerprint, env: env_vars)
291
292
  end
@@ -355,18 +356,67 @@ module Dependabot
355
356
 
356
357
  sig { returns(T::Array[String]) }
357
358
  def lock_index_options
358
- credentials
359
- .select { |cred| cred["type"] == "python_index" }
360
- .reject { |cred| explicit_index?(cred) }
361
- .map do |cred|
362
- authed_url = AuthedUrlBuilder.authed_url(credential: cred)
363
-
364
- if cred.replaces_base?
365
- "--default-index #{authed_url}"
366
- else
367
- "--index #{authed_url}"
368
- end
359
+ filtered_credentials = credentials
360
+ .select { |cred| cred["type"] == "python_index" }
361
+ .reject do |cred|
362
+ cred.replaces_base? ? defined_in_pyproject?(cred) : explicit_index?(cred)
363
+ end
364
+
365
+ options = T.let([], T::Array[String])
366
+ used_credential_urls = T.let([], T::Array[String])
367
+ credential_matcher = LockIndexCredentialMatcher.new(credentials: filtered_credentials)
368
+
369
+ uv_lock_registry_urls.each do |registry_url|
370
+ credential = credential_matcher.best_credential_for_registry_url(registry_url)
371
+ next unless credential
372
+
373
+ used_credential_urls << credential["index-url"].to_s
374
+ options << option_for_credential_url(credential, authed_registry_url(credential, registry_url))
375
+ end
376
+
377
+ # Fall back to credential URLs for indices not represented in uv.lock.
378
+ filtered_credentials.each do |credential|
379
+ next if used_credential_urls.include?(credential["index-url"].to_s)
380
+
381
+ authed_url = AuthedUrlBuilder.authed_url(credential: credential)
382
+ options << option_for_credential_url(credential, authed_url)
369
383
  end
384
+
385
+ options.uniq
386
+ end
387
+
388
+ sig { params(credential: Dependabot::Credential, url: String).returns(String) }
389
+ def option_for_credential_url(credential, url)
390
+ if credential.replaces_base?
391
+ "--default-index #{url}"
392
+ else
393
+ "--index #{url}"
394
+ end
395
+ end
396
+
397
+ sig { params(credential: Dependabot::Credential, registry_url: String).returns(String) }
398
+ def authed_registry_url(credential, registry_url)
399
+ lock_credential = Dependabot::Credential.new(credential.to_h.merge("index-url" => registry_url))
400
+ AuthedUrlBuilder.authed_url(credential: lock_credential)
401
+ end
402
+
403
+ sig { returns(T::Array[String]) }
404
+ def uv_lock_registry_urls
405
+ return [] unless lockfile&.content
406
+
407
+ parsed = TomlRB.parse(T.must(lockfile).content)
408
+ packages = parsed["package"]
409
+ return [] unless packages.is_a?(Array)
410
+
411
+ packages.filter_map do |package|
412
+ source = package["source"]
413
+ next unless source.is_a?(Hash)
414
+
415
+ registry = source["registry"]
416
+ registry if registry.is_a?(String)
417
+ end.uniq
418
+ rescue TomlRB::ParseError
419
+ []
370
420
  end
371
421
 
372
422
  sig { params(credential: Dependabot::Credential).returns(T::Boolean) }
@@ -379,6 +429,14 @@ module Dependabot
379
429
  end
380
430
  end
381
431
 
432
+ # Checks if a credential's index URL matches any index defined in pyproject.toml.
433
+ # When true, authentication is provided via env vars so uv uses the pyproject.toml URL,
434
+ # preserving URL format alignment between pyproject.toml and uv.lock.
435
+ sig { params(credential: Dependabot::Credential).returns(T::Boolean) }
436
+ def defined_in_pyproject?(credential)
437
+ !find_index_name_for_credential(credential).nil?
438
+ end
439
+
382
440
  sig { params(url: String).returns(String) }
383
441
  def normalize_index_url(url)
384
442
  url.chomp("/")
@@ -414,16 +472,17 @@ module Dependabot
414
472
  # (the proxy handles authentication). This is for those running Dependabot
415
473
  # themselves and for dry-run.
416
474
  sig { returns(T::Hash[String, String]) }
417
- def explicit_index_env_vars
475
+ def pyproject_index_env_vars
418
476
  env_vars = {}
419
477
 
420
- credentials
421
- .select { |cred| cred["type"] == "python_index" }
422
- .select { |cred| explicit_index?(cred) }
423
- .each do |cred|
424
- index_name = find_index_name_for_credential(cred)
425
- next unless index_name
478
+ matched_credentials = credentials
479
+ .select { |cred| cred["type"] == "python_index" }
480
+ .filter_map do |cred|
481
+ index_name = find_index_name_for_credential(cred)
482
+ [cred, index_name] if index_name
483
+ end
426
484
 
485
+ matched_credentials.each do |cred, index_name|
427
486
  env_name = index_name.upcase.gsub(/[^A-Z0-9]/, "_")
428
487
 
429
488
  env_vars["UV_INDEX_#{env_name}_USERNAME"] = cred["username"] if cred["username"]
@@ -451,9 +510,9 @@ module Dependabot
451
510
 
452
511
  sig { params(options: String).returns(String) }
453
512
  def lock_options_fingerprint(options)
454
- options.sub(
513
+ options.gsub(
455
514
  /--default-index\s+\S+/, "--default-index <default_index>"
456
- ).sub(
515
+ ).gsub(
457
516
  /--index\s+\S+/, "--index <index>"
458
517
  )
459
518
  end
@@ -0,0 +1,74 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "uri"
5
+ require "dependabot/uv/file_updater"
6
+
7
+ module Dependabot
8
+ module Uv
9
+ class FileUpdater < Dependabot::FileUpdaters::Base
10
+ class LockIndexCredentialMatcher
11
+ extend T::Sig
12
+
13
+ sig { params(credentials: T::Array[Dependabot::Credential]).void }
14
+ def initialize(credentials:)
15
+ @credentials = credentials
16
+ end
17
+
18
+ sig { params(registry_url: String).returns(T.nilable(Dependabot::Credential)) }
19
+ def best_credential_for_registry_url(registry_url)
20
+ credential_scores = @credentials.map do |credential|
21
+ [credential, credential_match_score(credential["index-url"].to_s, registry_url)]
22
+ end
23
+ best_match = credential_scores.max_by { |_, score| score }
24
+
25
+ return nil unless best_match
26
+ return nil if best_match[1].negative?
27
+
28
+ best_match[0]
29
+ end
30
+
31
+ private
32
+
33
+ sig { params(credential_url: String, registry_url: String).returns(Integer) }
34
+ def credential_match_score(credential_url, registry_url)
35
+ normalized_credential_url = normalize_index_url(credential_url)
36
+ normalized_registry_url = normalize_index_url(registry_url)
37
+
38
+ return 100_000 if normalized_credential_url == normalized_registry_url
39
+
40
+ credential_uri = URI.parse(normalized_credential_url)
41
+ registry_uri = URI.parse(normalized_registry_url)
42
+
43
+ return -1 unless credential_uri.scheme == registry_uri.scheme
44
+ return -1 unless credential_uri.host == registry_uri.host
45
+ return -1 unless credential_uri.port == registry_uri.port
46
+
47
+ credential_path = normalized_uri_path(credential_uri)
48
+ registry_path = normalized_uri_path(registry_uri)
49
+
50
+ return 1 if credential_path == "/"
51
+
52
+ if registry_path.start_with?(credential_path.chomp("/") + "/")
53
+ credential_path.length
54
+ else
55
+ -1
56
+ end
57
+ rescue URI::InvalidURIError
58
+ -1
59
+ end
60
+
61
+ sig { params(url: String).returns(String) }
62
+ def normalize_index_url(url)
63
+ url.chomp("/")
64
+ end
65
+
66
+ sig { params(uri: URI::Generic).returns(String) }
67
+ def normalized_uri_path(uri)
68
+ path = uri.path.to_s
69
+ path.empty? ? "/" : path
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
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.370.0
4
+ version: 0.372.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
@@ -15,28 +15,28 @@ dependencies:
15
15
  requirements:
16
16
  - - '='
17
17
  - !ruby/object:Gem::Version
18
- version: 0.370.0
18
+ version: 0.372.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.370.0
25
+ version: 0.372.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: dependabot-python
28
28
  requirement: !ruby/object:Gem::Requirement
29
29
  requirements:
30
30
  - - '='
31
31
  - !ruby/object:Gem::Version
32
- version: 0.370.0
32
+ version: 0.372.0
33
33
  type: :runtime
34
34
  prerelease: false
35
35
  version_requirements: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - '='
38
38
  - !ruby/object:Gem::Version
39
- version: 0.370.0
39
+ version: 0.372.0
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: debug
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -273,6 +273,7 @@ files:
273
273
  - lib/dependabot/uv/file_updater/compile_file_updater.rb
274
274
  - lib/dependabot/uv/file_updater/lock_file_error_handler.rb
275
275
  - lib/dependabot/uv/file_updater/lock_file_updater.rb
276
+ - lib/dependabot/uv/file_updater/lock_index_credential_matcher.rb
276
277
  - lib/dependabot/uv/file_updater/pyproject_preparer.rb
277
278
  - lib/dependabot/uv/file_updater/requirement_file_updater.rb
278
279
  - lib/dependabot/uv/file_updater/requirement_replacer.rb
@@ -300,7 +301,7 @@ licenses:
300
301
  - MIT
301
302
  metadata:
302
303
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
303
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.370.0
304
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.372.0
304
305
  rdoc_options: []
305
306
  require_paths:
306
307
  - lib