dependabot-uv 0.361.1 → 0.361.2

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: f865148cffa8d91b9ba83af41241852f7b98c3da1b07584e88bc5c6549f53c58
4
- data.tar.gz: a28f399323f96cd94c42b9095daa1e92bc411168eb7b35ef01a7931bddc5e459
3
+ metadata.gz: a7e6fc7ea7c65eda2ec37cb76fc3069372232587e8bab6e0b66905d6703086c2
4
+ data.tar.gz: a59ef842182d8f30f194f1a7303aa55b1740753e7f64d4ccf5e07a29abd91861
5
5
  SHA512:
6
- metadata.gz: d161b78f65db1f90cea84951489430a03f7f025ae5011521fa0667dd19e17f2b5b4a120831e413ece2d6e23a7129e5fdb68553cc1355de1bdc323e0e4704b964
7
- data.tar.gz: f520f88f03625f96260672f413dcb42400a0e468f6015aa9074dba07cdadda29e8961e0eb87dc85f327d1ad4ec2ec9acbf34fc745fbe4ff25298cb6d6d3b0b0d
6
+ metadata.gz: 6d1fe91ffcd369acdcf37f8b7cdce64f8d2f1cce66a8fcf4033015ea157124d4dca96dc28fd346a1d6291aeb64fbf2bb6a4b38d9d32e674cd613558e73dcd0e5
7
+ data.tar.gz: 01a78ecaf7d193113aaf76bcabbbca7888ab9666ea30cae81cb40b0368f24eb3109c63e328c6e3262df1bf64c3f0502ebfed3452e759129cc78da2304edbd878
@@ -24,6 +24,7 @@ module Dependabot
24
24
 
25
25
  require_relative "requirement_replacer"
26
26
  require_relative "requirement_file_updater"
27
+ require_relative "lock_file_error_handler"
27
28
 
28
29
  UNSAFE_PACKAGES = T.let(%w(setuptools distribute pip).freeze, T::Array[String])
29
30
  INCOMPATIBLE_VERSIONS_REGEX = T.let(
@@ -154,7 +155,7 @@ module Dependabot
154
155
  retry
155
156
  end
156
157
 
157
- raise
158
+ error_handler.handle_uv_error(e)
158
159
  end
159
160
 
160
161
  sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(T::Boolean) }
@@ -228,7 +229,7 @@ module Dependabot
228
229
  raise DependencyFileNotResolvable, stdout.match(INCOMPATIBLE_VERSIONS_REGEX)
229
230
  end
230
231
 
231
- raise
232
+ error_handler.handle_uv_error(e)
232
233
  end
233
234
 
234
235
  sig { params(command: String, fingerprint: String, allow_unsafe_shell_command: T::Boolean).returns(String) }
@@ -261,6 +262,11 @@ module Dependabot
261
262
  env
262
263
  end
263
264
 
265
+ sig { returns(LockFileErrorHandler) }
266
+ def error_handler
267
+ @error_handler ||= T.let(LockFileErrorHandler.new, T.nilable(LockFileErrorHandler))
268
+ end
269
+
264
270
  sig { void }
265
271
  def write_updated_dependency_files
266
272
  dependency_files.each do |file|
@@ -20,12 +20,20 @@ module Dependabot
20
20
  /Did not find branch or tag '(?<tag>[^\n"']+)'/m,
21
21
  Regexp
22
22
  )
23
+ GIT_CREDENTIALS_ERROR_REGEX = T.let(
24
+ /could not read Username for '(?<url>[^']+)'/,
25
+ Regexp
26
+ )
27
+ GIT_DEPENDENCY_URL_FROM_UV_REGEX = T.let(
28
+ %r{git\+(?<url>https?://[^\s@#]+)},
29
+ Regexp
30
+ )
23
31
  PYTHON_VERSION_ERROR_REGEX = T.let(
24
32
  /Requires-Python|requires-python|python_requires|Python version/i,
25
33
  Regexp
26
34
  )
27
35
  AUTH_ERROR_REGEX = T.let(
28
- /401|403|authentication|unauthorized|forbidden|HTTP status code: 40[13]/i,
36
+ /authentication|unauthorized|forbidden|HTTP status code: 40[13]/i,
29
37
  Regexp
30
38
  )
31
39
  TIMEOUT_ERROR_REGEX = T.let(
@@ -33,7 +41,15 @@ module Dependabot
33
41
  Regexp
34
42
  )
35
43
  NETWORK_ERROR_REGEX = T.let(
36
- /ConnectionError|NetworkError|SSLError|certificate verify failed/i,
44
+ Regexp.union(
45
+ /ConnectionError/i,
46
+ /NetworkError/i,
47
+ /SSLError/i,
48
+ /certificate verify failed/i,
49
+ /connection refused/i,
50
+ /dns.*failed/i,
51
+ /error sending request/i
52
+ ),
37
53
  Regexp
38
54
  )
39
55
  PACKAGE_NOT_FOUND_REGEX = T.let(
@@ -44,6 +60,36 @@ module Dependabot
44
60
  /Required uv version `(?<required>[^`]+)` does not match the running version `(?<running>[^`]+)`/,
45
61
  Regexp
46
62
  )
63
+ TOML_PARSE_ERROR_REGEX = T.let(
64
+ /Failed to parse:?\s*`?(?<file>[^`\n]+\.toml)`?|TOML parse error/i,
65
+ Regexp
66
+ )
67
+ PYPROJECT_SCHEMA_ERROR_REGEX = T.let(
68
+ /missing field `project`|missing.*\[project\].*table|Field `project\.name` is required/i,
69
+ Regexp
70
+ )
71
+ WORKSPACE_MEMBER_ERROR_REGEX = T.let(
72
+ /Failed to find workspace member|No `pyproject\.toml` found in workspace member/i,
73
+ Regexp
74
+ )
75
+ PATH_DEPENDENCY_ERROR_REGEX = T.let(
76
+ /Failed to read `(?<path>[^`]+)`|failed to read from file `(?<path>[^`]+)`/i,
77
+ Regexp
78
+ )
79
+ HTTP_STATUS_ERROR_REGEX = T.let(
80
+ /HTTP status code: (?<code>\d{3})/i,
81
+ Regexp
82
+ )
83
+ UV_MISCONFIGURED_REGEX = T.let(
84
+ Regexp.union(
85
+ /unknown field `[^`]+`, expected one of/i,
86
+ /Unrecognized.*value:/i,
87
+ /URL scheme `[^`]+` is not supported/i,
88
+ /Failed to parse URL/i,
89
+ /the argument '--[^']+' cannot be used/i
90
+ ),
91
+ Regexp
92
+ )
47
93
 
48
94
  # Maximum number of lines to include in cleaned error messages.
49
95
  # This limit ensures error messages remain readable while providing enough
@@ -56,6 +102,7 @@ module Dependabot
56
102
  message = error.message
57
103
 
58
104
  handle_required_version_errors(message)
105
+ handle_pyproject_errors(message)
59
106
  handle_resolution_errors(message)
60
107
  handle_git_errors(message)
61
108
  handle_authentication_errors(message)
@@ -80,6 +127,53 @@ module Dependabot
80
127
  )
81
128
  end
82
129
 
130
+ sig { params(message: String).void }
131
+ def handle_pyproject_errors(message)
132
+ handle_toml_parse_errors(message)
133
+ handle_pyproject_schema_errors(message)
134
+ handle_workspace_member_errors(message)
135
+ handle_path_dependency_errors(message)
136
+ handle_uv_misconfiguration_errors(message)
137
+ end
138
+
139
+ sig { params(message: String).void }
140
+ def handle_toml_parse_errors(message)
141
+ return unless message.match?(TOML_PARSE_ERROR_REGEX)
142
+
143
+ match = message.match(TOML_PARSE_ERROR_REGEX)
144
+ file_path = match&.named_captures&.fetch("file", nil) || "pyproject.toml"
145
+ raise Dependabot::DependencyFileNotParseable, file_path
146
+ end
147
+
148
+ sig { params(message: String).void }
149
+ def handle_pyproject_schema_errors(message)
150
+ return unless message.match?(PYPROJECT_SCHEMA_ERROR_REGEX)
151
+
152
+ raise Dependabot::DependencyFileNotParseable, "pyproject.toml"
153
+ end
154
+
155
+ sig { params(message: String).void }
156
+ def handle_workspace_member_errors(message)
157
+ return unless message.match?(WORKSPACE_MEMBER_ERROR_REGEX)
158
+
159
+ raise Dependabot::DependencyFileNotResolvable, clean_error_message(message)
160
+ end
161
+
162
+ sig { params(message: String).void }
163
+ def handle_path_dependency_errors(message)
164
+ return unless (match = message.match(PATH_DEPENDENCY_ERROR_REGEX))
165
+
166
+ path = match.named_captures.fetch("path")
167
+ raise Dependabot::PathDependenciesNotReachable, T.must(path)
168
+ end
169
+
170
+ sig { params(message: String).void }
171
+ def handle_uv_misconfiguration_errors(message)
172
+ return unless message.match?(UV_MISCONFIGURED_REGEX)
173
+
174
+ raise Dependabot::MisconfiguredTooling.new("uv", clean_error_message(message))
175
+ end
176
+
83
177
  sig { params(message: String).void }
84
178
  def handle_resolution_errors(message)
85
179
  return unless message.include?("No solution found when resolving dependencies") ||
@@ -103,8 +197,6 @@ module Dependabot
103
197
 
104
198
  sig { params(error_message: String).returns(T::Array[String]) }
105
199
  def extract_conflicting_dependencies(error_message)
106
- # Extract conflicting dependency names from the error message
107
- # Pattern: "Because <pkg>==<ver> depends on <dep>>=<ver> and your project depends on <dep>==<ver>"
108
200
  normalized_message = error_message.gsub(/\s+/, " ")
109
201
  conflict_pattern = /Because (\S+)==\S+ depends on (\S+)[><=!]+\S+ and your project depends on \2==\S+/
110
202
 
@@ -121,12 +213,26 @@ module Dependabot
121
213
  raise Dependabot::GitDependencyReferenceNotFound, "(unknown package at #{tag})"
122
214
  end
123
215
 
124
- return unless (match = message.match(GIT_DEPENDENCY_UNREACHABLE_REGEX))
216
+ if (match = message.match(GIT_DEPENDENCY_UNREACHABLE_REGEX))
217
+ url = match.named_captures.fetch("url")
218
+ raise Dependabot::GitDependenciesNotReachable, T.must(url)
219
+ end
220
+
221
+ return unless message.match?(GIT_CREDENTIALS_ERROR_REGEX)
125
222
 
126
- url = match.named_captures.fetch("url")
223
+ url = extract_git_url_from_message(message)
127
224
  raise Dependabot::GitDependenciesNotReachable, T.must(url)
128
225
  end
129
226
 
227
+ sig { params(message: String).returns(T.nilable(String)) }
228
+ def extract_git_url_from_message(message)
229
+ if (url_match = message.match(GIT_DEPENDENCY_URL_FROM_UV_REGEX))
230
+ return url_match.named_captures.fetch("url")
231
+ end
232
+
233
+ message.match(GIT_CREDENTIALS_ERROR_REGEX)&.named_captures&.fetch("url")
234
+ end
235
+
130
236
  sig { params(message: String).void }
131
237
  def handle_authentication_errors(message)
132
238
  return unless message.match?(AUTH_ERROR_REGEX)
@@ -137,6 +243,8 @@ module Dependabot
137
243
 
138
244
  sig { params(message: String).void }
139
245
  def handle_network_errors(message)
246
+ handle_http_status_errors(message)
247
+
140
248
  if message.match?(TIMEOUT_ERROR_REGEX)
141
249
  source = extract_source_from_message(message)
142
250
  raise Dependabot::PrivateSourceTimedOut, source
@@ -153,6 +261,17 @@ module Dependabot
153
261
  "Network error while resolving dependencies: #{clean_error_message(message)}"
154
262
  end
155
263
 
264
+ sig { params(message: String).void }
265
+ def handle_http_status_errors(message)
266
+ return unless (match = message.match(HTTP_STATUS_ERROR_REGEX))
267
+
268
+ code = match.named_captures.fetch("code").to_i
269
+ source = extract_source_from_message(message)
270
+ return if code >= 400 && code < 404 # already handled by AUTH_ERROR_REGEX
271
+
272
+ raise Dependabot::PrivateSourceBadResponse, source if code >= 400
273
+ end
274
+
156
275
  sig { params(message: String).void }
157
276
  def handle_python_version_errors(message)
158
277
  return unless message.match?(PYTHON_VERSION_ERROR_REGEX)
@@ -27,14 +27,6 @@ module Dependabot
27
27
 
28
28
  REQUIRED_FILES = %w(pyproject.toml uv.lock).freeze # At least one of these files should be present
29
29
 
30
- UV_UNRESOLVABLE_REGEX = T.let(/× No solution found when resolving dependencies.*[\s\S]*$/, Regexp)
31
- RESOLUTION_IMPOSSIBLE_ERROR = T.let("ResolutionImpossible", String)
32
- UV_BUILD_FAILED_REGEX = T.let(/× Failed to build.*[\s\S]*$/, Regexp)
33
- UV_REQUIRED_VERSION_REGEX = T.let(
34
- /Required uv version `(?<required>[^`]+)` does not match the running version `(?<running>[^`]+)`/,
35
- Regexp
36
- )
37
-
38
30
  sig { returns(T::Array[Dependency]) }
39
31
  attr_reader :dependencies
40
32
 
@@ -270,43 +262,6 @@ module Dependabot
270
262
  error_handler.handle_uv_error(e)
271
263
  end
272
264
 
273
- sig { params(error_message: String).returns(T::Boolean) }
274
- def resolution_error?(error_message)
275
- ["No solution found when resolving dependencies", "Failed to build"].any? do |pattern|
276
- error_message.include?(pattern)
277
- end
278
- end
279
-
280
- sig { params(error_message: String).returns(T.noreturn) }
281
- def handle_resolution_error(error_message)
282
- match_unresolvable = error_message.scan(UV_UNRESOLVABLE_REGEX).last
283
- match_build_failed = error_message.scan(UV_BUILD_FAILED_REGEX).last
284
-
285
- if match_unresolvable
286
- formatted_error = Array(match_unresolvable).join
287
- conflicting_deps = extract_conflicting_dependencies(formatted_error)
288
- raise Dependabot::UpdateNotPossible, conflicting_deps if conflicting_deps.any?
289
-
290
- raise Dependabot::DependencyFileNotResolvable, formatted_error
291
- end
292
-
293
- formatted_error = match_build_failed ? Array(match_build_failed).join : error_message
294
- raise Dependabot::DependencyFileNotResolvable, formatted_error
295
- end
296
-
297
- sig { params(error_message: String).returns(T::Array[String]) }
298
- def extract_conflicting_dependencies(error_message)
299
- # Extract conflicting dependency names from the error message
300
- # Pattern: "Because <pkg>==<ver> depends on <dep>>=<ver> and your project depends on <dep>==<ver>"
301
- normalized_message = error_message.gsub(/\s+/, " ")
302
- conflict_pattern = /Because (\S+)==\S+ depends on (\S+)[><=!]+\S+ and your project depends on \2==\S+/
303
-
304
- match = normalized_message.match(conflict_pattern)
305
- return [] unless match
306
-
307
- [T.must(match[1]), T.must(match[2])].uniq
308
- end
309
-
310
265
  sig { returns(LockFileErrorHandler) }
311
266
  def error_handler
312
267
  @error_handler ||= T.let(LockFileErrorHandler.new, T.nilable(LockFileErrorHandler))
@@ -30,6 +30,14 @@ module Dependabot
30
30
 
31
31
  GIT_DEPENDENCY_UNREACHABLE_REGEX = T.let(/git clone --filter=blob:none --quiet (?<url>[^\s]+).* /, Regexp)
32
32
  GIT_REFERENCE_NOT_FOUND_REGEX = T.let(/Did not find branch or tag '(?<tag>[^\n"]+)'/m, Regexp)
33
+ GIT_CREDENTIALS_ERROR_REGEX = T.let(
34
+ /could not read Username for '(?<url>[^']+)'/,
35
+ Regexp
36
+ )
37
+ GIT_DEPENDENCY_URL_FROM_UV_REGEX = T.let(
38
+ %r{git\+(?<url>https?://[^\s@#]+)},
39
+ Regexp
40
+ )
33
41
  NATIVE_COMPILATION_ERROR = T.let(
34
42
  "pip._internal.exceptions.InstallationSubprocessError: Getting requirements to build wheel exited with 1",
35
43
  String
@@ -210,6 +218,7 @@ module Dependabot
210
218
  .named_captures.fetch("url")
211
219
  raise GitDependenciesNotReachable, T.must(url)
212
220
  end
221
+ handle_git_credentials_error(message)
213
222
 
214
223
  raise Dependabot::OutOfDisk if message.end_with?("[Errno 28] No space left on device")
215
224
 
@@ -430,6 +439,25 @@ module Dependabot
430
439
  T.must(T.cast(message.scan(ERROR_REGEX), T::Array[String]).last)
431
440
  end
432
441
 
442
+ sig { params(message: String).returns(T.nilable(String)) }
443
+ def extract_git_url_from_message(message)
444
+ # Try to extract the full repository URL from UV's git dependency reference (git+https://...)
445
+ if (url_match = message.match(GIT_DEPENDENCY_URL_FROM_UV_REGEX))
446
+ return url_match.named_captures.fetch("url")
447
+ end
448
+
449
+ # Fall back to the URL from the "could not read Username" error
450
+ message.match(GIT_CREDENTIALS_ERROR_REGEX)&.named_captures&.fetch("url")
451
+ end
452
+
453
+ sig { params(message: String).void }
454
+ def handle_git_credentials_error(message)
455
+ return unless message.match?(GIT_CREDENTIALS_ERROR_REGEX)
456
+
457
+ url = extract_git_url_from_message(message)
458
+ raise GitDependenciesNotReachable, T.must(url)
459
+ end
460
+
433
461
  sig { returns(T::Array[String]) }
434
462
  def filenames_to_compile
435
463
  files_from_reqs =
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.361.1
4
+ version: 0.361.2
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.361.1
18
+ version: 0.361.2
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.361.1
25
+ version: 0.361.2
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.361.1
32
+ version: 0.361.2
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.361.1
39
+ version: 0.361.2
40
40
  - !ruby/object:Gem::Dependency
41
41
  name: debug
42
42
  requirement: !ruby/object:Gem::Requirement
@@ -299,7 +299,7 @@ licenses:
299
299
  - MIT
300
300
  metadata:
301
301
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
302
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.361.1
302
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.361.2
303
303
  rdoc_options: []
304
304
  require_paths:
305
305
  - lib