dependabot-uv 0.392.0 → 0.394.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/helpers/requirements.txt +5 -5
- data/lib/dependabot/uv/file_fetcher/workspace_fetcher.rb +2 -2
- data/lib/dependabot/uv/file_fetcher.rb +6 -6
- data/lib/dependabot/uv/file_parser/pyproject_files_parser.rb +167 -88
- data/lib/dependabot/uv/file_updater/lock_file_updater.rb +25 -4
- data/lib/dependabot/uv/update_checker/lock_file_resolver.rb +228 -14
- data/lib/dependabot/uv/update_checker.rb +0 -23
- metadata +8 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f9eee59202ca318e612e23d7303309e498d51999cda642a1660d41390a2bd4a8
|
|
4
|
+
data.tar.gz: 3b3bb2ea60f190db5d8c9bd36f1ff01531097788c3755c6638d5a4e8e3ebf923
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2f6d9c0f1ea2c05bab8acea5563a4a74c016ab9b8bd77639afe9468a8f7b8cb18d238585b5bdc11b255bf8e8d0af01d7d470c07ab9b83792d8001156bb73a199
|
|
7
|
+
data.tar.gz: '09c83e67c0b94adf7ad3f848f17521b57e282ef33db9d4ac0b5991d0ea8135024fc9eb5e78a1515a7f9f4c826f8db3347e25b24ed842ed85681a0b3dd8289e94'
|
data/helpers/requirements.txt
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
pip==26.
|
|
2
|
-
pip-tools==7.
|
|
1
|
+
pip==26.2.1
|
|
2
|
+
pip-tools==7.6.1
|
|
3
3
|
flake8==7.3.0
|
|
4
4
|
hashin==1.0.5
|
|
5
5
|
pipenv==2024.4.1
|
|
6
6
|
plette==2.2.1
|
|
7
|
-
poetry==2.
|
|
7
|
+
poetry==2.4.1
|
|
8
8
|
# TODO: Replace 3p package `tomli` with 3.11's new stdlib `tomllib` once we drop support for Python 3.10.
|
|
9
9
|
tomli==2.4.1
|
|
10
|
-
uv==0.12.
|
|
10
|
+
uv==0.12.5
|
|
11
11
|
|
|
12
12
|
# Some dependencies will only install if Cython is present
|
|
13
|
-
Cython==3.
|
|
13
|
+
Cython==3.3.0
|
|
@@ -277,8 +277,8 @@ module Dependabot
|
|
|
277
277
|
normalized_directory = directory.gsub(%r{(^/|/$)}, "")
|
|
278
278
|
|
|
279
279
|
repo_contents(dir: base_dir, raise_errors: false)
|
|
280
|
-
.select { |file|
|
|
281
|
-
.map { |
|
|
280
|
+
.select { |file| file.type == "dir" }
|
|
281
|
+
.map { |file| file.path.gsub(%r{^/?#{Regexp.escape(normalized_directory)}/?}, "") }
|
|
282
282
|
end
|
|
283
283
|
|
|
284
284
|
sig { params(paths: T::Array[String], pattern: String).returns(T::Array[String]) }
|
|
@@ -276,7 +276,7 @@ module Dependabot
|
|
|
276
276
|
def req_files_for_dir(requirements_dir)
|
|
277
277
|
dir = directory.gsub(%r{(^/|/$)}, "")
|
|
278
278
|
relative_reqs_dir =
|
|
279
|
-
requirements_dir.path
|
|
279
|
+
requirements_dir.path.gsub(%r{^/?#{Regexp.escape(dir)}/?}, "")
|
|
280
280
|
|
|
281
281
|
fetch_requirement_files_from_path(relative_reqs_dir)
|
|
282
282
|
end
|
|
@@ -321,7 +321,7 @@ module Dependabot
|
|
|
321
321
|
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
322
322
|
def fetch_requirement_files_from_dirs
|
|
323
323
|
repo_contents
|
|
324
|
-
.select { |f|
|
|
324
|
+
.select { |f| f.type == "dir" }
|
|
325
325
|
.flat_map { |dir| req_files_for_dir(dir) }
|
|
326
326
|
end
|
|
327
327
|
|
|
@@ -333,10 +333,10 @@ module Dependabot
|
|
|
333
333
|
end
|
|
334
334
|
def filter_requirement_files(contents, base_path: nil)
|
|
335
335
|
contents
|
|
336
|
-
.select { |f|
|
|
337
|
-
.select { |f| file_matches_requirement_pattern?(
|
|
338
|
-
.reject { |f|
|
|
339
|
-
.map { |f| fetch_file_with_path(
|
|
336
|
+
.select { |f| f.type == "file" }
|
|
337
|
+
.select { |f| file_matches_requirement_pattern?(f.name) }
|
|
338
|
+
.reject { |f| f.size > MAX_FILE_SIZE }
|
|
339
|
+
.map { |f| fetch_file_with_path(f.name, base_path) }
|
|
340
340
|
.select { |f| T.must(REQUIREMENT_FILE_PATTERNS[:filenames]).include?(f.name) || requirements_file?(f) }
|
|
341
341
|
end
|
|
342
342
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# typed:
|
|
1
|
+
# typed: strong
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "toml-rb"
|
|
@@ -9,6 +9,9 @@ require "dependabot/uv/file_parser"
|
|
|
9
9
|
require "dependabot/uv/requirement"
|
|
10
10
|
require "dependabot/errors"
|
|
11
11
|
require "dependabot/uv/name_normaliser"
|
|
12
|
+
require "dependabot/python/file_parser/pep_dependency"
|
|
13
|
+
require "dependabot/python/file_parser/poetry_lock"
|
|
14
|
+
require "dependabot/python/file_parser/pyproject_document"
|
|
12
15
|
|
|
13
16
|
module Dependabot
|
|
14
17
|
module Uv
|
|
@@ -16,6 +19,10 @@ module Dependabot
|
|
|
16
19
|
class PyprojectFilesParser
|
|
17
20
|
extend T::Sig
|
|
18
21
|
|
|
22
|
+
PepDependency = Dependabot::Python::FileParser::PepDependency
|
|
23
|
+
PoetryLock = Dependabot::Python::FileParser::PoetryLock
|
|
24
|
+
PyprojectDocument = Dependabot::Python::FileParser::PyprojectDocument
|
|
25
|
+
|
|
19
26
|
POETRY_DEPENDENCY_TYPES = %w(dependencies dev-dependencies).freeze
|
|
20
27
|
|
|
21
28
|
# https://python-poetry.org/docs/dependency-specification/
|
|
@@ -24,6 +31,8 @@ module Dependabot
|
|
|
24
31
|
sig { params(dependency_files: T::Array[Dependabot::DependencyFile]).void }
|
|
25
32
|
def initialize(dependency_files:)
|
|
26
33
|
@dependency_files = dependency_files
|
|
34
|
+
@pyproject_document = T.let(nil, T.nilable(PyprojectDocument))
|
|
35
|
+
@poetry_lock_document = T.let(nil, T.nilable(PoetryLock))
|
|
27
36
|
end
|
|
28
37
|
|
|
29
38
|
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
|
@@ -61,13 +70,11 @@ module Dependabot
|
|
|
61
70
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
|
62
71
|
|
|
63
72
|
POETRY_DEPENDENCY_TYPES.each do |type|
|
|
64
|
-
|
|
65
|
-
dependencies += parse_poetry_dependency_group(type, deps_hash)
|
|
73
|
+
dependencies += parse_poetry_dependency_group(type, pyproject_document.poetry_dependencies(type))
|
|
66
74
|
end
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
dependencies += parse_poetry_dependency_group(group, group_spec["dependencies"])
|
|
76
|
+
pyproject_document.poetry_groups.each do |group, dependencies_by_name|
|
|
77
|
+
dependencies += parse_poetry_dependency_group(group, dependencies_by_name)
|
|
71
78
|
end
|
|
72
79
|
dependencies
|
|
73
80
|
end
|
|
@@ -85,20 +92,20 @@ module Dependabot
|
|
|
85
92
|
parse_pep621_pep735_dependencies(pyproject_file).each do |dep|
|
|
86
93
|
# If a requirement has a `<` or `<=` marker then updating it is
|
|
87
94
|
# probably blocked. Ignore it.
|
|
88
|
-
next if dep
|
|
95
|
+
next if dep.markers&.include?("<")
|
|
89
96
|
|
|
90
97
|
# In uv no constraint means any version is acceptable
|
|
91
|
-
requirement_value = dep
|
|
98
|
+
requirement_value = dep.requirement == "" ? "*" : dep.requirement
|
|
92
99
|
|
|
93
100
|
dependencies <<
|
|
94
101
|
Dependency.new(
|
|
95
|
-
name: normalised_name(dep
|
|
96
|
-
version: dep
|
|
102
|
+
name: normalised_name(dep.name, dep.extras),
|
|
103
|
+
version: dep.version&.include?("*") ? nil : dep.version,
|
|
97
104
|
requirements: [{
|
|
98
105
|
requirement: requirement_value,
|
|
99
|
-
file: Pathname.new(dep
|
|
106
|
+
file: Pathname.new(dep.file).cleanpath.to_path,
|
|
100
107
|
source: nil,
|
|
101
|
-
groups: [dep
|
|
108
|
+
groups: [dep.requirement_type].compact
|
|
102
109
|
}],
|
|
103
110
|
package_manager: "uv"
|
|
104
111
|
)
|
|
@@ -109,7 +116,52 @@ module Dependabot
|
|
|
109
116
|
|
|
110
117
|
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
|
111
118
|
def workspace_member_pyproject_files
|
|
112
|
-
|
|
119
|
+
return [] if workspace_member_patterns.empty?
|
|
120
|
+
|
|
121
|
+
dependency_files.select do |file|
|
|
122
|
+
next false unless file.support_file? && file.name.end_with?("pyproject.toml")
|
|
123
|
+
|
|
124
|
+
workspace_member_file?(file)
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Only pyprojects declared under `[tool.uv.workspace].members` in the root
|
|
129
|
+
# manifest are true workspace members whose requirements should be updated.
|
|
130
|
+
# Editable `[tool.uv.sources]` path dependencies are separate packages that
|
|
131
|
+
# are fetched as support files for resolution but must not be modified.
|
|
132
|
+
sig { returns(T::Array[String]) }
|
|
133
|
+
def workspace_member_patterns
|
|
134
|
+
workspace_globs("members")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# uv removes paths matching `[tool.uv.workspace].exclude` after expanding
|
|
138
|
+
# `members`, so an excluded directory is not a workspace member even when it
|
|
139
|
+
# matches a `members` glob.
|
|
140
|
+
sig { returns(T::Array[String]) }
|
|
141
|
+
def workspace_exclude_patterns
|
|
142
|
+
workspace_globs("exclude")
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
sig { params(key: String).returns(T::Array[String]) }
|
|
146
|
+
def workspace_globs(key)
|
|
147
|
+
return [] unless pyproject
|
|
148
|
+
|
|
149
|
+
pyproject_document.workspace_globs(key)
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
sig { params(file: Dependabot::DependencyFile).returns(T::Boolean) }
|
|
153
|
+
def workspace_member_file?(file)
|
|
154
|
+
member_dir = File.dirname(file.name)
|
|
155
|
+
|
|
156
|
+
return false if workspace_exclude_patterns.any? { |pattern| glob_matches_dir?(pattern, member_dir) }
|
|
157
|
+
|
|
158
|
+
workspace_member_patterns.any? { |pattern| glob_matches_dir?(pattern, member_dir) }
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
sig { params(pattern: String, dir: String).returns(T::Boolean) }
|
|
162
|
+
def glob_matches_dir?(pattern, dir)
|
|
163
|
+
normalized_pattern = pattern.gsub(%r{^\./}, "").chomp("/")
|
|
164
|
+
File.fnmatch?(normalized_pattern, dir, File::FNM_PATHNAME)
|
|
113
165
|
end
|
|
114
166
|
|
|
115
167
|
sig { returns(Dependabot::FileParsers::Base::DependencySet) }
|
|
@@ -126,17 +178,16 @@ module Dependabot
|
|
|
126
178
|
sig do
|
|
127
179
|
params(
|
|
128
180
|
type: String,
|
|
129
|
-
deps_hash:
|
|
130
|
-
T.untyped]
|
|
181
|
+
deps_hash: PyprojectDocument::PoetryDependencyMap
|
|
131
182
|
).returns(Dependabot::FileParsers::Base::DependencySet)
|
|
132
183
|
end
|
|
133
184
|
def parse_poetry_dependency_group(type, deps_hash)
|
|
134
185
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
|
135
186
|
|
|
136
|
-
deps_hash.each do |name,
|
|
187
|
+
deps_hash.each do |name, requirements_data|
|
|
137
188
|
next if normalise(name) == "python"
|
|
138
189
|
|
|
139
|
-
requirements = parse_requirements_from(
|
|
190
|
+
requirements = parse_requirements_from(requirements_data, type)
|
|
140
191
|
next if requirements.empty?
|
|
141
192
|
|
|
142
193
|
dependencies << Dependency.new(
|
|
@@ -154,57 +205,62 @@ module Dependabot
|
|
|
154
205
|
NameNormaliser.normalise_including_extras(name, extras)
|
|
155
206
|
end
|
|
156
207
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
208
|
+
sig do
|
|
209
|
+
params(
|
|
210
|
+
requirements_data: T::Array[PyprojectDocument::PoetryRequirement],
|
|
211
|
+
type: String
|
|
212
|
+
).returns(T::Array[Dependabot::Dependency::RequirementInput])
|
|
213
|
+
end
|
|
214
|
+
def parse_requirements_from(requirements_data, type)
|
|
215
|
+
requirements_data.filter_map { |requirement| poetry_requirement(requirement, type) }
|
|
216
|
+
end
|
|
162
217
|
|
|
218
|
+
sig do
|
|
219
|
+
params(
|
|
220
|
+
requirement: PyprojectDocument::PoetryRequirement,
|
|
221
|
+
type: String
|
|
222
|
+
).returns(T.nilable(Dependabot::Dependency::RequirementInput))
|
|
223
|
+
end
|
|
224
|
+
def poetry_requirement(requirement, type)
|
|
225
|
+
if requirement.is_a?(String)
|
|
163
226
|
check_requirements(requirement)
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
groups: [type]
|
|
171
|
-
}
|
|
172
|
-
else
|
|
173
|
-
{
|
|
174
|
-
requirement: requirement["version"],
|
|
175
|
-
file: T.must(pyproject).name,
|
|
176
|
-
source: requirement.fetch("source", nil),
|
|
177
|
-
groups: [type]
|
|
178
|
-
}
|
|
179
|
-
end
|
|
227
|
+
return {
|
|
228
|
+
requirement: requirement,
|
|
229
|
+
file: T.must(pyproject).name,
|
|
230
|
+
source: nil,
|
|
231
|
+
groups: [type]
|
|
232
|
+
}
|
|
180
233
|
end
|
|
234
|
+
|
|
235
|
+
return if UNSUPPORTED_DEPENDENCY_TYPES.intersect?(requirement.keys)
|
|
236
|
+
|
|
237
|
+
check_requirements(requirement)
|
|
238
|
+
{
|
|
239
|
+
requirement: requirement_string(requirement, "version"),
|
|
240
|
+
file: T.must(pyproject).name,
|
|
241
|
+
source: poetry_source(requirement["source"]),
|
|
242
|
+
groups: [type]
|
|
243
|
+
}
|
|
181
244
|
end
|
|
182
245
|
|
|
183
|
-
sig { returns(T
|
|
246
|
+
sig { returns(T::Boolean) }
|
|
184
247
|
def using_poetry?
|
|
185
|
-
|
|
248
|
+
pyproject_document.poetry?
|
|
186
249
|
end
|
|
187
250
|
|
|
188
251
|
sig { returns(T::Boolean) }
|
|
189
252
|
def using_pep621?
|
|
190
|
-
|
|
191
|
-
!parsed_pyproject.dig("project", "optional-dependencies").nil? ||
|
|
192
|
-
!parsed_pyproject.dig("build-system", "requires").nil?
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
sig { returns(T.nilable(T::Hash[String, T.untyped])) }
|
|
196
|
-
def poetry_root
|
|
197
|
-
parsed_pyproject.dig("tool", "poetry")
|
|
253
|
+
pyproject_document.pep621?
|
|
198
254
|
end
|
|
199
255
|
|
|
200
256
|
sig { returns(T::Boolean) }
|
|
201
257
|
def using_pep735?
|
|
202
|
-
|
|
258
|
+
pyproject_document.pep735?
|
|
203
259
|
end
|
|
204
260
|
|
|
205
|
-
sig { returns(T
|
|
261
|
+
sig { returns(T::Boolean) }
|
|
206
262
|
def using_pdm?
|
|
207
|
-
using_pep621? && pdm_lock
|
|
263
|
+
using_pep621? && !pdm_lock.nil?
|
|
208
264
|
end
|
|
209
265
|
|
|
210
266
|
# Create a DependencySet where each element has no requirement. Any
|
|
@@ -215,15 +271,15 @@ module Dependabot
|
|
|
215
271
|
dependencies = Dependabot::FileParsers::Base::DependencySet.new
|
|
216
272
|
|
|
217
273
|
source_types = %w(directory git url)
|
|
218
|
-
|
|
219
|
-
next if source_types.include?(
|
|
274
|
+
poetry_lock_document.packages.each do |package|
|
|
275
|
+
next if source_types.include?(package.source_type)
|
|
220
276
|
|
|
221
|
-
name = normalise(
|
|
277
|
+
name = normalise(package.name)
|
|
222
278
|
|
|
223
279
|
dependencies <<
|
|
224
280
|
Dependency.new(
|
|
225
281
|
name: name,
|
|
226
|
-
version:
|
|
282
|
+
version: package.version,
|
|
227
283
|
requirements: [],
|
|
228
284
|
package_manager: "uv",
|
|
229
285
|
subdependency_metadata: [{
|
|
@@ -246,8 +302,10 @@ module Dependabot
|
|
|
246
302
|
sig { returns(T::Array[T.nilable(String)]) }
|
|
247
303
|
def parse_production_dependency_names
|
|
248
304
|
SharedHelpers.in_a_temporary_directory do
|
|
249
|
-
|
|
250
|
-
|
|
305
|
+
pyproject_file = T.must(pyproject)
|
|
306
|
+
lockfile_file = T.must(lockfile)
|
|
307
|
+
File.write(pyproject_file.name, pyproject_file.content)
|
|
308
|
+
File.write(lockfile_file.name, lockfile_file.content)
|
|
251
309
|
|
|
252
310
|
begin
|
|
253
311
|
output = SharedHelpers.run_shell_command("pyenv exec poetry show --only main")
|
|
@@ -266,18 +324,19 @@ module Dependabot
|
|
|
266
324
|
end
|
|
267
325
|
end
|
|
268
326
|
|
|
269
|
-
sig { params(dep_name: String).returns(T.
|
|
327
|
+
sig { params(dep_name: String).returns(T.nilable(String)) }
|
|
270
328
|
def version_from_lockfile(dep_name)
|
|
271
|
-
return unless
|
|
329
|
+
return unless poetry_lock
|
|
272
330
|
|
|
273
|
-
|
|
274
|
-
.find { |p| normalise(p.fetch("name")) == normalise(dep_name) }
|
|
275
|
-
&.fetch("version", nil)
|
|
331
|
+
poetry_lock_document.version_for(dep_name) { |name| normalise(name) }
|
|
276
332
|
end
|
|
277
333
|
|
|
278
|
-
sig
|
|
334
|
+
sig do
|
|
335
|
+
params(req: PyprojectDocument::PoetryRequirement)
|
|
336
|
+
.returns(T::Array[Dependabot::Uv::Requirement])
|
|
337
|
+
end
|
|
279
338
|
def check_requirements(req)
|
|
280
|
-
requirement = req.is_a?(String) ? req : req
|
|
339
|
+
requirement = req.is_a?(String) ? req : requirement_string(req, "version")
|
|
281
340
|
Uv::Requirement.requirements_array(requirement)
|
|
282
341
|
rescue Gem::Requirement::BadRequirementError => e
|
|
283
342
|
raise Dependabot::DependencyFileNotEvaluatable, e.message
|
|
@@ -288,21 +347,14 @@ module Dependabot
|
|
|
288
347
|
NameNormaliser.normalise(name)
|
|
289
348
|
end
|
|
290
349
|
|
|
291
|
-
sig { returns(
|
|
292
|
-
def
|
|
293
|
-
@
|
|
294
|
-
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
|
295
|
-
raise Dependabot::DependencyFileNotParseable, T.must(pyproject).path
|
|
350
|
+
sig { returns(PyprojectDocument) }
|
|
351
|
+
def pyproject_document
|
|
352
|
+
@pyproject_document ||= PyprojectDocument.from_file(T.must(pyproject))
|
|
296
353
|
end
|
|
297
354
|
|
|
298
|
-
sig { returns(
|
|
299
|
-
def
|
|
300
|
-
@
|
|
301
|
-
TomlRB.parse(T.must(poetry_lock).content),
|
|
302
|
-
T.nilable(T::Hash[String, T.untyped])
|
|
303
|
-
)
|
|
304
|
-
rescue TomlRB::ParseError, TomlRB::ValueOverwriteError
|
|
305
|
-
raise Dependabot::DependencyFileNotParseable, T.must(poetry_lock).path
|
|
355
|
+
sig { returns(PoetryLock) }
|
|
356
|
+
def poetry_lock_document
|
|
357
|
+
@poetry_lock_document ||= PoetryLock.from_file(T.must(poetry_lock))
|
|
306
358
|
end
|
|
307
359
|
|
|
308
360
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
@@ -313,20 +365,22 @@ module Dependabot
|
|
|
313
365
|
)
|
|
314
366
|
end
|
|
315
367
|
|
|
316
|
-
sig { returns(T.
|
|
368
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
317
369
|
def lockfile
|
|
318
370
|
poetry_lock
|
|
319
371
|
end
|
|
320
372
|
|
|
321
|
-
sig { params(pyproject_file: Dependabot::DependencyFile).returns(T
|
|
373
|
+
sig { params(pyproject_file: Dependabot::DependencyFile).returns(T::Array[PepDependency]) }
|
|
322
374
|
def parse_pep621_pep735_dependencies(pyproject_file)
|
|
323
375
|
SharedHelpers.in_a_temporary_directory do
|
|
324
376
|
write_temporary_pyproject(pyproject_file)
|
|
325
377
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
378
|
+
PepDependency.from_helper_result(
|
|
379
|
+
SharedHelpers.run_helper_subprocess(
|
|
380
|
+
command: "pyenv exec python3 #{NativeHelpers.python_helper_path}",
|
|
381
|
+
function: "parse_pep621_pep735_dependencies",
|
|
382
|
+
args: [pyproject_file.name]
|
|
383
|
+
)
|
|
330
384
|
)
|
|
331
385
|
end
|
|
332
386
|
end
|
|
@@ -338,11 +392,6 @@ module Dependabot
|
|
|
338
392
|
File.write(path, pyproject_file.content)
|
|
339
393
|
end
|
|
340
394
|
|
|
341
|
-
sig { returns(T.untyped) }
|
|
342
|
-
def parsed_lockfile
|
|
343
|
-
parsed_poetry_lock if poetry_lock
|
|
344
|
-
end
|
|
345
|
-
|
|
346
395
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
347
396
|
def poetry_lock
|
|
348
397
|
@poetry_lock ||= T.let(
|
|
@@ -351,6 +400,36 @@ module Dependabot
|
|
|
351
400
|
)
|
|
352
401
|
end
|
|
353
402
|
|
|
403
|
+
sig do
|
|
404
|
+
params(
|
|
405
|
+
requirement: T::Hash[String, Object],
|
|
406
|
+
key: String
|
|
407
|
+
).returns(T.nilable(String))
|
|
408
|
+
end
|
|
409
|
+
def requirement_string(requirement, key)
|
|
410
|
+
value = requirement[key]
|
|
411
|
+
return if value.nil?
|
|
412
|
+
return value if value.is_a?(String)
|
|
413
|
+
|
|
414
|
+
raise TypeError, "Poetry dependency #{key} must be a string or nil"
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
sig { params(value: T.nilable(Object)).returns(T.nilable(Dependabot::DependencyRequirement::Source)) }
|
|
418
|
+
def poetry_source(value)
|
|
419
|
+
return if value.nil?
|
|
420
|
+
return value if value.is_a?(String)
|
|
421
|
+
raise TypeError, "Poetry dependency source must be a string, object, or nil" unless value.is_a?(Hash)
|
|
422
|
+
|
|
423
|
+
source = T.let({}, Dependabot::DependencyRequirement::ObjectHash)
|
|
424
|
+
value.each do |raw_key, raw_value|
|
|
425
|
+
key = T.cast(raw_key, Object)
|
|
426
|
+
raise TypeError, "Poetry dependency source keys must be strings" unless key.is_a?(String)
|
|
427
|
+
|
|
428
|
+
source[key] = T.cast(raw_value, Object)
|
|
429
|
+
end
|
|
430
|
+
source
|
|
431
|
+
end
|
|
432
|
+
|
|
354
433
|
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
355
434
|
def pdm_lock
|
|
356
435
|
@pdm_lock ||= T.let(
|
|
@@ -44,21 +44,33 @@ module Dependabot
|
|
|
44
44
|
sig { returns(T.nilable(String)) }
|
|
45
45
|
attr_reader :repo_contents_path
|
|
46
46
|
|
|
47
|
+
sig { returns(T.nilable(String)) }
|
|
48
|
+
attr_reader :target_requirement
|
|
49
|
+
|
|
47
50
|
sig do
|
|
48
51
|
params(
|
|
49
52
|
dependencies: T::Array[Dependency],
|
|
50
53
|
dependency_files: T::Array[DependencyFile],
|
|
51
54
|
credentials: T::Array[Dependabot::Credential],
|
|
52
55
|
index_urls: T.nilable(T::Array[T.nilable(String)]),
|
|
53
|
-
repo_contents_path: T.nilable(String)
|
|
56
|
+
repo_contents_path: T.nilable(String),
|
|
57
|
+
target_requirement: T.nilable(String)
|
|
54
58
|
).void
|
|
55
59
|
end
|
|
56
|
-
def initialize(
|
|
60
|
+
def initialize(
|
|
61
|
+
dependencies:,
|
|
62
|
+
dependency_files:,
|
|
63
|
+
credentials:,
|
|
64
|
+
index_urls: nil,
|
|
65
|
+
repo_contents_path: nil,
|
|
66
|
+
target_requirement: nil
|
|
67
|
+
)
|
|
57
68
|
@dependencies = dependencies
|
|
58
69
|
@dependency_files = dependency_files
|
|
59
70
|
@credentials = credentials
|
|
60
71
|
@index_urls = index_urls
|
|
61
72
|
@repo_contents_path = repo_contents_path
|
|
73
|
+
@target_requirement = target_requirement
|
|
62
74
|
@prepared_pyproject = T.let(nil, T.nilable(String))
|
|
63
75
|
@updated_lockfile_content = T.let(nil, T.nilable(String))
|
|
64
76
|
@pyproject = T.let(nil, T.nilable(Dependabot::DependencyFile))
|
|
@@ -112,7 +124,9 @@ module Dependabot
|
|
|
112
124
|
# Use updated_lockfile_content which might raise if the lockfile doesn't change
|
|
113
125
|
new_content = updated_lockfile_content
|
|
114
126
|
|
|
115
|
-
|
|
127
|
+
if T.must(lockfile).content == new_content
|
|
128
|
+
raise DependencyFileContentNotChanged, "Expected lockfile to change!"
|
|
129
|
+
end
|
|
116
130
|
|
|
117
131
|
updated_files << updated_file(file: T.must(lockfile), content: new_content)
|
|
118
132
|
end
|
|
@@ -291,7 +305,14 @@ module Dependabot
|
|
|
291
305
|
# Strip extras from the package name for the uv lock command
|
|
292
306
|
# uv lock --upgrade-package expects the base package name without extras
|
|
293
307
|
base_dep_name = normalise(dep_name)
|
|
294
|
-
package_spec =
|
|
308
|
+
package_spec =
|
|
309
|
+
if target_requirement
|
|
310
|
+
"#{base_dep_name}#{target_requirement}"
|
|
311
|
+
elsif dep_version
|
|
312
|
+
"#{base_dep_name}==#{dep_version}"
|
|
313
|
+
else
|
|
314
|
+
base_dep_name
|
|
315
|
+
end
|
|
295
316
|
|
|
296
317
|
command = "pyenv exec uv lock --upgrade-package #{package_spec} #{options}"
|
|
297
318
|
fingerprint = "pyenv exec uv lock --upgrade-package <dependency_name> #{options_fingerprint}"
|
|
@@ -2,9 +2,17 @@
|
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
4
|
require "sorbet-runtime"
|
|
5
|
+
require "toml-rb"
|
|
5
6
|
|
|
7
|
+
require "dependabot/errors"
|
|
6
8
|
require "dependabot/package/release_cooldown_options"
|
|
9
|
+
require "dependabot/update_checkers/version_filters"
|
|
7
10
|
require "dependabot/uv/version"
|
|
11
|
+
require "dependabot/uv/file_updater/lock_file_error_handler"
|
|
12
|
+
require "dependabot/uv/file_updater/lock_file_updater"
|
|
13
|
+
require "dependabot/uv/file_parser/python_requirement_parser"
|
|
14
|
+
require "dependabot/uv/language_version_manager"
|
|
15
|
+
require "dependabot/uv/name_normaliser"
|
|
8
16
|
require "dependabot/uv/requirement"
|
|
9
17
|
require "dependabot/uv/update_checker"
|
|
10
18
|
require "dependabot/uv/update_checker/latest_version_finder"
|
|
@@ -42,33 +50,42 @@ module Dependabot
|
|
|
42
50
|
@security_advisories = security_advisories
|
|
43
51
|
@ignored_versions = ignored_versions
|
|
44
52
|
@update_cooldown = update_cooldown
|
|
53
|
+
@latest_resolvable_versions = T.let(
|
|
54
|
+
{},
|
|
55
|
+
T::Hash[String, T.nilable(Dependabot::Uv::Version)]
|
|
56
|
+
)
|
|
57
|
+
@resolved_versions = T.let(
|
|
58
|
+
{},
|
|
59
|
+
T::Hash[String, T.nilable(Dependabot::Uv::Version)]
|
|
60
|
+
)
|
|
61
|
+
@resolvable_versions = T.let({}, T::Hash[String, T::Boolean])
|
|
45
62
|
end
|
|
46
63
|
|
|
47
64
|
sig { params(requirement: T.nilable(String)).returns(T.nilable(Dependabot::Uv::Version)) }
|
|
48
65
|
def latest_resolvable_version(requirement:)
|
|
49
66
|
return nil unless requirement
|
|
67
|
+
return @latest_resolvable_versions[requirement] if @latest_resolvable_versions.key?(requirement)
|
|
50
68
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# Get the version from the dependency if available
|
|
54
|
-
version_from_dependency = dependency.version && Uv::Version.new(dependency.version)
|
|
55
|
-
return version_from_dependency if version_from_dependency && req.satisfied_by?(version_from_dependency)
|
|
56
|
-
|
|
57
|
-
nil
|
|
69
|
+
@latest_resolvable_versions[requirement] = fetch_latest_resolvable_version(requirement)
|
|
58
70
|
end
|
|
59
71
|
|
|
60
|
-
sig { params(
|
|
61
|
-
def resolvable?(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
72
|
+
sig { params(version: Gem::Version).returns(T::Boolean) }
|
|
73
|
+
def resolvable?(version:)
|
|
74
|
+
target_version = Uv::Version.new(version.to_s)
|
|
75
|
+
key = target_version.to_s
|
|
76
|
+
return T.must(@resolvable_versions[key]) if @resolvable_versions.key?(key)
|
|
77
|
+
|
|
78
|
+
@resolvable_versions[key] = resolved_version("==#{key}", target_version)&.to_s == key
|
|
65
79
|
end
|
|
66
80
|
|
|
67
81
|
sig { returns(T.nilable(Dependabot::Uv::Version)) }
|
|
68
82
|
def lowest_resolvable_security_fix_version
|
|
69
83
|
# Delegate to LatestVersionFinder which handles security advisory filtering
|
|
70
|
-
fix_version = latest_version_finder.lowest_security_fix_version
|
|
71
|
-
|
|
84
|
+
fix_version = latest_version_finder.lowest_security_fix_version(
|
|
85
|
+
language_version: python_version
|
|
86
|
+
)
|
|
87
|
+
return nil unless fix_version
|
|
88
|
+
return nil unless resolvable?(version: fix_version)
|
|
72
89
|
|
|
73
90
|
# Return the fix version cast to Uv::Version
|
|
74
91
|
Uv::Version.new(fix_version.to_s)
|
|
@@ -97,6 +114,191 @@ module Dependabot
|
|
|
97
114
|
sig { returns(T.nilable(Dependabot::Package::ReleaseCooldownOptions)) }
|
|
98
115
|
attr_reader :update_cooldown
|
|
99
116
|
|
|
117
|
+
sig { params(requirement_string: String).returns(T.nilable(Dependabot::Uv::Version)) }
|
|
118
|
+
def fetch_latest_resolvable_version(requirement_string)
|
|
119
|
+
requirement = Uv::Requirement.new(requirement_string)
|
|
120
|
+
current_version = dependency.version && Uv::Version.new(dependency.version)
|
|
121
|
+
eligible_versions = eligible_versions(requirement, current_version)
|
|
122
|
+
return current_version if no_newer_eligible_version?(requirement, current_version, eligible_versions)
|
|
123
|
+
|
|
124
|
+
native_version = resolved_version(
|
|
125
|
+
policy_requirement(requirement_string, requirement, current_version, eligible_versions),
|
|
126
|
+
nil
|
|
127
|
+
)
|
|
128
|
+
if eligible_native_version?(requirement, native_version, eligible_versions) &&
|
|
129
|
+
resolvable?(version: T.must(native_version))
|
|
130
|
+
return native_version
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
current_version if current_version && requirement.satisfied_by?(current_version)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
sig do
|
|
137
|
+
params(
|
|
138
|
+
requirement: Dependabot::Uv::Requirement,
|
|
139
|
+
current_version: T.nilable(Dependabot::Uv::Version),
|
|
140
|
+
eligible_versions: T.nilable(T::Array[Dependabot::Uv::Version])
|
|
141
|
+
).returns(T::Boolean)
|
|
142
|
+
end
|
|
143
|
+
def no_newer_eligible_version?(requirement, current_version, eligible_versions)
|
|
144
|
+
return false unless current_version && eligible_versions
|
|
145
|
+
|
|
146
|
+
requirement.satisfied_by?(current_version) && eligible_versions.empty?
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
sig do
|
|
150
|
+
params(
|
|
151
|
+
requirement: Dependabot::Uv::Requirement,
|
|
152
|
+
native_version: T.nilable(Dependabot::Uv::Version),
|
|
153
|
+
eligible_versions: T.nilable(T::Array[Dependabot::Uv::Version])
|
|
154
|
+
).returns(T::Boolean)
|
|
155
|
+
end
|
|
156
|
+
def eligible_native_version?(requirement, native_version, eligible_versions)
|
|
157
|
+
return false unless native_version && requirement.satisfied_by?(native_version)
|
|
158
|
+
|
|
159
|
+
!eligible_versions || eligible_versions.include?(native_version)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
sig do
|
|
163
|
+
params(
|
|
164
|
+
requirement: Dependabot::Uv::Requirement,
|
|
165
|
+
current_version: T.nilable(Dependabot::Uv::Version)
|
|
166
|
+
).returns(T.nilable(T::Array[Dependabot::Uv::Version]))
|
|
167
|
+
end
|
|
168
|
+
def eligible_versions(requirement, current_version)
|
|
169
|
+
releases = latest_version_finder.eligible_releases(
|
|
170
|
+
language_version: python_version
|
|
171
|
+
)
|
|
172
|
+
return unless releases
|
|
173
|
+
|
|
174
|
+
releases = Dependabot::UpdateCheckers::VersionFilters
|
|
175
|
+
.filter_vulnerable_versions(releases, security_advisories)
|
|
176
|
+
releases
|
|
177
|
+
.map { |release| Uv::Version.new(release.version.to_s) }
|
|
178
|
+
.select { |version| requirement.satisfied_by?(version) && (!current_version || version > current_version) }
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
sig do
|
|
182
|
+
params(
|
|
183
|
+
requirement_string: String,
|
|
184
|
+
requirement: Dependabot::Uv::Requirement,
|
|
185
|
+
current_version: T.nilable(Dependabot::Uv::Version),
|
|
186
|
+
eligible_versions: T.nilable(T::Array[Dependabot::Uv::Version])
|
|
187
|
+
).returns(String)
|
|
188
|
+
end
|
|
189
|
+
def policy_requirement(requirement_string, requirement, current_version, eligible_versions)
|
|
190
|
+
releases = latest_version_finder.available_versions
|
|
191
|
+
return requirement_string unless releases && eligible_versions
|
|
192
|
+
|
|
193
|
+
excluded_versions = releases
|
|
194
|
+
.map { |release| Uv::Version.new(release.version.to_s) }
|
|
195
|
+
.select do |version|
|
|
196
|
+
requirement.satisfied_by?(version) &&
|
|
197
|
+
(!current_version || version > current_version) &&
|
|
198
|
+
!eligible_versions.include?(version)
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
([requirement_string] + excluded_versions.map { |version| "!=#{version}" }).join(",")
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
sig do
|
|
205
|
+
params(
|
|
206
|
+
requirement_string: String,
|
|
207
|
+
target_version: T.nilable(Dependabot::Uv::Version)
|
|
208
|
+
)
|
|
209
|
+
.returns(T.nilable(Dependabot::Uv::Version))
|
|
210
|
+
end
|
|
211
|
+
def resolved_version(requirement_string, target_version)
|
|
212
|
+
return @resolved_versions[requirement_string] if @resolved_versions.key?(requirement_string)
|
|
213
|
+
|
|
214
|
+
@resolved_versions[requirement_string] = run_resolution(requirement_string, target_version)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
sig do
|
|
218
|
+
params(
|
|
219
|
+
requirement_string: String,
|
|
220
|
+
target_version: T.nilable(Dependabot::Uv::Version)
|
|
221
|
+
)
|
|
222
|
+
.returns(T.nilable(Dependabot::Uv::Version))
|
|
223
|
+
end
|
|
224
|
+
def run_resolution(requirement_string, target_version)
|
|
225
|
+
updated_dependency = Dependabot::Dependency.new(
|
|
226
|
+
name: dependency.name,
|
|
227
|
+
version: nil,
|
|
228
|
+
previous_version: dependency.version,
|
|
229
|
+
requirements: [],
|
|
230
|
+
previous_requirements: [],
|
|
231
|
+
package_manager: dependency.package_manager
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
updated_files = FileUpdater::LockFileUpdater.new(
|
|
235
|
+
dependencies: [updated_dependency],
|
|
236
|
+
dependency_files: dependency_files,
|
|
237
|
+
credentials: credentials,
|
|
238
|
+
repo_contents_path: repo_contents_path,
|
|
239
|
+
target_requirement: requirement_string
|
|
240
|
+
).updated_dependency_files
|
|
241
|
+
|
|
242
|
+
lockfile = updated_files.find { |file| file.name == "uv.lock" } || original_lockfile
|
|
243
|
+
resolved_locked_version(T.must(lockfile), target_version)
|
|
244
|
+
rescue Dependabot::DependencyFileContentNotChanged
|
|
245
|
+
resolved_locked_version(T.must(original_lockfile), target_version)
|
|
246
|
+
rescue Dependabot::UpdateNotPossible
|
|
247
|
+
nil
|
|
248
|
+
rescue Dependabot::DependencyFileNotResolvable => e
|
|
249
|
+
conflict = e.message.match?(FileUpdater::LockFileErrorHandler::UV_UNRESOLVABLE_REGEX) ||
|
|
250
|
+
e.message.include?(FileUpdater::LockFileErrorHandler::RESOLUTION_IMPOSSIBLE_ERROR)
|
|
251
|
+
raise unless conflict
|
|
252
|
+
|
|
253
|
+
nil
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
sig do
|
|
257
|
+
params(
|
|
258
|
+
lockfile: Dependabot::DependencyFile,
|
|
259
|
+
target_version: T.nilable(Dependabot::Uv::Version)
|
|
260
|
+
).returns(T.nilable(Dependabot::Uv::Version))
|
|
261
|
+
end
|
|
262
|
+
def resolved_locked_version(lockfile, target_version)
|
|
263
|
+
original_versions = locked_versions(T.must(original_lockfile))
|
|
264
|
+
updated_versions = locked_versions(lockfile)
|
|
265
|
+
current_version = dependency.version && Uv::Version.new(dependency.version)
|
|
266
|
+
return nil unless current_version && original_versions.min == current_version
|
|
267
|
+
return current_version if updated_versions.include?(current_version)
|
|
268
|
+
|
|
269
|
+
updated_version = updated_versions.min
|
|
270
|
+
return target_version if target_version && updated_version == target_version
|
|
271
|
+
return nil if target_version
|
|
272
|
+
|
|
273
|
+
updated_version
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
sig do
|
|
277
|
+
params(lockfile: Dependabot::DependencyFile)
|
|
278
|
+
.returns(T::Array[Dependabot::Uv::Version])
|
|
279
|
+
end
|
|
280
|
+
def locked_versions(lockfile)
|
|
281
|
+
parsed = T.cast(TomlRB.parse(T.must(lockfile.content)), T::Hash[String, Object])
|
|
282
|
+
packages = T.cast(parsed["package"], T.nilable(T::Array[T::Hash[String, Object]])) || []
|
|
283
|
+
dependency_name = NameNormaliser.normalise(dependency.name)
|
|
284
|
+
versions = T.let([], T::Array[Dependabot::Uv::Version])
|
|
285
|
+
packages.each do |package|
|
|
286
|
+
package_name = T.cast(package["name"], T.nilable(String))
|
|
287
|
+
package_version = T.cast(package["version"], T.nilable(String))
|
|
288
|
+
next unless package_name && NameNormaliser.normalise(package_name) == dependency_name
|
|
289
|
+
next unless Uv::Version.correct?(package_version)
|
|
290
|
+
|
|
291
|
+
versions << Uv::Version.new(package_version)
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
versions
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
|
298
|
+
def original_lockfile
|
|
299
|
+
dependency_files.find { |file| file.name == "uv.lock" }
|
|
300
|
+
end
|
|
301
|
+
|
|
100
302
|
sig { returns(LatestVersionFinder) }
|
|
101
303
|
def latest_version_finder
|
|
102
304
|
@latest_version_finder ||= T.let(
|
|
@@ -112,6 +314,18 @@ module Dependabot
|
|
|
112
314
|
T.nilable(LatestVersionFinder)
|
|
113
315
|
)
|
|
114
316
|
end
|
|
317
|
+
|
|
318
|
+
sig { returns(String) }
|
|
319
|
+
def python_version
|
|
320
|
+
@python_version ||= T.let(
|
|
321
|
+
LanguageVersionManager.new(
|
|
322
|
+
python_requirement_parser: FileParser::PythonRequirementParser.new(
|
|
323
|
+
dependency_files: dependency_files
|
|
324
|
+
)
|
|
325
|
+
).python_version,
|
|
326
|
+
T.nilable(String)
|
|
327
|
+
)
|
|
328
|
+
end
|
|
115
329
|
end
|
|
116
330
|
end
|
|
117
331
|
end
|
|
@@ -213,29 +213,6 @@ module Dependabot
|
|
|
213
213
|
)
|
|
214
214
|
end
|
|
215
215
|
|
|
216
|
-
sig { override.returns(T::Boolean) }
|
|
217
|
-
def library?
|
|
218
|
-
return false unless updating_pyproject?
|
|
219
|
-
return false unless library_details
|
|
220
|
-
|
|
221
|
-
return false if T.must(library_details)["name"].nil?
|
|
222
|
-
|
|
223
|
-
# Hit PyPi and check whether there are details for a library with a
|
|
224
|
-
# matching name and description
|
|
225
|
-
index_response = Dependabot::RegistryClient.get(
|
|
226
|
-
url: "https://pypi.org/pypi/#{normalised_name(T.must(library_details)['name'])}/json/"
|
|
227
|
-
)
|
|
228
|
-
|
|
229
|
-
return false unless index_response.status == 200
|
|
230
|
-
|
|
231
|
-
pypi_info = JSON.parse(index_response.body)["info"] || {}
|
|
232
|
-
pypi_info["summary"] == T.must(library_details)["description"]
|
|
233
|
-
rescue Excon::Error::Timeout, Excon::Error::Socket
|
|
234
|
-
false
|
|
235
|
-
rescue URI::InvalidURIError
|
|
236
|
-
false
|
|
237
|
-
end
|
|
238
|
-
|
|
239
216
|
sig { returns(T::Boolean) }
|
|
240
217
|
def updating_pyproject?
|
|
241
218
|
requirement_files.any? { |file| file.end_with?("pyproject.toml") }
|
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.394.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.394.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.394.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.394.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.394.0
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: debug
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -183,14 +183,14 @@ dependencies:
|
|
|
183
183
|
requirements:
|
|
184
184
|
- - "~>"
|
|
185
185
|
- !ruby/object:Gem::Version
|
|
186
|
-
version: '
|
|
186
|
+
version: '1.1'
|
|
187
187
|
type: :development
|
|
188
188
|
prerelease: false
|
|
189
189
|
version_requirements: !ruby/object:Gem::Requirement
|
|
190
190
|
requirements:
|
|
191
191
|
- - "~>"
|
|
192
192
|
- !ruby/object:Gem::Version
|
|
193
|
-
version: '
|
|
193
|
+
version: '1.1'
|
|
194
194
|
- !ruby/object:Gem::Dependency
|
|
195
195
|
name: turbo_tests
|
|
196
196
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -301,7 +301,7 @@ licenses:
|
|
|
301
301
|
- MIT
|
|
302
302
|
metadata:
|
|
303
303
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
304
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
304
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.394.0
|
|
305
305
|
rdoc_options: []
|
|
306
306
|
require_paths:
|
|
307
307
|
- lib
|