dependabot-uv 0.299.1 → 0.301.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_fetcher.rb +55 -25
- data/lib/dependabot/uv/file_parser/python_requirement_parser.rb +5 -44
- data/lib/dependabot/uv/file_parser.rb +77 -101
- data/lib/dependabot/uv/file_updater/lock_file_updater.rb +392 -0
- data/lib/dependabot/uv/file_updater/pyproject_preparer.rb +97 -77
- data/lib/dependabot/uv/file_updater.rb +14 -1
- data/lib/dependabot/uv/{pip_compile_file_matcher.rb → requirements_file_matcher.rb} +5 -5
- data/lib/dependabot/uv/update_checker/lock_file_resolver.rb +48 -0
- data/lib/dependabot/uv/update_checker.rb +12 -1
- metadata +8 -7
- data/lib/dependabot/uv/file_parser/pipfile_files_parser.rb +0 -192
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8eea1accc31d49dda91328296fc952b9d49a1e3cfddb443772b1cd794905779
|
4
|
+
data.tar.gz: a6978d2a2679d009129333b785331ee903b19b5ef673bdba89d81a1b8d67473f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5e5c87148fd6d1db52d0a5fe59b6855a2e0fa50396b6613cb01f7d9ef86845b3c191b5b3dd8188f245c1fc230617c44b8f0531bd03fb4f15b695fc60d2674ee5
|
7
|
+
data.tar.gz: 2802f6b46388ca8a30bebfc56cf02594eaff5cf87aed03cf0c79facf0e6f13b62b150426ea2341f636607d2e8f48e899a92724451ffca00d2397c3870ca2c01e
|
@@ -7,7 +7,7 @@ require "sorbet-runtime"
|
|
7
7
|
require "dependabot/file_fetchers"
|
8
8
|
require "dependabot/file_fetchers/base"
|
9
9
|
require "dependabot/uv/language_version_manager"
|
10
|
-
require "dependabot/uv/
|
10
|
+
require "dependabot/uv/requirements_file_matcher"
|
11
11
|
require "dependabot/uv/requirement_parser"
|
12
12
|
require "dependabot/uv/file_parser/pyproject_files_parser"
|
13
13
|
require "dependabot/uv/file_parser/python_requirement_parser"
|
@@ -22,19 +22,24 @@ module Dependabot
|
|
22
22
|
CHILD_REQUIREMENT_REGEX = /^-r\s?(?<path>.*\.(?:txt|in))/
|
23
23
|
CONSTRAINT_REGEX = /^-c\s?(?<path>.*\.(?:txt|in))/
|
24
24
|
DEPENDENCY_TYPES = %w(packages dev-packages).freeze
|
25
|
+
REQUIREMENT_FILE_PATTERNS = {
|
26
|
+
extensions: [".txt", ".in"],
|
27
|
+
filenames: ["uv.lock"]
|
28
|
+
}.freeze
|
29
|
+
MAX_FILE_SIZE = 500_000
|
25
30
|
|
26
31
|
def self.required_files_in?(filenames)
|
27
|
-
return true if filenames.any? { |name| name.end_with?(
|
32
|
+
return true if filenames.any? { |name| name.end_with?(*REQUIREMENT_FILE_PATTERNS[:extensions]) }
|
28
33
|
|
29
34
|
# If there is a directory of requirements return true
|
30
35
|
return true if filenames.include?("requirements")
|
31
36
|
|
32
|
-
# If this repo is using pyproject.toml return true
|
37
|
+
# If this repo is using pyproject.toml return true (uv.lock files require a pyproject.toml)
|
33
38
|
filenames.include?("pyproject.toml")
|
34
39
|
end
|
35
40
|
|
36
41
|
def self.required_files_message
|
37
|
-
"Repo must contain a requirements.txt, requirements.in, or pyproject.toml" \
|
42
|
+
"Repo must contain a requirements.txt, uv.lock, requirements.in, or pyproject.toml" \
|
38
43
|
end
|
39
44
|
|
40
45
|
def ecosystem_versions
|
@@ -69,6 +74,7 @@ module Dependabot
|
|
69
74
|
fetched_files += requirements_in_files
|
70
75
|
fetched_files += requirement_files if requirements_txt_files.any?
|
71
76
|
|
77
|
+
fetched_files += uv_lock_files
|
72
78
|
fetched_files += project_files
|
73
79
|
fetched_files << python_version_file if python_version_file
|
74
80
|
|
@@ -125,6 +131,11 @@ module Dependabot
|
|
125
131
|
child_requirement_in_files
|
126
132
|
end
|
127
133
|
|
134
|
+
def uv_lock_files
|
135
|
+
req_txt_and_in_files.select { |f| f.name.end_with?("uv.lock") } +
|
136
|
+
child_uv_lock_files
|
137
|
+
end
|
138
|
+
|
128
139
|
def parsed_pyproject
|
129
140
|
raise "No pyproject.toml" unless pyproject
|
130
141
|
|
@@ -137,18 +148,8 @@ module Dependabot
|
|
137
148
|
return @req_txt_and_in_files if @req_txt_and_in_files
|
138
149
|
|
139
150
|
@req_txt_and_in_files = []
|
140
|
-
|
141
|
-
|
142
|
-
.select { |f| f.type == "file" }
|
143
|
-
.select { |f| f.name.end_with?(".txt", ".in") }
|
144
|
-
.reject { |f| f.size > 500_000 }
|
145
|
-
.map { |f| fetch_file_from_host(f.name) }
|
146
|
-
.select { |f| requirements_file?(f) }
|
147
|
-
.each { |f| @req_txt_and_in_files << f }
|
148
|
-
|
149
|
-
repo_contents
|
150
|
-
.select { |f| f.type == "dir" }
|
151
|
-
.each { |f| @req_txt_and_in_files += req_files_for_dir(f) }
|
151
|
+
@req_txt_and_in_files += fetch_requirement_files_from_path
|
152
|
+
@req_txt_and_in_files += fetch_requirement_files_from_dirs
|
152
153
|
|
153
154
|
@req_txt_and_in_files
|
154
155
|
end
|
@@ -158,12 +159,7 @@ module Dependabot
|
|
158
159
|
relative_reqs_dir =
|
159
160
|
requirements_dir.path.gsub(%r{^/?#{Regexp.escape(dir)}/?}, "")
|
160
161
|
|
161
|
-
|
162
|
-
.select { |f| f.type == "file" }
|
163
|
-
.select { |f| f.name.end_with?(".txt", ".in") }
|
164
|
-
.reject { |f| f.size > 500_000 }
|
165
|
-
.map { |f| fetch_file_from_host("#{relative_reqs_dir}/#{f.name}") }
|
166
|
-
.select { |f| requirements_file?(f) }
|
162
|
+
fetch_requirement_files_from_path(relative_reqs_dir)
|
167
163
|
end
|
168
164
|
|
169
165
|
def child_requirement_txt_files
|
@@ -174,6 +170,10 @@ module Dependabot
|
|
174
170
|
child_requirement_files.select { |f| f.name.end_with?(".in") }
|
175
171
|
end
|
176
172
|
|
173
|
+
def child_uv_lock_files
|
174
|
+
child_requirement_files.select { |f| f.name.end_with?("uv.lock") }
|
175
|
+
end
|
176
|
+
|
177
177
|
def child_requirement_files
|
178
178
|
@child_requirement_files ||=
|
179
179
|
begin
|
@@ -295,7 +295,7 @@ module Dependabot
|
|
295
295
|
|
296
296
|
def parse_requirement_path_dependencies(req_file)
|
297
297
|
# If this is a pip-compile lockfile, rely on whatever path dependencies we found in the main manifest
|
298
|
-
return [] if
|
298
|
+
return [] if requirements_in_file_matcher.compiled_file?(req_file)
|
299
299
|
|
300
300
|
uneditable_reqs =
|
301
301
|
req_file.content
|
@@ -318,8 +318,38 @@ module Dependabot
|
|
318
318
|
Pathname.new(path).cleanpath.to_path
|
319
319
|
end
|
320
320
|
|
321
|
-
def
|
322
|
-
@
|
321
|
+
def requirements_in_file_matcher
|
322
|
+
@requirements_in_file_matcher ||= RequiremenstFileMatcher.new(requirements_in_files)
|
323
|
+
end
|
324
|
+
|
325
|
+
def fetch_requirement_files_from_path(path = nil)
|
326
|
+
contents = path ? repo_contents(dir: path) : repo_contents
|
327
|
+
filter_requirement_files(contents, base_path: path)
|
328
|
+
end
|
329
|
+
|
330
|
+
def fetch_requirement_files_from_dirs
|
331
|
+
repo_contents
|
332
|
+
.select { |f| f.type == "dir" }
|
333
|
+
.flat_map { |dir| req_files_for_dir(dir) }
|
334
|
+
end
|
335
|
+
|
336
|
+
def filter_requirement_files(contents, base_path: nil)
|
337
|
+
contents
|
338
|
+
.select { |f| f.type == "file" }
|
339
|
+
.select { |f| file_matches_requirement_pattern?(f.name) }
|
340
|
+
.reject { |f| f.size > MAX_FILE_SIZE }
|
341
|
+
.map { |f| fetch_file_with_path(f.name, base_path) }
|
342
|
+
.select { |f| REQUIREMENT_FILE_PATTERNS[:filenames].include?(f.name) || requirements_file?(f) }
|
343
|
+
end
|
344
|
+
|
345
|
+
def file_matches_requirement_pattern?(filename)
|
346
|
+
REQUIREMENT_FILE_PATTERNS[:extensions].any? { |ext| filename.end_with?(ext) } ||
|
347
|
+
REQUIREMENT_FILE_PATTERNS[:filenames].any?(filename)
|
348
|
+
end
|
349
|
+
|
350
|
+
def fetch_file_with_path(filename, base_path)
|
351
|
+
path = base_path ? File.join(base_path, filename) : filename
|
352
|
+
fetch_file_from_host(path)
|
323
353
|
end
|
324
354
|
end
|
325
355
|
end
|
@@ -6,7 +6,7 @@ require "open3"
|
|
6
6
|
require "dependabot/errors"
|
7
7
|
require "dependabot/shared_helpers"
|
8
8
|
require "dependabot/uv/file_parser"
|
9
|
-
require "dependabot/uv/
|
9
|
+
require "dependabot/uv/requirements_file_matcher"
|
10
10
|
require "dependabot/uv/requirement"
|
11
11
|
|
12
12
|
module Dependabot
|
@@ -21,12 +21,10 @@ module Dependabot
|
|
21
21
|
|
22
22
|
def user_specified_requirements
|
23
23
|
[
|
24
|
-
pipfile_python_requirement,
|
25
24
|
pyproject_python_requirement,
|
26
25
|
pip_compile_python_requirement,
|
27
26
|
python_version_file_version,
|
28
|
-
runtime_file_python_version
|
29
|
-
setup_file_requirement
|
27
|
+
runtime_file_python_version
|
30
28
|
].compact
|
31
29
|
end
|
32
30
|
|
@@ -44,18 +42,6 @@ module Dependabot
|
|
44
42
|
|
45
43
|
private
|
46
44
|
|
47
|
-
def pipfile_python_requirement
|
48
|
-
return unless pipfile
|
49
|
-
|
50
|
-
parsed_pipfile = TomlRB.parse(pipfile.content)
|
51
|
-
requirement =
|
52
|
-
parsed_pipfile.dig("requires", "python_full_version") ||
|
53
|
-
parsed_pipfile.dig("requires", "python_version")
|
54
|
-
return unless requirement&.match?(/^\d/)
|
55
|
-
|
56
|
-
requirement
|
57
|
-
end
|
58
|
-
|
59
45
|
def pyproject_python_requirement
|
60
46
|
return unless pyproject
|
61
47
|
|
@@ -74,7 +60,7 @@ module Dependabot
|
|
74
60
|
|
75
61
|
def pip_compile_python_requirement
|
76
62
|
requirement_files.each do |file|
|
77
|
-
next unless
|
63
|
+
next unless requirements_in_file_matcher.compiled_file?(file)
|
78
64
|
|
79
65
|
marker = /^# This file is autogenerated by pip-compile with [pP]ython (?<version>\d+.\d+)$/m
|
80
66
|
match = marker.match(file.content)
|
@@ -112,19 +98,6 @@ module Dependabot
|
|
112
98
|
file_version
|
113
99
|
end
|
114
100
|
|
115
|
-
def setup_file_requirement
|
116
|
-
return unless setup_file
|
117
|
-
|
118
|
-
req = setup_file.content
|
119
|
-
.match(/python_requires\s*=\s*['"](?<req>[^'"]+)['"]/)
|
120
|
-
&.named_captures&.fetch("req")&.strip
|
121
|
-
|
122
|
-
requirement_class.new(req)
|
123
|
-
req
|
124
|
-
rescue Gem::Requirement::BadRequirementError
|
125
|
-
nil
|
126
|
-
end
|
127
|
-
|
128
101
|
def pyenv_versions
|
129
102
|
@pyenv_versions ||= run_command("pyenv install --list")
|
130
103
|
end
|
@@ -133,8 +106,8 @@ module Dependabot
|
|
133
106
|
SharedHelpers.run_shell_command(command, env: env, stderr_to_stdout: true)
|
134
107
|
end
|
135
108
|
|
136
|
-
def
|
137
|
-
@
|
109
|
+
def requirements_in_file_matcher
|
110
|
+
@requirements_in_file_matcher ||= RequiremenstFileMatcher.new(pip_compile_files)
|
138
111
|
end
|
139
112
|
|
140
113
|
def requirement_class
|
@@ -148,22 +121,10 @@ module Dependabot
|
|
148
121
|
false
|
149
122
|
end
|
150
123
|
|
151
|
-
def pipfile
|
152
|
-
dependency_files.find { |f| f.name == "Pipfile" }
|
153
|
-
end
|
154
|
-
|
155
|
-
def pipfile_lock
|
156
|
-
dependency_files.find { |f| f.name == "Pipfile.lock" }
|
157
|
-
end
|
158
|
-
|
159
124
|
def pyproject
|
160
125
|
dependency_files.find { |f| f.name == "pyproject.toml" }
|
161
126
|
end
|
162
127
|
|
163
|
-
def setup_file
|
164
|
-
dependency_files.find { |f| f.name == "setup.py" }
|
165
|
-
end
|
166
|
-
|
167
128
|
def python_version_file
|
168
129
|
dependency_files.find { |f| f.name == ".python-version" }
|
169
130
|
end
|
@@ -11,17 +11,16 @@ require "dependabot/errors"
|
|
11
11
|
require "dependabot/uv/language"
|
12
12
|
require "dependabot/uv/native_helpers"
|
13
13
|
require "dependabot/uv/name_normaliser"
|
14
|
-
require "dependabot/uv/
|
14
|
+
require "dependabot/uv/requirements_file_matcher"
|
15
15
|
require "dependabot/uv/language_version_manager"
|
16
16
|
require "dependabot/uv/package_manager"
|
17
|
+
require "toml-rb"
|
17
18
|
|
18
19
|
module Dependabot
|
19
20
|
module Uv
|
20
21
|
class FileParser < Dependabot::FileParsers::Base
|
21
22
|
extend T::Sig
|
22
|
-
require_relative "file_parser/pipfile_files_parser"
|
23
23
|
require_relative "file_parser/pyproject_files_parser"
|
24
|
-
require_relative "file_parser/setup_file_parser"
|
25
24
|
require_relative "file_parser/python_requirement_parser"
|
26
25
|
|
27
26
|
DEPENDENCY_GROUP_KEYS = T.let([
|
@@ -40,18 +39,16 @@ module Dependabot
|
|
40
39
|
).freeze
|
41
40
|
|
42
41
|
# we use this placeholder version in case we are not able to detect any
|
43
|
-
#
|
42
|
+
# uv version from shell, we are ensuring that the actual update is not blocked
|
44
43
|
# in any way if any metric collection exception start happening
|
45
44
|
UNDETECTED_PACKAGE_MANAGER_VERSION = "0.0"
|
46
45
|
|
47
|
-
sig { override.returns(T::Array[
|
46
|
+
sig { override.returns(T::Array[Dependency]) }
|
48
47
|
def parse
|
49
|
-
# TODO: setup.py from external dependencies is evaluated. Provide guards before removing this.
|
50
|
-
raise Dependabot::UnexpectedExternalCode if @reject_external_code
|
51
|
-
|
52
48
|
dependency_set = DependencySet.new
|
53
49
|
|
54
50
|
dependency_set += pyproject_file_dependencies if pyproject
|
51
|
+
dependency_set += uv_lock_file_dependencies
|
55
52
|
dependency_set += requirement_dependencies if requirement_files.any?
|
56
53
|
|
57
54
|
dependency_set.dependencies
|
@@ -69,58 +66,57 @@ module Dependabot
|
|
69
66
|
)
|
70
67
|
end
|
71
68
|
|
69
|
+
# Normalize dependency names to match the PyPI index normalization
|
70
|
+
sig { params(name: String, extras: T::Array[String]).returns(String) }
|
71
|
+
def self.normalize_dependency_name(name, extras = [])
|
72
|
+
NameNormaliser.normalise_including_extras(name, extras)
|
73
|
+
end
|
74
|
+
|
72
75
|
private
|
73
76
|
|
74
|
-
sig { returns(
|
77
|
+
sig { returns(LanguageVersionManager) }
|
75
78
|
def language_version_manager
|
76
79
|
@language_version_manager ||= T.let(LanguageVersionManager.new(python_requirement_parser:
|
77
80
|
python_requirement_parser), T.nilable(LanguageVersionManager))
|
78
81
|
end
|
79
82
|
|
80
|
-
sig { returns(
|
83
|
+
sig { returns(FileParser::PythonRequirementParser) }
|
81
84
|
def python_requirement_parser
|
82
|
-
@python_requirement_parser ||= T.let(
|
83
|
-
dependency_files), T.nilable(
|
85
|
+
@python_requirement_parser ||= T.let(PythonRequirementParser.new(dependency_files:
|
86
|
+
dependency_files), T.nilable(PythonRequirementParser))
|
84
87
|
end
|
85
88
|
|
86
89
|
sig { returns(Ecosystem::VersionManager) }
|
87
90
|
def package_manager
|
88
|
-
if
|
91
|
+
if Experiments.enabled?(:enable_file_parser_python_local)
|
89
92
|
Dependabot.logger.info("Detected package manager : #{detected_package_manager.name}")
|
90
93
|
end
|
91
94
|
|
92
|
-
@package_manager ||= T.let(detected_package_manager, T.nilable(
|
95
|
+
@package_manager ||= T.let(detected_package_manager, T.nilable(Ecosystem::VersionManager))
|
93
96
|
end
|
94
97
|
|
95
98
|
sig { returns(Ecosystem::VersionManager) }
|
96
99
|
def detected_package_manager
|
97
|
-
setup_python_environment if
|
100
|
+
setup_python_environment if Experiments.enabled?(:enable_file_parser_python_local)
|
98
101
|
|
99
|
-
PackageManager.new(T.must(
|
102
|
+
PackageManager.new(T.must(detect_uv_version))
|
100
103
|
end
|
101
104
|
|
102
|
-
# Detects the version of pip-compile. If the version cannot be detected, it returns nil
|
103
105
|
sig { returns(T.nilable(String)) }
|
104
|
-
def
|
105
|
-
|
106
|
-
package_manager = PackageManager::NAME
|
106
|
+
def detect_uv_version
|
107
|
+
version = uv_version.to_s.split("version ").last&.split(")")&.first
|
107
108
|
|
108
|
-
|
109
|
-
.to_s.split("version ").last&.split(")")&.first
|
109
|
+
log_if_version_malformed("uv", version)
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
# makes sure we have correct version format returned
|
114
|
-
version if version&.match?(/^\d+(?:\.\d+)*$/)
|
115
|
-
end
|
111
|
+
version if version&.match?(/^\d+(?:\.\d+)*$/)
|
116
112
|
rescue StandardError
|
117
113
|
nil
|
118
114
|
end
|
119
115
|
|
120
|
-
sig {
|
121
|
-
def
|
122
|
-
version_info = SharedHelpers.run_shell_command("pyenv exec
|
123
|
-
Dependabot.logger.info("Package manager
|
116
|
+
sig { returns(T.any(String, T.untyped)) }
|
117
|
+
def uv_version
|
118
|
+
version_info = SharedHelpers.run_shell_command("pyenv exec uv --version")
|
119
|
+
Dependabot.logger.info("Package manager uv, Info : #{version_info}")
|
124
120
|
|
125
121
|
version_info.match(/\d+(?:\.\d+)*/)&.to_s
|
126
122
|
rescue StandardError => e
|
@@ -128,7 +124,6 @@ module Dependabot
|
|
128
124
|
nil
|
129
125
|
end
|
130
126
|
|
131
|
-
# setup python local setup on file parser stage
|
132
127
|
sig { returns(T.nilable(String)) }
|
133
128
|
def setup_python_environment
|
134
129
|
language_version_manager.install_required_python
|
@@ -141,7 +136,6 @@ module Dependabot
|
|
141
136
|
|
142
137
|
sig { params(package_manager: String, version: String).returns(T::Boolean) }
|
143
138
|
def log_if_version_malformed(package_manager, version)
|
144
|
-
# logs warning if malformed version is found
|
145
139
|
if version.match?(/^\d+(?:\.\d+)*$/)
|
146
140
|
true
|
147
141
|
else
|
@@ -152,7 +146,7 @@ module Dependabot
|
|
152
146
|
|
153
147
|
sig { returns(String) }
|
154
148
|
def python_raw_version
|
155
|
-
if
|
149
|
+
if Experiments.enabled?(:enable_file_parser_python_local)
|
156
150
|
Dependabot.logger.info("Detected python version: #{language_version_manager.python_version}")
|
157
151
|
Dependabot.logger.info("Detected python major minor version: #{language_version_manager.python_major_minor}")
|
158
152
|
end
|
@@ -173,15 +167,39 @@ module Dependabot
|
|
173
167
|
)
|
174
168
|
end
|
175
169
|
|
176
|
-
sig { returns(T::Array[
|
170
|
+
sig { returns(T::Array[DependencyFile]) }
|
177
171
|
def requirement_files
|
178
172
|
dependency_files.select { |f| f.name.end_with?(".txt", ".in") }
|
179
173
|
end
|
180
174
|
|
175
|
+
sig { returns(T::Array[DependencyFile]) }
|
176
|
+
def uv_lock_files
|
177
|
+
dependency_files.select { |f| f.name == "uv.lock" }
|
178
|
+
end
|
179
|
+
|
181
180
|
sig { returns(DependencySet) }
|
182
|
-
def
|
183
|
-
|
184
|
-
|
181
|
+
def uv_lock_file_dependencies
|
182
|
+
dependency_set = DependencySet.new
|
183
|
+
|
184
|
+
uv_lock_files.each do |file|
|
185
|
+
lockfile_content = TomlRB.parse(file.content)
|
186
|
+
packages = lockfile_content.fetch("package", [])
|
187
|
+
|
188
|
+
packages.each do |package_data|
|
189
|
+
next unless package_data.is_a?(Hash) && package_data["name"] && package_data["version"]
|
190
|
+
|
191
|
+
dependency_set << Dependency.new(
|
192
|
+
name: normalised_name(package_data["name"]),
|
193
|
+
version: package_data["version"],
|
194
|
+
requirements: [], # Lock files don't contain requirements
|
195
|
+
package_manager: "uv"
|
196
|
+
)
|
197
|
+
end
|
198
|
+
rescue StandardError => e
|
199
|
+
Dependabot.logger.warn("Error parsing uv.lock: #{e.message}")
|
200
|
+
end
|
201
|
+
|
202
|
+
dependency_set
|
185
203
|
end
|
186
204
|
|
187
205
|
sig { returns(DependencySet) }
|
@@ -194,8 +212,6 @@ module Dependabot
|
|
194
212
|
def requirement_dependencies
|
195
213
|
dependencies = DependencySet.new
|
196
214
|
parsed_requirement_files.each do |dep|
|
197
|
-
# If a requirement has a `<`, `<=` or '==' marker then updating it is
|
198
|
-
# probably blocked. Ignore it.
|
199
215
|
next if blocking_marker?(dep)
|
200
216
|
|
201
217
|
name = dep["name"]
|
@@ -204,7 +220,7 @@ module Dependabot
|
|
204
220
|
original_file = get_original_file(file)
|
205
221
|
|
206
222
|
requirements =
|
207
|
-
if original_file &&
|
223
|
+
if original_file && requirements_in_file_matcher.compiled_file?(original_file) then []
|
208
224
|
else
|
209
225
|
[{
|
210
226
|
requirement: dep["requirement"],
|
@@ -214,7 +230,7 @@ module Dependabot
|
|
214
230
|
}]
|
215
231
|
end
|
216
232
|
|
217
|
-
# PyYAML < 6.0 will cause `pip-compile` to fail due to incompatibility with Cython 3. Workaround it.
|
233
|
+
# PyYAML < 6.0 will cause `pip-compile` to fail due to incompatibility with Cython 3. Workaround it. PR #8189
|
218
234
|
SharedHelpers.run_shell_command("pyenv exec pip install cython<3.0") if old_pyyaml?(name, version)
|
219
235
|
|
220
236
|
dependencies <<
|
@@ -268,7 +284,6 @@ module Dependabot
|
|
268
284
|
def marker_satisfied?(marker, python_version)
|
269
285
|
conditions = marker.split(/\s+(and|or)\s+/)
|
270
286
|
|
271
|
-
# Explicitly define the type of result as T::Boolean
|
272
287
|
result = T.let(evaluate_condition(conditions.shift, python_version), T::Boolean)
|
273
288
|
|
274
289
|
until conditions.empty?
|
@@ -295,26 +310,20 @@ module Dependabot
|
|
295
310
|
|
296
311
|
case operator
|
297
312
|
when "<"
|
298
|
-
|
313
|
+
Version.new(python_version) < Version.new(version)
|
299
314
|
when "<="
|
300
|
-
|
315
|
+
Version.new(python_version) <= Version.new(version)
|
301
316
|
when ">"
|
302
|
-
|
317
|
+
Version.new(python_version) > Version.new(version)
|
303
318
|
when ">="
|
304
|
-
|
319
|
+
Version.new(python_version) >= Version.new(version)
|
305
320
|
when "=="
|
306
|
-
|
321
|
+
Version.new(python_version) == Version.new(version)
|
307
322
|
else
|
308
323
|
false
|
309
324
|
end
|
310
325
|
end
|
311
326
|
|
312
|
-
sig { returns(DependencySet) }
|
313
|
-
def setup_file_dependencies
|
314
|
-
@setup_file_dependencies ||= T.let(SetupFileParser.new(dependency_files: dependency_files)
|
315
|
-
.dependency_set, T.nilable(DependencySet))
|
316
|
-
end
|
317
|
-
|
318
327
|
sig { returns(T.untyped) }
|
319
328
|
def parsed_requirement_files
|
320
329
|
SharedHelpers.in_a_temporary_directory do
|
@@ -333,7 +342,7 @@ module Dependabot
|
|
333
342
|
evaluation_errors = REQUIREMENT_FILE_EVALUATION_ERRORS
|
334
343
|
raise unless e.message.start_with?(*evaluation_errors)
|
335
344
|
|
336
|
-
raise
|
345
|
+
raise DependencyFileNotEvaluatable, e.message
|
337
346
|
end
|
338
347
|
|
339
348
|
sig { params(requirements: T.untyped).returns(T.untyped) }
|
@@ -341,18 +350,13 @@ module Dependabot
|
|
341
350
|
requirements.each do |dep|
|
342
351
|
next unless dep["requirement"]
|
343
352
|
|
344
|
-
|
353
|
+
Requirement.new(dep["requirement"].split(","))
|
345
354
|
rescue Gem::Requirement::BadRequirementError => e
|
346
|
-
raise
|
355
|
+
raise DependencyFileNotEvaluatable, e.message
|
347
356
|
end
|
348
357
|
end
|
349
358
|
|
350
|
-
sig { returns(T::
|
351
|
-
def pipcompile_in_file
|
352
|
-
requirement_files.any? { |f| f.name.end_with?(PackageManager::MANIFEST_FILENAME) }
|
353
|
-
end
|
354
|
-
|
355
|
-
sig { returns(T::Array[Dependabot::DependencyFile]) }
|
359
|
+
sig { returns(T::Array[DependencyFile]) }
|
356
360
|
def write_temporary_dependency_files
|
357
361
|
dependency_files
|
358
362
|
.reject { |f| f.name == ".python-version" }
|
@@ -375,60 +379,32 @@ module Dependabot
|
|
375
379
|
|
376
380
|
sig { params(name: String, extras: T::Array[String]).returns(String) }
|
377
381
|
def normalised_name(name, extras = [])
|
378
|
-
|
382
|
+
FileParser.normalize_dependency_name(name, extras)
|
379
383
|
end
|
380
384
|
|
381
385
|
sig { override.returns(T.untyped) }
|
382
386
|
def check_required_files
|
383
387
|
filenames = dependency_files.map(&:name)
|
384
388
|
return if filenames.any? { |name| name.end_with?(".txt", ".in") }
|
385
|
-
return if pipfile
|
386
389
|
return if pyproject
|
387
|
-
return if setup_file
|
388
|
-
return if setup_cfg_file
|
389
390
|
|
390
391
|
raise "Missing required files!"
|
391
392
|
end
|
392
393
|
|
393
|
-
sig { returns(T.nilable(
|
394
|
-
def pipfile
|
395
|
-
@pipfile ||= T.let(get_original_file("Pipfile"), T.nilable(Dependabot::DependencyFile))
|
396
|
-
end
|
397
|
-
|
398
|
-
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
399
|
-
def pipfile_lock
|
400
|
-
@pipfile_lock ||= T.let(get_original_file("Pipfile.lock"), T.nilable(Dependabot::DependencyFile))
|
401
|
-
end
|
402
|
-
|
403
|
-
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
394
|
+
sig { returns(T.nilable(DependencyFile)) }
|
404
395
|
def pyproject
|
405
|
-
@pyproject ||= T.let(get_original_file("pyproject.toml"), T.nilable(
|
406
|
-
end
|
407
|
-
|
408
|
-
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
409
|
-
def poetry_lock
|
410
|
-
@poetry_lock ||= T.let(get_original_file("poetry.lock"), T.nilable(Dependabot::DependencyFile))
|
411
|
-
end
|
412
|
-
|
413
|
-
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
414
|
-
def setup_file
|
415
|
-
@setup_file ||= T.let(get_original_file("setup.py"), T.nilable(Dependabot::DependencyFile))
|
416
|
-
end
|
417
|
-
|
418
|
-
sig { returns(T.nilable(Dependabot::DependencyFile)) }
|
419
|
-
def setup_cfg_file
|
420
|
-
@setup_cfg_file ||= T.let(get_original_file("setup.cfg"), T.nilable(Dependabot::DependencyFile))
|
396
|
+
@pyproject ||= T.let(get_original_file("pyproject.toml"), T.nilable(DependencyFile))
|
421
397
|
end
|
422
398
|
|
423
|
-
sig { returns(T::Array[
|
424
|
-
def
|
425
|
-
@
|
399
|
+
sig { returns(T::Array[Requirement]) }
|
400
|
+
def requirements_in_files
|
401
|
+
@requirements_in_files ||= T.let(dependency_files.select { |f| f.name.end_with?(".in") }, T.untyped)
|
426
402
|
end
|
427
403
|
|
428
|
-
sig { returns(
|
429
|
-
def
|
430
|
-
@
|
431
|
-
|
404
|
+
sig { returns(RequiremenstFileMatcher) }
|
405
|
+
def requirements_in_file_matcher
|
406
|
+
@requirements_in_file_matcher ||= T.let(RequiremenstFileMatcher.new(requirements_in_files),
|
407
|
+
T.nilable(RequiremenstFileMatcher))
|
432
408
|
end
|
433
409
|
end
|
434
410
|
end
|