dependabot-uv 0.313.0 → 0.314.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 +4 -4
- data/lib/dependabot/uv/file_updater/lock_file_updater.rb +126 -44
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2f78bea59c8500e0193c416cb5e6f2502e37450c34429b642a9d563ee67fdac
|
4
|
+
data.tar.gz: 6a802c357783217e10881e46df0e5d55f42fefbfc9bd7a087cb17e97572d5785
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5695bf2e04719f3aecdf56622074439632ecb715f29fa0ab91059b42e79b17ca603f041c3fabe1475283d12d19fa32b40299bcd3db92ca14e0d5c03cd699a259
|
7
|
+
data.tar.gz: 5bb0d5859b3948363da8708e1765695c841a688ea35cbd0bcf1c7afbc937aba47c348b8bd2bcb1093ccc582c674c71b86eae8fc6f4f899b13a4bf5b484fa53b8
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# typed:
|
1
|
+
# typed: strict
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "toml-rb"
|
@@ -17,33 +17,56 @@ module Dependabot
|
|
17
17
|
module Uv
|
18
18
|
class FileUpdater
|
19
19
|
class LockFileUpdater
|
20
|
+
extend T::Sig
|
20
21
|
require_relative "pyproject_preparer"
|
21
22
|
|
22
23
|
REQUIRED_FILES = %w(pyproject.toml uv.lock).freeze # At least one of these files should be present
|
23
24
|
|
25
|
+
sig { returns(T::Array[Dependency]) }
|
24
26
|
attr_reader :dependencies
|
27
|
+
|
28
|
+
sig { returns(T::Array[DependencyFile]) }
|
25
29
|
attr_reader :dependency_files
|
30
|
+
|
31
|
+
sig { returns(T::Array[Dependabot::Credential]) }
|
26
32
|
attr_reader :credentials
|
33
|
+
|
34
|
+
sig { returns(T.nilable(T::Array[String])) }
|
27
35
|
attr_reader :index_urls
|
28
36
|
|
37
|
+
sig do
|
38
|
+
params(
|
39
|
+
dependencies: T::Array[Dependency],
|
40
|
+
dependency_files: T::Array[DependencyFile],
|
41
|
+
credentials: T::Array[Dependabot::Credential],
|
42
|
+
index_urls: T.nilable(T::Array[String])
|
43
|
+
).void
|
44
|
+
end
|
29
45
|
def initialize(dependencies:, dependency_files:, credentials:, index_urls: nil)
|
30
46
|
@dependencies = dependencies
|
31
47
|
@dependency_files = dependency_files
|
32
48
|
@credentials = credentials
|
33
49
|
@index_urls = index_urls
|
50
|
+
@prepared_pyproject = T.let(nil, T.nilable(String))
|
51
|
+
@updated_lockfile_content = T.let(nil, T.nilable(String))
|
52
|
+
@pyproject = T.let(nil, T.nilable(Dependabot::DependencyFile))
|
34
53
|
end
|
35
54
|
|
55
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
36
56
|
def updated_dependency_files
|
37
|
-
@updated_dependency_files ||= fetch_updated_dependency_files
|
57
|
+
@updated_dependency_files ||= T.let(fetch_updated_dependency_files,
|
58
|
+
T.nilable(T::Array[Dependabot::DependencyFile]))
|
38
59
|
end
|
39
60
|
|
40
61
|
private
|
41
62
|
|
63
|
+
sig { returns(T.nilable(Dependabot::Dependency)) }
|
42
64
|
def dependency
|
43
65
|
# For now, we'll only ever be updating a single dependency
|
44
|
-
dependencies.first
|
66
|
+
T.must(dependencies.first)
|
45
67
|
end
|
46
68
|
|
69
|
+
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
47
70
|
def fetch_updated_dependency_files
|
48
71
|
return [] unless create_or_update_lock_file?
|
49
72
|
|
@@ -52,32 +75,33 @@ module Dependabot
|
|
52
75
|
if file_changed?(pyproject)
|
53
76
|
updated_files <<
|
54
77
|
updated_file(
|
55
|
-
file: pyproject,
|
56
|
-
content: updated_pyproject_content
|
78
|
+
file: T.must(pyproject),
|
79
|
+
content: T.must(updated_pyproject_content)
|
57
80
|
)
|
58
81
|
end
|
59
82
|
|
60
83
|
if lockfile
|
61
84
|
# Use updated_lockfile_content which might raise if the lockfile doesn't change
|
62
85
|
new_content = updated_lockfile_content
|
63
|
-
raise "Expected lockfile to change!" if lockfile.content == new_content
|
86
|
+
raise "Expected lockfile to change!" if T.must(lockfile).content == new_content
|
64
87
|
|
65
|
-
updated_files << updated_file(file: lockfile, content: new_content)
|
88
|
+
updated_files << updated_file(file: T.must(lockfile), content: new_content)
|
66
89
|
end
|
67
90
|
|
68
91
|
updated_files
|
69
92
|
end
|
70
93
|
|
94
|
+
sig { returns(T.nilable(String)) }
|
71
95
|
def updated_pyproject_content
|
72
|
-
content = pyproject.content
|
73
|
-
return content unless file_changed?(pyproject)
|
96
|
+
content = T.must(pyproject).content
|
97
|
+
return content unless file_changed?(T.must(pyproject))
|
74
98
|
|
75
99
|
updated_content = content.dup
|
76
100
|
|
77
|
-
dependency.requirements.zip(dependency.previous_requirements).each do |new_r, old_r|
|
78
|
-
next unless new_r[:file] == pyproject.name && old_r[:file] == pyproject.name
|
101
|
+
T.must(dependency).requirements.zip(T.must(T.must(dependency).previous_requirements)).each do |new_r, old_r|
|
102
|
+
next unless new_r[:file] == T.must(pyproject).name && T.must(old_r)[:file] == T.must(pyproject).name
|
79
103
|
|
80
|
-
updated_content = replace_dep(dependency, updated_content, new_r, old_r)
|
104
|
+
updated_content = replace_dep(T.must(dependency), T.must(updated_content), new_r, T.must(old_r))
|
81
105
|
end
|
82
106
|
|
83
107
|
raise DependencyFileContentNotChanged, "Content did not change!" if content == updated_content
|
@@ -85,6 +109,14 @@ module Dependabot
|
|
85
109
|
updated_content
|
86
110
|
end
|
87
111
|
|
112
|
+
sig do
|
113
|
+
params(
|
114
|
+
dep: Dependabot::Dependency,
|
115
|
+
content: String,
|
116
|
+
new_r: T::Hash[Symbol, T.untyped],
|
117
|
+
old_r: T::Hash[Symbol, T.untyped]
|
118
|
+
).returns(String)
|
119
|
+
end
|
88
120
|
def replace_dep(dep, content, new_r, old_r)
|
89
121
|
new_req = new_r[:requirement]
|
90
122
|
old_req = old_r[:requirement]
|
@@ -93,28 +125,29 @@ module Dependabot
|
|
93
125
|
declaration_match = content.match(declaration_regex)
|
94
126
|
if declaration_match
|
95
127
|
declaration = declaration_match[:declaration]
|
96
|
-
new_declaration = declaration.sub(old_req, new_req)
|
97
|
-
content.sub(declaration, new_declaration)
|
128
|
+
new_declaration = T.must(declaration).sub(old_req, new_req)
|
129
|
+
content.sub(T.must(declaration), new_declaration)
|
98
130
|
else
|
99
131
|
content
|
100
132
|
end
|
101
133
|
end
|
102
134
|
|
135
|
+
sig { returns(String) }
|
103
136
|
def updated_lockfile_content
|
104
137
|
@updated_lockfile_content ||=
|
105
138
|
begin
|
106
|
-
original_content = lockfile.content
|
139
|
+
original_content = T.must(lockfile).content
|
107
140
|
# Extract the original requires-python value to preserve it
|
108
|
-
original_requires_python = original_content
|
109
|
-
|
141
|
+
original_requires_python = T.must(original_content)
|
142
|
+
.match(/requires-python\s*=\s*["']([^"']+)["']/)&.captures&.first
|
110
143
|
|
111
144
|
# Store the original Python version requirement for later use
|
112
|
-
@original_python_version = original_requires_python
|
145
|
+
@original_python_version = T.let(original_requires_python, T.nilable(String))
|
113
146
|
|
114
147
|
new_lockfile = updated_lockfile_content_for(prepared_pyproject)
|
115
148
|
|
116
149
|
# Normalize line endings to ensure proper comparison
|
117
|
-
new_lockfile = normalize_line_endings(new_lockfile, original_content)
|
150
|
+
new_lockfile = normalize_line_endings(new_lockfile, T.must(original_content))
|
118
151
|
|
119
152
|
result = new_lockfile
|
120
153
|
|
@@ -129,6 +162,7 @@ module Dependabot
|
|
129
162
|
end
|
130
163
|
|
131
164
|
# Helper method to normalize line endings between two strings
|
165
|
+
sig { params(content: String, reference: String).returns(String) }
|
132
166
|
def normalize_line_endings(content, reference)
|
133
167
|
# Check if reference has escaped newlines like "\n" +
|
134
168
|
if reference.include?("\\n")
|
@@ -138,33 +172,24 @@ module Dependabot
|
|
138
172
|
end
|
139
173
|
end
|
140
174
|
|
141
|
-
|
142
|
-
if original_requires_python
|
143
|
-
original_python_version = @original_python_version
|
144
|
-
@original_python_version = original_requires_python
|
145
|
-
result = yield
|
146
|
-
@original_python_version = original_python_version
|
147
|
-
result
|
148
|
-
else
|
149
|
-
yield
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
175
|
+
sig { returns(String) }
|
153
176
|
def prepared_pyproject
|
154
177
|
@prepared_pyproject ||=
|
155
178
|
begin
|
156
179
|
content = updated_pyproject_content
|
157
|
-
content = sanitize(content)
|
180
|
+
content = sanitize(T.must(content))
|
158
181
|
content
|
159
182
|
end
|
160
183
|
end
|
161
184
|
|
185
|
+
sig { params(pyproject_content: String).returns(String) }
|
162
186
|
def sanitize(pyproject_content)
|
163
187
|
PyprojectPreparer
|
164
188
|
.new(pyproject_content: pyproject_content)
|
165
189
|
.sanitize
|
166
190
|
end
|
167
191
|
|
192
|
+
sig { params(pyproject_content: String).returns(String) }
|
168
193
|
def updated_lockfile_content_for(pyproject_content)
|
169
194
|
SharedHelpers.in_a_temporary_directory do
|
170
195
|
SharedHelpers.with_git_configured(credentials: credentials) do
|
@@ -180,19 +205,25 @@ module Dependabot
|
|
180
205
|
end
|
181
206
|
end
|
182
207
|
|
208
|
+
sig { returns(T.nilable(String)) }
|
183
209
|
def run_update_command
|
210
|
+
options = lock_options
|
211
|
+
options_fingerprint = lock_options_fingerprint(options)
|
212
|
+
|
184
213
|
# Use pyenv exec to ensure we're using the correct Python environment
|
185
|
-
command = "pyenv exec uv lock --upgrade-package #{dependency.name}"
|
186
|
-
fingerprint = "pyenv exec uv lock --upgrade-package <dependency_name>"
|
214
|
+
command = "pyenv exec uv lock --upgrade-package #{T.must(dependency).name} #{options}"
|
215
|
+
fingerprint = "pyenv exec uv lock --upgrade-package <dependency_name> #{options_fingerprint}"
|
187
216
|
|
188
217
|
run_command(command, fingerprint:)
|
189
218
|
end
|
190
219
|
|
220
|
+
sig { params(command: String, fingerprint: T.nilable(String)).returns(String) }
|
191
221
|
def run_command(command, fingerprint: nil)
|
192
222
|
Dependabot.logger.info("Running command: #{command}")
|
193
223
|
SharedHelpers.run_shell_command(command, fingerprint: fingerprint)
|
194
224
|
end
|
195
225
|
|
226
|
+
sig { params(pyproject_content: String).returns(Integer) }
|
196
227
|
def write_temporary_dependency_files(pyproject_content)
|
197
228
|
dependency_files.each do |file|
|
198
229
|
path = file.name
|
@@ -204,6 +235,7 @@ module Dependabot
|
|
204
235
|
File.write("pyproject.toml", pyproject_content)
|
205
236
|
end
|
206
237
|
|
238
|
+
sig { void }
|
207
239
|
def setup_python_environment
|
208
240
|
# Use LanguageVersionManager to determine and install the appropriate Python version
|
209
241
|
Dependabot.logger.info("Setting up Python environment using LanguageVersionManager")
|
@@ -225,10 +257,12 @@ module Dependabot
|
|
225
257
|
end
|
226
258
|
end
|
227
259
|
|
260
|
+
sig { params(url: String).returns(String) }
|
228
261
|
def sanitize_env_name(url)
|
229
262
|
url.gsub(%r{^https?://}, "").gsub(/[^a-zA-Z0-9]/, "_").upcase
|
230
263
|
end
|
231
264
|
|
265
|
+
sig { params(dep: T.untyped, old_req: T.untyped).returns(Regexp) }
|
232
266
|
def declaration_regex(dep, old_req)
|
233
267
|
escaped_name = Regexp.escape(dep.name)
|
234
268
|
# Extract the requirement operator and version
|
@@ -246,10 +280,43 @@ module Dependabot
|
|
246
280
|
/x
|
247
281
|
end
|
248
282
|
|
283
|
+
sig { returns(String) }
|
284
|
+
def lock_options
|
285
|
+
options = lock_index_options
|
286
|
+
|
287
|
+
options.join(" ")
|
288
|
+
end
|
289
|
+
|
290
|
+
sig { returns(T::Array[String]) }
|
291
|
+
def lock_index_options
|
292
|
+
credentials
|
293
|
+
.select { |cred| cred["type"] == "python_index" }
|
294
|
+
.map do |cred|
|
295
|
+
authed_url = AuthedUrlBuilder.authed_url(credential: cred)
|
296
|
+
|
297
|
+
if cred.replaces_base?
|
298
|
+
"--default-index #{authed_url}"
|
299
|
+
else
|
300
|
+
"--index #{authed_url}"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
sig { params(options: String).returns(String) }
|
306
|
+
def lock_options_fingerprint(options)
|
307
|
+
options.sub(
|
308
|
+
/--default-index\s+\S+/, "--default-index <default_index>"
|
309
|
+
).sub(
|
310
|
+
/--index\s+\S+/, "--index <index>"
|
311
|
+
)
|
312
|
+
end
|
313
|
+
|
314
|
+
sig { params(name: T.any(String, Symbol)).returns(String) }
|
249
315
|
def escape(name)
|
250
316
|
Regexp.escape(name).gsub("\\-", "[-_.]")
|
251
317
|
end
|
252
318
|
|
319
|
+
sig { params(file: T.nilable(DependencyFile)).returns(T::Boolean) }
|
253
320
|
def file_changed?(file)
|
254
321
|
return false unless file
|
255
322
|
|
@@ -259,56 +326,71 @@ module Dependabot
|
|
259
326
|
end
|
260
327
|
end
|
261
328
|
|
329
|
+
sig do
|
330
|
+
params(file: T.nilable(DependencyFile), dependency: Dependency)
|
331
|
+
.returns(T::Boolean)
|
332
|
+
end
|
262
333
|
def requirement_changed?(file, dependency)
|
263
334
|
changed_requirements =
|
264
|
-
dependency.requirements - dependency.previous_requirements
|
335
|
+
dependency.requirements - T.must(dependency.previous_requirements)
|
265
336
|
|
266
|
-
changed_requirements.any? { |f| f[:file] == file.name }
|
337
|
+
changed_requirements.any? { |f| f[:file] == T.must(file).name }
|
267
338
|
end
|
268
339
|
|
340
|
+
sig { params(file: Dependabot::DependencyFile, content: String).returns(Dependabot::DependencyFile) }
|
269
341
|
def updated_file(file:, content:)
|
270
342
|
updated_file = file.dup
|
271
343
|
updated_file.content = content
|
272
344
|
updated_file
|
273
345
|
end
|
274
346
|
|
347
|
+
sig { params(name: String).returns(String) }
|
275
348
|
def normalise(name)
|
276
349
|
NameNormaliser.normalise(name)
|
277
350
|
end
|
278
351
|
|
352
|
+
sig { returns(Dependabot::Uv::FileParser::PythonRequirementParser) }
|
279
353
|
def python_requirement_parser
|
280
|
-
@python_requirement_parser ||=
|
354
|
+
@python_requirement_parser ||= T.let(
|
281
355
|
FileParser::PythonRequirementParser.new(
|
282
356
|
dependency_files: dependency_files
|
283
|
-
)
|
357
|
+
), T.nilable(FileParser::PythonRequirementParser)
|
358
|
+
)
|
284
359
|
end
|
285
360
|
|
361
|
+
sig { returns(Dependabot::Uv::LanguageVersionManager) }
|
286
362
|
def language_version_manager
|
287
|
-
@language_version_manager ||=
|
363
|
+
@language_version_manager ||= T.let(
|
288
364
|
LanguageVersionManager.new(
|
289
365
|
python_requirement_parser: python_requirement_parser
|
290
|
-
)
|
366
|
+
), T.nilable(LanguageVersionManager)
|
367
|
+
)
|
291
368
|
end
|
292
369
|
|
370
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
293
371
|
def pyproject
|
294
|
-
@pyproject ||=
|
295
|
-
|
372
|
+
@pyproject ||= T.let(dependency_files.find { |f| f.name == "pyproject.toml" },
|
373
|
+
T.nilable(Dependabot::DependencyFile))
|
296
374
|
end
|
297
375
|
|
376
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
298
377
|
def lockfile
|
299
|
-
@lockfile ||= uv_lock
|
378
|
+
@lockfile ||= T.let(uv_lock, T.nilable(Dependabot::DependencyFile))
|
300
379
|
end
|
301
380
|
|
381
|
+
sig { returns(String) }
|
302
382
|
def python_helper_path
|
303
383
|
NativeHelpers.python_helper_path
|
304
384
|
end
|
305
385
|
|
386
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
306
387
|
def uv_lock
|
307
388
|
dependency_files.find { |f| f.name == "uv.lock" }
|
308
389
|
end
|
309
390
|
|
391
|
+
sig { returns(T::Boolean) }
|
310
392
|
def create_or_update_lock_file?
|
311
|
-
dependency.requirements.select { _1[:file].end_with?(*REQUIRED_FILES) }.any?
|
393
|
+
T.must(dependency).requirements.select { _1[:file].end_with?(*REQUIRED_FILES) }.any?
|
312
394
|
end
|
313
395
|
end
|
314
396
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dependabot-uv
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.314.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dependabot
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-05-
|
10
|
+
date: 2025-05-22 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: dependabot-common
|
@@ -15,14 +15,14 @@ dependencies:
|
|
15
15
|
requirements:
|
16
16
|
- - '='
|
17
17
|
- !ruby/object:Gem::Version
|
18
|
-
version: 0.
|
18
|
+
version: 0.314.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.314.0
|
26
26
|
- !ruby/object:Gem::Dependency
|
27
27
|
name: debug
|
28
28
|
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.
|
287
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.314.0
|
288
288
|
rdoc_options: []
|
289
289
|
require_paths:
|
290
290
|
- lib
|