dependabot-uv 0.359.0 → 0.360.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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9ac9ccc655f8d74cd2b9ffc95c37a012bd74815ddc749117a241b1e200bfd4e7
|
|
4
|
+
data.tar.gz: a28f399323f96cd94c42b9095daa1e92bc411168eb7b35ef01a7931bddc5e459
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c434e3666e41e2f75cb4be56e13a9f005c8594a16e288405b0c0f234f95b4ce4a95a75d1abae351dfd5f28802ed856fdfccabecc564c94ea1bdadb29c8e4d23f
|
|
7
|
+
data.tar.gz: f520f88f03625f96260672f413dcb42400a0e468f6015aa9074dba07cdadda29e8961e0eb87dc85f327d1ad4ec2ec9acbf34fc745fbe4ff25298cb6d6d3b0b0d
|
|
@@ -321,7 +321,7 @@ module Dependabot
|
|
|
321
321
|
params(
|
|
322
322
|
dir: T.nilable(String),
|
|
323
323
|
raise_errors: T::Boolean
|
|
324
|
-
).returns(T::Array[
|
|
324
|
+
).returns(T::Array[Dependabot::FileFetchers::RepositoryContent])
|
|
325
325
|
end
|
|
326
326
|
def repo_contents(dir: nil, raise_errors: true)
|
|
327
327
|
@file_fetcher.send(:repo_contents, dir: dir, raise_errors: raise_errors)
|
|
@@ -272,11 +272,11 @@ module Dependabot
|
|
|
272
272
|
@req_txt_and_in_files
|
|
273
273
|
end
|
|
274
274
|
|
|
275
|
-
sig { params(requirements_dir:
|
|
275
|
+
sig { params(requirements_dir: Dependabot::FileFetchers::RepositoryContent).returns(T::Array[Dependabot::DependencyFile]) }
|
|
276
276
|
def req_files_for_dir(requirements_dir)
|
|
277
277
|
dir = directory.gsub(%r{(^/|/$)}, "")
|
|
278
278
|
relative_reqs_dir =
|
|
279
|
-
|
|
279
|
+
requirements_dir.path&.gsub(%r{^/?#{Regexp.escape(dir)}/?}, "")
|
|
280
280
|
|
|
281
281
|
fetch_requirement_files_from_path(relative_reqs_dir)
|
|
282
282
|
end
|
|
@@ -327,7 +327,7 @@ module Dependabot
|
|
|
327
327
|
|
|
328
328
|
sig do
|
|
329
329
|
params(
|
|
330
|
-
contents: T::Array[
|
|
330
|
+
contents: T::Array[Dependabot::FileFetchers::RepositoryContent],
|
|
331
331
|
base_path: T.nilable(T.any(Pathname, String))
|
|
332
332
|
).returns(T::Array[Dependabot::DependencyFile])
|
|
333
333
|
end
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# typed: strict
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require "dependabot/errors"
|
|
5
|
+
require "dependabot/utils"
|
|
6
|
+
require "dependabot/uv/file_updater"
|
|
7
|
+
|
|
8
|
+
module Dependabot
|
|
9
|
+
module Uv
|
|
10
|
+
class FileUpdater < Dependabot::FileUpdaters::Base
|
|
11
|
+
class LockFileErrorHandler
|
|
12
|
+
extend T::Sig
|
|
13
|
+
|
|
14
|
+
UV_UNRESOLVABLE_REGEX = T.let(/× No solution found when resolving dependencies.*[\s\S]*$/, Regexp)
|
|
15
|
+
UV_BUILD_FAILED_REGEX = T.let(/× Failed to build.*[\s\S]*$/, Regexp)
|
|
16
|
+
RESOLUTION_IMPOSSIBLE_ERROR = T.let("ResolutionImpossible", String)
|
|
17
|
+
|
|
18
|
+
GIT_DEPENDENCY_UNREACHABLE_REGEX = T.let(%r{git clone.*(?<url>https?://[^\s]+)}, Regexp)
|
|
19
|
+
GIT_REFERENCE_NOT_FOUND_REGEX = T.let(
|
|
20
|
+
/Did not find branch or tag '(?<tag>[^\n"']+)'/m,
|
|
21
|
+
Regexp
|
|
22
|
+
)
|
|
23
|
+
PYTHON_VERSION_ERROR_REGEX = T.let(
|
|
24
|
+
/Requires-Python|requires-python|python_requires|Python version/i,
|
|
25
|
+
Regexp
|
|
26
|
+
)
|
|
27
|
+
AUTH_ERROR_REGEX = T.let(
|
|
28
|
+
/401|403|authentication|unauthorized|forbidden|HTTP status code: 40[13]/i,
|
|
29
|
+
Regexp
|
|
30
|
+
)
|
|
31
|
+
TIMEOUT_ERROR_REGEX = T.let(
|
|
32
|
+
/timed?\s*out|connection.*reset|read timeout|connect timeout/i,
|
|
33
|
+
Regexp
|
|
34
|
+
)
|
|
35
|
+
NETWORK_ERROR_REGEX = T.let(
|
|
36
|
+
/ConnectionError|NetworkError|SSLError|certificate verify failed/i,
|
|
37
|
+
Regexp
|
|
38
|
+
)
|
|
39
|
+
PACKAGE_NOT_FOUND_REGEX = T.let(
|
|
40
|
+
/No matching distribution found|package.*not found|No versions found/i,
|
|
41
|
+
Regexp
|
|
42
|
+
)
|
|
43
|
+
UV_REQUIRED_VERSION_REGEX = T.let(
|
|
44
|
+
/Required uv version `(?<required>[^`]+)` does not match the running version `(?<running>[^`]+)`/,
|
|
45
|
+
Regexp
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Maximum number of lines to include in cleaned error messages.
|
|
49
|
+
# This limit ensures error messages remain readable while providing enough
|
|
50
|
+
# context for debugging. Most uv error messages convey the key information
|
|
51
|
+
# within the first few lines.
|
|
52
|
+
MAX_ERROR_LINES = T.let(10, Integer)
|
|
53
|
+
|
|
54
|
+
sig { params(error: SharedHelpers::HelperSubprocessFailed).returns(T.noreturn) }
|
|
55
|
+
def handle_uv_error(error)
|
|
56
|
+
message = error.message
|
|
57
|
+
|
|
58
|
+
handle_required_version_errors(message)
|
|
59
|
+
handle_resolution_errors(message)
|
|
60
|
+
handle_git_errors(message)
|
|
61
|
+
handle_authentication_errors(message)
|
|
62
|
+
handle_network_errors(message)
|
|
63
|
+
handle_python_version_errors(message)
|
|
64
|
+
handle_resource_errors(message)
|
|
65
|
+
handle_package_not_found_errors(message)
|
|
66
|
+
|
|
67
|
+
raise error
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
sig { params(message: String).void }
|
|
73
|
+
def handle_required_version_errors(message)
|
|
74
|
+
return unless (version_match = message.match(UV_REQUIRED_VERSION_REGEX))
|
|
75
|
+
|
|
76
|
+
raise Dependabot::ToolVersionNotSupported.new(
|
|
77
|
+
"uv",
|
|
78
|
+
T.must(version_match[:required]),
|
|
79
|
+
T.must(version_match[:running])
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
sig { params(message: String).void }
|
|
84
|
+
def handle_resolution_errors(message)
|
|
85
|
+
return unless message.include?("No solution found when resolving dependencies") ||
|
|
86
|
+
message.include?("Failed to build") ||
|
|
87
|
+
message.include?(RESOLUTION_IMPOSSIBLE_ERROR)
|
|
88
|
+
|
|
89
|
+
match_unresolvable = message.scan(UV_UNRESOLVABLE_REGEX).last
|
|
90
|
+
match_build_failed = message.scan(UV_BUILD_FAILED_REGEX).last
|
|
91
|
+
|
|
92
|
+
if match_unresolvable
|
|
93
|
+
formatted_error = extract_match_string(match_unresolvable) || message
|
|
94
|
+
conflicting_deps = extract_conflicting_dependencies(formatted_error)
|
|
95
|
+
raise Dependabot::UpdateNotPossible, conflicting_deps if conflicting_deps.any?
|
|
96
|
+
|
|
97
|
+
raise Dependabot::DependencyFileNotResolvable, formatted_error
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
formatted_error = extract_match_string(match_build_failed) || message
|
|
101
|
+
raise Dependabot::DependencyFileNotResolvable, formatted_error
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
sig { params(error_message: String).returns(T::Array[String]) }
|
|
105
|
+
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
|
+
normalized_message = error_message.gsub(/\s+/, " ")
|
|
109
|
+
conflict_pattern = /Because (\S+)==\S+ depends on (\S+)[><=!]+\S+ and your project depends on \2==\S+/
|
|
110
|
+
|
|
111
|
+
match = normalized_message.match(conflict_pattern)
|
|
112
|
+
return [] unless match
|
|
113
|
+
|
|
114
|
+
[T.must(match[1]), T.must(match[2])].uniq
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
sig { params(message: String).void }
|
|
118
|
+
def handle_git_errors(message)
|
|
119
|
+
if (match = message.match(GIT_REFERENCE_NOT_FOUND_REGEX))
|
|
120
|
+
tag = match.named_captures.fetch("tag")
|
|
121
|
+
raise Dependabot::GitDependencyReferenceNotFound, "(unknown package at #{tag})"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
return unless (match = message.match(GIT_DEPENDENCY_UNREACHABLE_REGEX))
|
|
125
|
+
|
|
126
|
+
url = match.named_captures.fetch("url")
|
|
127
|
+
raise Dependabot::GitDependenciesNotReachable, T.must(url)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
sig { params(message: String).void }
|
|
131
|
+
def handle_authentication_errors(message)
|
|
132
|
+
return unless message.match?(AUTH_ERROR_REGEX)
|
|
133
|
+
|
|
134
|
+
source = extract_source_from_message(message)
|
|
135
|
+
raise Dependabot::PrivateSourceAuthenticationFailure, source
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
sig { params(message: String).void }
|
|
139
|
+
def handle_network_errors(message)
|
|
140
|
+
if message.match?(TIMEOUT_ERROR_REGEX)
|
|
141
|
+
source = extract_source_from_message(message)
|
|
142
|
+
raise Dependabot::PrivateSourceTimedOut, source
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
return unless message.match?(NETWORK_ERROR_REGEX)
|
|
146
|
+
|
|
147
|
+
source = extract_source_from_message(message)
|
|
148
|
+
if message.include?("certificate verify failed") || message.include?("SSLError")
|
|
149
|
+
raise Dependabot::PrivateSourceCertificateFailure, source
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
raise Dependabot::DependencyFileNotResolvable,
|
|
153
|
+
"Network error while resolving dependencies: #{clean_error_message(message)}"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
sig { params(message: String).void }
|
|
157
|
+
def handle_python_version_errors(message)
|
|
158
|
+
return unless message.match?(PYTHON_VERSION_ERROR_REGEX)
|
|
159
|
+
|
|
160
|
+
raise Dependabot::DependencyFileNotResolvable,
|
|
161
|
+
"Python version incompatibility: #{clean_error_message(message)}"
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
sig { params(message: String).void }
|
|
165
|
+
def handle_resource_errors(message)
|
|
166
|
+
raise Dependabot::OutOfDisk if message.include?("[Errno 28] No space left on device")
|
|
167
|
+
raise Dependabot::OutOfMemory if message.include?("MemoryError")
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
sig { params(message: String).void }
|
|
171
|
+
def handle_package_not_found_errors(message)
|
|
172
|
+
return unless message.match?(PACKAGE_NOT_FOUND_REGEX)
|
|
173
|
+
|
|
174
|
+
raise Dependabot::DependencyFileNotResolvable, clean_error_message(message)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
sig { params(match: T.untyped).returns(T.nilable(String)) }
|
|
178
|
+
def extract_match_string(match)
|
|
179
|
+
return nil unless match
|
|
180
|
+
|
|
181
|
+
match.is_a?(Array) ? match.join : match.to_s
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
sig { params(message: String).returns(String) }
|
|
185
|
+
def extract_source_from_message(message)
|
|
186
|
+
urls = URI.extract(message, %w(http https))
|
|
187
|
+
return T.must(urls.first).gsub(%r{/$}, "") if urls.any?
|
|
188
|
+
|
|
189
|
+
"private source"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
sig { params(message: String).returns(String) }
|
|
193
|
+
def clean_error_message(message)
|
|
194
|
+
message
|
|
195
|
+
.gsub(/#{Regexp.escape(Utils::BUMP_TMP_DIR_PATH)}[^\s]*/o, "")
|
|
196
|
+
.lines
|
|
197
|
+
.reject { |line| line.strip.empty? }
|
|
198
|
+
.first(MAX_ERROR_LINES)
|
|
199
|
+
.join
|
|
200
|
+
.strip
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
@@ -23,12 +23,17 @@ module Dependabot
|
|
|
23
23
|
|
|
24
24
|
require_relative "pyproject_preparer"
|
|
25
25
|
require_relative "version_config_parser"
|
|
26
|
+
require_relative "lock_file_error_handler"
|
|
26
27
|
|
|
27
28
|
REQUIRED_FILES = %w(pyproject.toml uv.lock).freeze # At least one of these files should be present
|
|
28
29
|
|
|
29
30
|
UV_UNRESOLVABLE_REGEX = T.let(/× No solution found when resolving dependencies.*[\s\S]*$/, Regexp)
|
|
30
31
|
RESOLUTION_IMPOSSIBLE_ERROR = T.let("ResolutionImpossible", String)
|
|
31
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
|
+
)
|
|
32
37
|
|
|
33
38
|
sig { returns(T::Array[Dependency]) }
|
|
34
39
|
attr_reader :dependencies
|
|
@@ -262,25 +267,7 @@ module Dependabot
|
|
|
262
267
|
end
|
|
263
268
|
end
|
|
264
269
|
rescue SharedHelpers::HelperSubprocessFailed => e
|
|
265
|
-
handle_uv_error(e)
|
|
266
|
-
end
|
|
267
|
-
|
|
268
|
-
sig do
|
|
269
|
-
params(
|
|
270
|
-
error: SharedHelpers::HelperSubprocessFailed
|
|
271
|
-
)
|
|
272
|
-
.returns(T.noreturn)
|
|
273
|
-
end
|
|
274
|
-
def handle_uv_error(error)
|
|
275
|
-
error_message = error.message
|
|
276
|
-
|
|
277
|
-
if resolution_error?(error_message)
|
|
278
|
-
handle_resolution_error(error_message)
|
|
279
|
-
elsif error_message.include?(RESOLUTION_IMPOSSIBLE_ERROR)
|
|
280
|
-
raise Dependabot::DependencyFileNotResolvable, error_message
|
|
281
|
-
else
|
|
282
|
-
raise error
|
|
283
|
-
end
|
|
270
|
+
error_handler.handle_uv_error(e)
|
|
284
271
|
end
|
|
285
272
|
|
|
286
273
|
sig { params(error_message: String).returns(T::Boolean) }
|
|
@@ -317,8 +304,12 @@ module Dependabot
|
|
|
317
304
|
match = normalized_message.match(conflict_pattern)
|
|
318
305
|
return [] unless match
|
|
319
306
|
|
|
320
|
-
|
|
321
|
-
|
|
307
|
+
[T.must(match[1]), T.must(match[2])].uniq
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
sig { returns(LockFileErrorHandler) }
|
|
311
|
+
def error_handler
|
|
312
|
+
@error_handler ||= T.let(LockFileErrorHandler.new, T.nilable(LockFileErrorHandler))
|
|
322
313
|
end
|
|
323
314
|
|
|
324
315
|
sig { returns(T.nilable(String)) }
|
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.
|
|
4
|
+
version: 0.360.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.
|
|
18
|
+
version: 0.360.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.
|
|
25
|
+
version: 0.360.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.
|
|
32
|
+
version: 0.360.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.
|
|
39
|
+
version: 0.360.0
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: debug
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -270,6 +270,7 @@ files:
|
|
|
270
270
|
- lib/dependabot/uv/file_parser/python_requirement_parser.rb
|
|
271
271
|
- lib/dependabot/uv/file_updater.rb
|
|
272
272
|
- lib/dependabot/uv/file_updater/compile_file_updater.rb
|
|
273
|
+
- lib/dependabot/uv/file_updater/lock_file_error_handler.rb
|
|
273
274
|
- lib/dependabot/uv/file_updater/lock_file_updater.rb
|
|
274
275
|
- lib/dependabot/uv/file_updater/pyproject_preparer.rb
|
|
275
276
|
- lib/dependabot/uv/file_updater/requirement_file_updater.rb
|
|
@@ -298,7 +299,7 @@ licenses:
|
|
|
298
299
|
- MIT
|
|
299
300
|
metadata:
|
|
300
301
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
301
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
302
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.360.0
|
|
302
303
|
rdoc_options: []
|
|
303
304
|
require_paths:
|
|
304
305
|
- lib
|