dependabot-python 0.357.0 → 0.358.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/python/file_parser/pyproject_files_parser.rb +23 -4
- data/lib/dependabot/python/file_parser.rb +1 -10
- data/lib/dependabot/python/file_updater/poetry_file_updater.rb +43 -0
- data/lib/dependabot/python/update_checker/requirements_updater.rb +2 -2
- data/lib/dependabot/python/update_checker.rb +68 -4
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 48c37437d99c146971cb9ecc12889faf559a657346ca44b95a71bc06d607445a
|
|
4
|
+
data.tar.gz: 163fbc7bfcb2aecde6cbc0f95bdc33bb1cb454201b6014158a65dcc71ab22fc4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: de34134537d989cc22bdea97b581b80e0adf85cde617690689916fbc1169e462d1fdea9c9c40369401ac2edcf4cf21015d3c399c9b4ebaafaf0fa9541109f84f
|
|
7
|
+
data.tar.gz: bf298b6e70c2fd083f89d3186a31d610ac937fe749345974edcce57f5871f97579bd215e3d5897f1b6d82e691a7a400f287c3d97241b50249d73dab2f2b1e765
|
|
@@ -19,7 +19,8 @@ module Dependabot
|
|
|
19
19
|
POETRY_DEPENDENCY_TYPES = %w(dependencies dev-dependencies).freeze
|
|
20
20
|
|
|
21
21
|
# https://python-poetry.org/docs/dependency-specification/
|
|
22
|
-
|
|
22
|
+
# Git dependencies with tags are now supported for version tracking
|
|
23
|
+
UNSUPPORTED_DEPENDENCY_TYPES = %w(path url).freeze
|
|
23
24
|
|
|
24
25
|
sig { params(dependency_files: T::Array[Dependabot::DependencyFile]).void }
|
|
25
26
|
def initialize(dependency_files:)
|
|
@@ -148,13 +149,29 @@ module Dependabot
|
|
|
148
149
|
|
|
149
150
|
# @param req can be an Array, Hash or String that represents the constraints for a dependency
|
|
150
151
|
sig { params(req: T.untyped, type: String).returns(T::Array[T::Hash[Symbol, T.nilable(String)]]) }
|
|
152
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
|
151
153
|
def parse_requirements_from(req, type)
|
|
152
154
|
[req].flatten.compact.filter_map do |requirement|
|
|
155
|
+
# Skip unsupported dependency types (path, url), but allow git
|
|
153
156
|
next if requirement.is_a?(Hash) && UNSUPPORTED_DEPENDENCY_TYPES.intersect?(requirement.keys)
|
|
157
|
+
# Skip git dependencies without tags (e.g., with branch, rev)
|
|
158
|
+
next if requirement.is_a?(Hash) && requirement["git"] && !requirement["tag"]
|
|
154
159
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
# Handle git dependencies with tags
|
|
161
|
+
if requirement.is_a?(Hash) && requirement["git"] && requirement["tag"]
|
|
162
|
+
{
|
|
163
|
+
requirement: nil,
|
|
164
|
+
file: T.must(pyproject).name,
|
|
165
|
+
source: {
|
|
166
|
+
type: "git",
|
|
167
|
+
url: requirement["git"],
|
|
168
|
+
ref: requirement["tag"],
|
|
169
|
+
branch: nil
|
|
170
|
+
},
|
|
171
|
+
groups: [type]
|
|
172
|
+
}
|
|
173
|
+
elsif requirement.is_a?(String)
|
|
174
|
+
check_requirements(requirement)
|
|
158
175
|
{
|
|
159
176
|
requirement: requirement,
|
|
160
177
|
file: T.must(pyproject).name,
|
|
@@ -162,6 +179,7 @@ module Dependabot
|
|
|
162
179
|
groups: [type]
|
|
163
180
|
}
|
|
164
181
|
else
|
|
182
|
+
check_requirements(requirement)
|
|
165
183
|
{
|
|
166
184
|
requirement: requirement["version"],
|
|
167
185
|
file: T.must(pyproject).name,
|
|
@@ -171,6 +189,7 @@ module Dependabot
|
|
|
171
189
|
end
|
|
172
190
|
end
|
|
173
191
|
end
|
|
192
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
|
174
193
|
|
|
175
194
|
sig { returns(T.nilable(T::Boolean)) }
|
|
176
195
|
def using_poetry?
|
|
@@ -101,16 +101,12 @@ module Dependabot
|
|
|
101
101
|
|
|
102
102
|
sig { returns(Ecosystem::VersionManager) }
|
|
103
103
|
def package_manager
|
|
104
|
-
if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
|
|
105
|
-
Dependabot.logger.info("Detected package manager : #{detected_package_manager.name}")
|
|
106
|
-
end
|
|
107
|
-
|
|
108
104
|
@package_manager ||= T.let(detected_package_manager, T.nilable(Dependabot::Ecosystem::VersionManager))
|
|
109
105
|
end
|
|
110
106
|
|
|
111
107
|
sig { returns(Ecosystem::VersionManager) }
|
|
112
108
|
def detected_package_manager
|
|
113
|
-
setup_python_environment
|
|
109
|
+
setup_python_environment
|
|
114
110
|
|
|
115
111
|
return PipenvPackageManager.new(T.must(detect_pipenv_version)) if detect_pipenv_version
|
|
116
112
|
|
|
@@ -225,11 +221,6 @@ module Dependabot
|
|
|
225
221
|
|
|
226
222
|
sig { returns(String) }
|
|
227
223
|
def python_raw_version
|
|
228
|
-
if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
|
|
229
|
-
Dependabot.logger.info("Detected python version: #{language_version_manager.python_version}")
|
|
230
|
-
Dependabot.logger.info("Detected python major minor version: #{language_version_manager.python_major_minor}")
|
|
231
|
-
end
|
|
232
|
-
|
|
233
224
|
language_version_manager.python_version
|
|
234
225
|
end
|
|
235
226
|
|
|
@@ -115,6 +115,9 @@ module Dependabot
|
|
|
115
115
|
).returns(String)
|
|
116
116
|
end
|
|
117
117
|
def replace_dep(dep, content, new_r, old_r)
|
|
118
|
+
# Handle Git dependencies with tags
|
|
119
|
+
return update_git_tag(dep, content, new_r, old_r) if git_dependency?(new_r) && git_dependency?(old_r)
|
|
120
|
+
|
|
118
121
|
new_req = new_r[:requirement]
|
|
119
122
|
old_req = old_r[:requirement]
|
|
120
123
|
|
|
@@ -149,6 +152,38 @@ module Dependabot
|
|
|
149
152
|
content
|
|
150
153
|
end
|
|
151
154
|
|
|
155
|
+
sig { params(req: T::Hash[Symbol, T.untyped]).returns(T::Boolean) }
|
|
156
|
+
def git_dependency?(req)
|
|
157
|
+
req.dig(:source, :type) == "git"
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
sig do
|
|
161
|
+
params(
|
|
162
|
+
dep: Dependabot::Dependency,
|
|
163
|
+
content: String,
|
|
164
|
+
new_r: T::Hash[Symbol, T.untyped],
|
|
165
|
+
old_r: T::Hash[Symbol, T.untyped]
|
|
166
|
+
).returns(String)
|
|
167
|
+
end
|
|
168
|
+
def update_git_tag(dep, content, new_r, old_r)
|
|
169
|
+
old_tag = old_r.dig(:source, :ref)
|
|
170
|
+
new_tag = new_r.dig(:source, :ref)
|
|
171
|
+
|
|
172
|
+
return content if old_tag == new_tag
|
|
173
|
+
|
|
174
|
+
# Match git dependency declaration with tag
|
|
175
|
+
# Example: fastapi = { git = "...", extras = ["all"], tag = "0.110.0" }
|
|
176
|
+
git_dep_regex = /
|
|
177
|
+
^(\s*)#{Regexp.escape(dep.name)}(\s*=\s*\{[^}]*tag\s*=\s*)
|
|
178
|
+
["']#{Regexp.escape(old_tag)}["']([^}]*\})
|
|
179
|
+
/mx
|
|
180
|
+
|
|
181
|
+
content.gsub(git_dep_regex) do
|
|
182
|
+
match_data = T.must(Regexp.last_match)
|
|
183
|
+
"#{match_data[1]}#{dep.name}#{match_data[2]}\"#{new_tag}\"#{match_data[3]}"
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
|
|
152
187
|
sig { returns(String) }
|
|
153
188
|
def updated_lockfile_content
|
|
154
189
|
@updated_lockfile_content ||=
|
|
@@ -199,6 +234,9 @@ module Dependabot
|
|
|
199
234
|
|
|
200
235
|
if poetry_object
|
|
201
236
|
dependencies.each do |dep|
|
|
237
|
+
# Skip Git dependencies - they use tags/refs, not versions
|
|
238
|
+
next if git_dependency_being_updated?(dep)
|
|
239
|
+
|
|
202
240
|
if dep.requirements.find { |r| r[:file] == pyproject&.name }
|
|
203
241
|
lock_declaration_to_new_version!(poetry_object, dep)
|
|
204
242
|
else
|
|
@@ -240,6 +278,11 @@ module Dependabot
|
|
|
240
278
|
poetry_object[subdep_type][dep.name] = dep.version
|
|
241
279
|
end
|
|
242
280
|
|
|
281
|
+
sig { params(dep: Dependabot::Dependency).returns(T::Boolean) }
|
|
282
|
+
def git_dependency_being_updated?(dep)
|
|
283
|
+
dep.requirements.any? { |r| r.dig(:source, :type) == "git" }
|
|
284
|
+
end
|
|
285
|
+
|
|
243
286
|
sig { params(pyproject_content: String).returns(String) }
|
|
244
287
|
def sanitize(pyproject_content)
|
|
245
288
|
PyprojectPreparer
|
|
@@ -389,7 +389,7 @@ module Dependabot
|
|
|
389
389
|
version = version.release if version.prerelease?
|
|
390
390
|
|
|
391
391
|
lb_segments = version.segments
|
|
392
|
-
lb_segments.pop while lb_segments.last
|
|
392
|
+
lb_segments.pop while lb_segments.last&.zero?
|
|
393
393
|
|
|
394
394
|
lb_segments
|
|
395
395
|
end
|
|
@@ -400,7 +400,7 @@ module Dependabot
|
|
|
400
400
|
version = req.requirements.first.last.release
|
|
401
401
|
|
|
402
402
|
if req_string.strip.start_with?("^")
|
|
403
|
-
version.segments.index { |i| i != 0 }
|
|
403
|
+
version.segments.index { |i| i != 0 } || (version.segments.count - 1)
|
|
404
404
|
elsif req_string.include?("*")
|
|
405
405
|
version.segments.count - 1
|
|
406
406
|
elsif req_string.strip.start_with?("~=", "==")
|
|
@@ -17,6 +17,7 @@ require "dependabot/update_checkers/base"
|
|
|
17
17
|
|
|
18
18
|
module Dependabot
|
|
19
19
|
module Python
|
|
20
|
+
# rubocop:disable Metrics/ClassLength
|
|
20
21
|
class UpdateChecker < Dependabot::UpdateCheckers::Base
|
|
21
22
|
extend T::Sig
|
|
22
23
|
|
|
@@ -35,6 +36,8 @@ module Dependabot
|
|
|
35
36
|
|
|
36
37
|
sig { override.returns(T.nilable(Gem::Version)) }
|
|
37
38
|
def latest_version
|
|
39
|
+
return latest_version_for_git_dependency if git_dependency?
|
|
40
|
+
|
|
38
41
|
@latest_version ||= T.let(
|
|
39
42
|
fetch_latest_version,
|
|
40
43
|
T.nilable(Gem::Version)
|
|
@@ -43,6 +46,8 @@ module Dependabot
|
|
|
43
46
|
|
|
44
47
|
sig { override.returns(T.nilable(Gem::Version)) }
|
|
45
48
|
def latest_resolvable_version
|
|
49
|
+
return latest_resolvable_version_for_git_dependency if git_dependency?
|
|
50
|
+
|
|
46
51
|
@latest_resolvable_version ||= T.let(
|
|
47
52
|
if resolver_type == :requirements
|
|
48
53
|
resolver.latest_resolvable_version
|
|
@@ -59,6 +64,8 @@ module Dependabot
|
|
|
59
64
|
|
|
60
65
|
sig { override.returns(T.nilable(Gem::Version)) }
|
|
61
66
|
def latest_resolvable_version_with_no_unlock
|
|
67
|
+
return T.cast(dependency.version, T.nilable(Gem::Version)) if git_dependency? && git_commit_checker.pinned?
|
|
68
|
+
|
|
62
69
|
@latest_resolvable_version_with_no_unlock ||= T.let(
|
|
63
70
|
if resolver_type == :requirements
|
|
64
71
|
resolver.latest_resolvable_version_with_no_unlock
|
|
@@ -88,6 +95,8 @@ module Dependabot
|
|
|
88
95
|
|
|
89
96
|
sig { override.returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
|
90
97
|
def updated_requirements
|
|
98
|
+
return updated_git_requirements if git_dependency?
|
|
99
|
+
|
|
91
100
|
RequirementsUpdater.new(
|
|
92
101
|
requirements: requirements,
|
|
93
102
|
latest_resolvable_version: preferred_resolvable_version&.to_s,
|
|
@@ -112,6 +121,64 @@ module Dependabot
|
|
|
112
121
|
|
|
113
122
|
private
|
|
114
123
|
|
|
124
|
+
sig { returns(T::Boolean) }
|
|
125
|
+
def git_dependency?
|
|
126
|
+
git_commit_checker.git_dependency?
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
sig { returns(T.nilable(Gem::Version)) }
|
|
130
|
+
def latest_version_for_git_dependency
|
|
131
|
+
latest_git_version_details&.fetch(:version)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
sig { returns(T.nilable(Gem::Version)) }
|
|
135
|
+
def latest_resolvable_version_for_git_dependency
|
|
136
|
+
# For git dependencies, we assume the latest version is resolvable
|
|
137
|
+
latest_version_for_git_dependency
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
sig { returns(T::Array[T::Hash[Symbol, T.untyped]]) }
|
|
141
|
+
def updated_git_requirements
|
|
142
|
+
updated_source = updated_git_source
|
|
143
|
+
return requirements unless updated_source
|
|
144
|
+
|
|
145
|
+
requirements.map do |req|
|
|
146
|
+
req.merge(source: updated_source)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
|
151
|
+
def updated_git_source
|
|
152
|
+
# Update the git tag if a new version is available
|
|
153
|
+
if git_commit_checker.pinned_ref_looks_like_version? && latest_git_version_details
|
|
154
|
+
new_tag = T.must(latest_git_version_details).fetch(:tag)
|
|
155
|
+
source_details = dependency.source_details
|
|
156
|
+
return source_details.transform_keys(&:to_sym).merge(ref: new_tag) if source_details
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Otherwise return the original source
|
|
160
|
+
dependency.source_details&.transform_keys(&:to_sym)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
sig { returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
|
164
|
+
def latest_git_version_details
|
|
165
|
+
@latest_git_version_details ||= T.let(
|
|
166
|
+
git_commit_checker.local_tag_for_latest_version,
|
|
167
|
+
T.nilable(T::Hash[Symbol, T.untyped])
|
|
168
|
+
)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
sig { returns(Dependabot::GitCommitChecker) }
|
|
172
|
+
def git_commit_checker
|
|
173
|
+
@git_commit_checker ||= T.let(
|
|
174
|
+
Dependabot::GitCommitChecker.new(
|
|
175
|
+
dependency: dependency,
|
|
176
|
+
credentials: credentials
|
|
177
|
+
),
|
|
178
|
+
T.nilable(Dependabot::GitCommitChecker)
|
|
179
|
+
)
|
|
180
|
+
end
|
|
181
|
+
|
|
115
182
|
sig { override.returns(T::Boolean) }
|
|
116
183
|
def latest_version_resolvable_with_full_unlock?
|
|
117
184
|
# Full unlock checks aren't implemented for Python (yet)
|
|
@@ -135,10 +202,6 @@ module Dependabot
|
|
|
135
202
|
|
|
136
203
|
sig { returns(T.untyped) }
|
|
137
204
|
def resolver
|
|
138
|
-
if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
|
|
139
|
-
Dependabot.logger.info("Python package resolver : #{resolver_type}")
|
|
140
|
-
end
|
|
141
|
-
|
|
142
205
|
case resolver_type
|
|
143
206
|
when :pip_compile then pip_compile_version_resolver
|
|
144
207
|
when :pipenv then pipenv_version_resolver
|
|
@@ -456,6 +519,7 @@ module Dependabot
|
|
|
456
519
|
dependency_files.select { |f| f.name.end_with?(".in") }
|
|
457
520
|
end
|
|
458
521
|
end
|
|
522
|
+
# rubocop:enable Metrics/ClassLength
|
|
459
523
|
end
|
|
460
524
|
end
|
|
461
525
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dependabot-python
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.358.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Dependabot
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - '='
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 0.
|
|
18
|
+
version: 0.358.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.358.0
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: debug
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -291,7 +291,7 @@ licenses:
|
|
|
291
291
|
- MIT
|
|
292
292
|
metadata:
|
|
293
293
|
bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
|
|
294
|
-
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.
|
|
294
|
+
changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.358.0
|
|
295
295
|
rdoc_options: []
|
|
296
296
|
require_paths:
|
|
297
297
|
- lib
|