dependabot-uv 0.351.0 → 0.352.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: f74cec4813c7f6b11b51b6f73a10db68327ca41a2737e469ba5d9ea3b4612bea
4
- data.tar.gz: e17b701d94aeafdca486c2303d23ea3b423eebbddd93d347ce1224160920cab5
3
+ metadata.gz: 2182d20a6869566befc86859bd0260cbe23c3ce48b128c95c82ec5713af9f25b
4
+ data.tar.gz: 0c7a49f6debe6d304cc07854636139d2504a9bd74baa1c72ff08a072b2ddea7c
5
5
  SHA512:
6
- metadata.gz: 32c427d81b22edb5d8b145ced9080a7fca9264e371da8f4a9ff5ca57c89b58f69179b4ade15620e24bb6a5d43194d959489d0c10942b050be8fb5e0c13327121
7
- data.tar.gz: 615a296656b8957f897e5b17e3f951b143579bbc08aa8e8c806928bcd3e3349e4f0e3a54f0dcf3b5449fa7c8b6a892677e9a865925ec1fb044094ee35f4de527
6
+ metadata.gz: ee6297977b3276e5d0661dfa1fc1400100a86dfacc0e916adef15ce504f9adb5707db9214c5ee017147202c8c2104333a9bf6c7f351fdd1ce8577e7b88d005ba
7
+ data.tar.gz: b71b17c588efbd34281a174f229657173f924cdba4194ebb8073a37b3e2b7e37cdeec7effa71da66807291f0d455f76d3da8e8ab2ff560b4e35cbdab60f6781a
@@ -32,7 +32,7 @@ def parse_pep621_pep735_dependencies(pyproject_path):
32
32
  next(iter(specifier_set)).operator in {"==", "==="}):
33
33
  return next(iter(specifier_set)).version
34
34
 
35
- def parse_requirement(entry, pyproject_path):
35
+ def parse_requirement(entry, pyproject_path, requirement_type=None):
36
36
  try:
37
37
  req = Requirement(entry)
38
38
  except InvalidRequirement as e:
@@ -46,14 +46,19 @@ def parse_pep621_pep735_dependencies(pyproject_path):
46
46
  "file": pyproject_path,
47
47
  "requirement": str(req.specifier),
48
48
  "extras": sorted(list(req.extras)),
49
+ "requirement_type": requirement_type,
49
50
  }
50
51
  return data
51
52
 
52
- def parse_toml_section_pep621_dependencies(pyproject_path, dependencies):
53
+ def parse_toml_section_pep621_dependencies(
54
+ pyproject_path, dependencies, requirement_type=None
55
+ ):
53
56
  requirement_packages = []
54
57
 
55
58
  for dependency in dependencies:
56
- parsed_dependency = parse_requirement(dependency, pyproject_path)
59
+ parsed_dependency = parse_requirement(
60
+ dependency, pyproject_path, requirement_type
61
+ )
57
62
  requirement_packages.append(parsed_dependency)
58
63
 
59
64
  return requirement_packages
@@ -75,7 +80,9 @@ def parse_pep621_pep735_dependencies(pyproject_path):
75
80
  for entry in dependencies:
76
81
  # Handle direct requirement
77
82
  if isinstance(entry, str):
78
- parsed_dependency = parse_requirement(entry, pyproject_path)
83
+ parsed_dependency = parse_requirement(
84
+ entry, pyproject_path, group_name
85
+ )
79
86
  requirement_packages.append(parsed_dependency)
80
87
  # Handle include-group directive
81
88
  elif isinstance(entry, dict) and "include-group" in entry:
@@ -128,7 +135,8 @@ def parse_pep621_pep735_dependencies(pyproject_path):
128
135
  if 'requires' in build_system_section:
129
136
  build_system_dependencies = parse_toml_section_pep621_dependencies(
130
137
  pyproject_path,
131
- build_system_section['requires']
138
+ build_system_section['requires'],
139
+ "build-system"
132
140
  )
133
141
  dependencies.extend(build_system_dependencies)
134
142
 
@@ -12,10 +12,12 @@ require "dependabot/uv/file_parser/python_requirement_parser"
12
12
  require "dependabot/uv/file_updater"
13
13
  require "dependabot/uv/native_helpers"
14
14
  require "dependabot/uv/name_normaliser"
15
+ require "dependabot/uv/requirement_suffix_helper"
15
16
 
16
17
  module Dependabot
17
18
  module Uv
18
19
  class FileUpdater
20
+ # rubocop:disable Metrics/ClassLength
19
21
  class LockFileUpdater
20
22
  extend T::Sig
21
23
 
@@ -73,6 +75,16 @@ module Dependabot
73
75
  T.must(dependencies.first)
74
76
  end
75
77
 
78
+ sig { returns(T::Boolean) }
79
+ def build_system_only_dependency?
80
+ return false unless dependency
81
+
82
+ groups = T.must(dependency).requirements.flat_map { |req| req[:groups] || [] }.compact.uniq
83
+ return false if groups.empty?
84
+
85
+ groups.all?("build-system")
86
+ end
87
+
76
88
  sig { returns(T::Array[Dependabot::DependencyFile]) }
77
89
  def fetch_updated_dependency_files
78
90
  return [] unless create_or_update_lock_file?
@@ -87,9 +99,10 @@ module Dependabot
87
99
  )
88
100
  end
89
101
 
90
- if lockfile
102
+ if lockfile && !build_system_only_dependency?
91
103
  # Use updated_lockfile_content which might raise if the lockfile doesn't change
92
104
  new_content = updated_lockfile_content
105
+
93
106
  raise "Expected lockfile to change!" if T.must(lockfile).content == new_content
94
107
 
95
108
  updated_files << updated_file(file: T.must(lockfile), content: new_content)
@@ -136,17 +149,23 @@ module Dependabot
136
149
  updated_content = content.gsub(regex) do
137
150
  captured_requirement = Regexp.last_match(2)
138
151
 
139
- if requirements_match?(T.must(captured_requirement), old_req)
152
+ requirement_body, suffix = RequirementSuffixHelper.split(T.must(captured_requirement))
153
+
154
+ next Regexp.last_match(0) unless old_req
155
+
156
+ if requirements_match?(T.must(requirement_body), old_req)
140
157
  replaced = true
141
- "#{Regexp.last_match(1)}#{new_req}#{Regexp.last_match(3)}"
158
+ "#{Regexp.last_match(1)}#{new_req}#{suffix}#{Regexp.last_match(3)}"
142
159
  else
143
160
  Regexp.last_match(0)
144
161
  end
145
162
  end
146
-
147
163
  unless replaced
148
164
  updated_content = content.sub(regex) do
149
- "#{Regexp.last_match(1)}#{new_req}#{Regexp.last_match(3)}"
165
+ captured_requirement = Regexp.last_match(2)
166
+ _, suffix = RequirementSuffixHelper.split(T.must(captured_requirement))
167
+
168
+ "#{Regexp.last_match(1)}#{new_req}#{suffix}#{Regexp.last_match(3)}"
150
169
  end
151
170
  end
152
171
 
@@ -155,11 +174,12 @@ module Dependabot
155
174
 
156
175
  sig { params(req1: String, req2: String).returns(T::Boolean) }
157
176
  def requirements_match?(req1, req2)
158
- normalize = lambda do |req|
159
- req.split(",").map(&:strip).sort.join(",")
160
- end
177
+ normalized_requirement(req1) == normalized_requirement(req2)
178
+ end
161
179
 
162
- normalize.call(req1) == normalize.call(req2)
180
+ sig { params(req: String).returns(String) }
181
+ def normalized_requirement(req)
182
+ req.split(",").map(&:strip).sort.join(",")
163
183
  end
164
184
 
165
185
  sig { returns(String) }
@@ -459,6 +479,7 @@ module Dependabot
459
479
  T.must(dependency).requirements.select { _1[:file].end_with?(*REQUIRED_FILES) }.any?
460
480
  end
461
481
  end
482
+ # rubocop:enable Metrics/ClassLength
462
483
  end
463
484
  end
464
485
  end
@@ -0,0 +1,29 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+
6
+ module Dependabot
7
+ module Uv
8
+ module RequirementSuffixHelper
9
+ extend T::Sig
10
+
11
+ REQUIREMENT_SUFFIX_REGEX = T.let(
12
+ Regexp.new(
13
+ "\\A(?<requirement>.*?)(?<suffix>\\s*(?:;|#).*)?\\z",
14
+ Regexp::MULTILINE
15
+ ).freeze,
16
+ Regexp
17
+ )
18
+
19
+ sig { params(segment: String).returns(T::Array[String]) }
20
+ def self.split(segment)
21
+ match = REQUIREMENT_SUFFIX_REGEX.match(segment)
22
+ requirement = match ? match[:requirement] : segment
23
+ suffix = match&.[](:suffix) || ""
24
+
25
+ [T.must(requirement).strip, suffix]
26
+ end
27
+ end
28
+ end
29
+ end
@@ -6,6 +6,7 @@ require "sorbet-runtime"
6
6
  require "dependabot/uv/version"
7
7
  require "dependabot/uv/requirement"
8
8
  require "dependabot/uv/update_checker"
9
+ require "dependabot/uv/update_checker/latest_version_finder"
9
10
 
10
11
  module Dependabot
11
12
  module Uv
@@ -18,14 +19,25 @@ module Dependabot
18
19
  dependency: Dependabot::Dependency,
19
20
  dependency_files: T::Array[Dependabot::DependencyFile],
20
21
  credentials: T::Array[Dependabot::Credential],
21
- repo_contents_path: T.nilable(String)
22
+ repo_contents_path: T.nilable(String),
23
+ security_advisories: T::Array[Dependabot::SecurityAdvisory],
24
+ ignored_versions: T::Array[String]
22
25
  ).void
23
26
  end
24
- def initialize(dependency:, dependency_files:, credentials:, repo_contents_path: nil)
27
+ def initialize(
28
+ dependency:,
29
+ dependency_files:,
30
+ credentials:,
31
+ repo_contents_path: nil,
32
+ security_advisories: [],
33
+ ignored_versions: []
34
+ )
25
35
  @dependency = dependency
26
36
  @dependency_files = dependency_files
27
37
  @credentials = credentials
28
38
  @repo_contents_path = repo_contents_path
39
+ @security_advisories = security_advisories
40
+ @ignored_versions = ignored_versions
29
41
  end
30
42
 
31
43
  sig { params(requirement: T.nilable(String)).returns(T.nilable(Dependabot::Uv::Version)) }
@@ -50,7 +62,12 @@ module Dependabot
50
62
 
51
63
  sig { returns(T.nilable(Dependabot::Uv::Version)) }
52
64
  def lowest_resolvable_security_fix_version
53
- nil
65
+ # Delegate to LatestVersionFinder which handles security advisory filtering
66
+ fix_version = latest_version_finder.lowest_security_fix_version
67
+ return nil if fix_version.nil?
68
+
69
+ # Return the fix version cast to Uv::Version
70
+ Uv::Version.new(fix_version.to_s)
54
71
  end
55
72
 
56
73
  private
@@ -66,6 +83,27 @@ module Dependabot
66
83
 
67
84
  sig { returns(T.nilable(String)) }
68
85
  attr_reader :repo_contents_path
86
+
87
+ sig { returns(T::Array[Dependabot::SecurityAdvisory]) }
88
+ attr_reader :security_advisories
89
+
90
+ sig { returns(T::Array[String]) }
91
+ attr_reader :ignored_versions
92
+
93
+ sig { returns(LatestVersionFinder) }
94
+ def latest_version_finder
95
+ @latest_version_finder ||= T.let(
96
+ LatestVersionFinder.new(
97
+ dependency: dependency,
98
+ dependency_files: dependency_files,
99
+ credentials: credentials,
100
+ ignored_versions: ignored_versions,
101
+ security_advisories: security_advisories,
102
+ raise_on_ignored: false
103
+ ),
104
+ T.nilable(LatestVersionFinder)
105
+ )
106
+ end
69
107
  end
70
108
  end
71
109
  end
@@ -127,7 +127,12 @@ module Dependabot
127
127
  fix_version = lowest_security_fix_version
128
128
  return latest_resolvable_version if fix_version.nil?
129
129
 
130
- return resolver.lowest_resolvable_security_fix_version if resolver_type == :requirements
130
+ # For requirements and lock_file resolver types, delegate to the resolver
131
+ if resolver_type == :requirements || resolver_type == :lock_file
132
+ resolved_fix = resolver.lowest_resolvable_security_fix_version
133
+ # If no security fix version is found, fall back to latest_resolvable_version
134
+ return resolved_fix || latest_resolvable_version
135
+ end
131
136
 
132
137
  resolver.resolvable?(version: fix_version) ? fix_version : nil
133
138
  end
@@ -216,7 +221,9 @@ module Dependabot
216
221
  dependency: dependency,
217
222
  dependency_files: dependency_files,
218
223
  credentials: credentials,
219
- repo_contents_path: repo_contents_path
224
+ repo_contents_path: repo_contents_path,
225
+ security_advisories: security_advisories,
226
+ ignored_versions: ignored_versions
220
227
  ),
221
228
  T.nilable(LockFileResolver)
222
229
  )
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.351.0
4
+ version: 0.352.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.351.0
18
+ version: 0.352.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.351.0
25
+ version: 0.352.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.351.0
32
+ version: 0.352.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.351.0
39
+ version: 0.352.0
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: debug
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -282,6 +282,7 @@ files:
282
282
  - lib/dependabot/uv/package_manager.rb
283
283
  - lib/dependabot/uv/requirement.rb
284
284
  - lib/dependabot/uv/requirement_parser.rb
285
+ - lib/dependabot/uv/requirement_suffix_helper.rb
285
286
  - lib/dependabot/uv/requirements_file_matcher.rb
286
287
  - lib/dependabot/uv/update_checker.rb
287
288
  - lib/dependabot/uv/update_checker/latest_version_finder.rb
@@ -295,7 +296,7 @@ licenses:
295
296
  - MIT
296
297
  metadata:
297
298
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
298
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.351.0
299
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.352.0
299
300
  rdoc_options: []
300
301
  require_paths:
301
302
  - lib