dependabot-python 0.288.0 → 0.289.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2a48e0851bec2770472370c41f5bc8c2f51252f14d0df9895b354eb0ed0cd26b
4
- data.tar.gz: f105f8d5deffbb70dc2c0a3cfb9e00a4b591c01e6ededcacec376f52ae926738
3
+ metadata.gz: 53fcf514cdb25a0a0ce7ee91ee7c7a709bed7a0b0b12e96c1b75ee0670c9a776
4
+ data.tar.gz: ad1d6c5111311f7c22da1b9632747a03a419d329a2047f147fc93aba580aedd1
5
5
  SHA512:
6
- metadata.gz: 0d407719216601023ff1d397072e158e3a4ab2fcf0113702655d83176accdfbdb3fb532a72e71fdaab76c07985203dbf12de20b69be78ed93d5bd37241b99db1
7
- data.tar.gz: 75ad08b140727494fbb29ea3a564680b2366c9104f19e08d16896483cb594a3fc66c1bf51836c8ab063fedc64d4448bbaa1777868efb883e13587e63cfe70c95
6
+ metadata.gz: ada2669aa9b1e58cc9ed8e8f3001d7d47b9ecaf496666753247a8e4b9e00db288aecae9a30061dfe4880bfe5569eeab7faf873187d93d132330097104fd1b5a3
7
+ data.tar.gz: 04c164ca91f954361f394fba2a2f4fe3ee4685b392526d6e8ad8d14148da95ea9f1ca4d104c84d8af626d6462cb545b73d7e60f52ead0f8fe228596a82322093
@@ -8,9 +8,12 @@ require "dependabot/file_parsers/base/dependency_set"
8
8
  require "dependabot/shared_helpers"
9
9
  require "dependabot/python/requirement"
10
10
  require "dependabot/errors"
11
+ require "dependabot/python/language"
11
12
  require "dependabot/python/native_helpers"
12
13
  require "dependabot/python/name_normaliser"
13
14
  require "dependabot/python/pip_compile_file_matcher"
15
+ require "dependabot/python/language_version_manager"
16
+ require "dependabot/python/package_manager"
14
17
 
15
18
  module Dependabot
16
19
  module Python
@@ -34,6 +37,11 @@ module Dependabot
34
37
  InvalidRequirement ValueError RecursionError
35
38
  ).freeze
36
39
 
40
+ # we use this placeholder version in case we are not able to detect any
41
+ # PIP version from shell, we are ensuring that the actual update is not blocked
42
+ # in any way if any metric collection exception start happening
43
+ UNDETECTED_PACKAGE_MANAGER_VERSION = "0.0"
44
+
37
45
  def parse
38
46
  # TODO: setup.py from external dependencies is evaluated. Provide guards before removing this.
39
47
  raise Dependabot::UnexpectedExternalCode if @reject_external_code
@@ -48,8 +56,172 @@ module Dependabot
48
56
  dependency_set.dependencies
49
57
  end
50
58
 
59
+ sig { returns(Ecosystem) }
60
+ def ecosystem
61
+ @ecosystem ||= T.let(
62
+ Ecosystem.new(
63
+ name: ECOSYSTEM,
64
+ package_manager: package_manager,
65
+ language: language
66
+ ),
67
+ T.nilable(Ecosystem)
68
+ )
69
+ end
70
+
51
71
  private
52
72
 
73
+ def language_version_manager
74
+ @language_version_manager ||=
75
+ LanguageVersionManager.new(
76
+ python_requirement_parser: python_requirement_parser
77
+ )
78
+ end
79
+
80
+ def python_requirement_parser
81
+ @python_requirement_parser ||=
82
+ FileParser::PythonRequirementParser.new(
83
+ dependency_files: dependency_files
84
+ )
85
+ end
86
+
87
+ sig { returns(Ecosystem::VersionManager) }
88
+ def package_manager
89
+ if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
90
+ Dependabot.logger.info("Detected package manager : #{detected_package_manager.name}")
91
+ end
92
+
93
+ @package_manager ||= detected_package_manager
94
+ end
95
+
96
+ sig { returns(Ecosystem::VersionManager) }
97
+ def detected_package_manager
98
+ setup_python_environment if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
99
+
100
+ return PipenvPackageManager.new(T.must(detect_pipenv_version)) if detect_pipenv_version
101
+
102
+ return PoetryPackageManager.new(T.must(detect_poetry_version)) if detect_poetry_version
103
+
104
+ return PipCompilePackageManager.new(T.must(detect_pipcompile_version)) if detect_pipcompile_version
105
+
106
+ PipPackageManager.new(detect_pip_version)
107
+ end
108
+
109
+ # Detects the version of poetry. If the version cannot be detected, it returns nil
110
+ sig { returns(T.nilable(String)) }
111
+ def detect_poetry_version
112
+ if poetry_files
113
+ package_manager = PoetryPackageManager::NAME
114
+
115
+ version = package_manager_version(package_manager)
116
+ .to_s.split("version ").last&.split(")")&.first
117
+
118
+ log_if_version_malformed(package_manager, version)
119
+
120
+ # makes sure we have correct version format returned
121
+ version if version&.match?(/^\d+(?:\.\d+)*$/)
122
+ end
123
+ rescue StandardError
124
+ nil
125
+ end
126
+
127
+ # Detects the version of pip-compile. If the version cannot be detected, it returns nil
128
+ sig { returns(T.nilable(String)) }
129
+ def detect_pipcompile_version
130
+ if pipcompile_in_file
131
+ package_manager = PipCompilePackageManager::NAME
132
+
133
+ version = package_manager_version(package_manager)
134
+ .to_s.split("version ").last&.split(")")&.first
135
+
136
+ log_if_version_malformed(package_manager, version)
137
+
138
+ # makes sure we have correct version format returned
139
+ version if version&.match?(/^\d+(?:\.\d+)*$/)
140
+ end
141
+ rescue StandardError
142
+ nil
143
+ end
144
+
145
+ # Detects the version of pipenv. If the version cannot be detected, it returns nil
146
+ sig { returns(T.nilable(String)) }
147
+ def detect_pipenv_version
148
+ if pipenv_files
149
+ package_manager = PipenvPackageManager::NAME
150
+
151
+ version = package_manager_version(package_manager)
152
+ .to_s.split("version ").last&.strip
153
+
154
+ log_if_version_malformed(package_manager, version)
155
+
156
+ # makes sure we have correct version format returned
157
+ version if version&.match?(/^\d+(?:\.\d+)*$/)
158
+ end
159
+ rescue StandardError
160
+ nil
161
+ end
162
+
163
+ # Detects the version of pip. If the version cannot be detected, it returns 0.0
164
+ sig { returns(String) }
165
+ def detect_pip_version
166
+ package_manager = PipPackageManager::NAME
167
+
168
+ version = package_manager_version(package_manager)
169
+ .split("from").first&.split("pip")&.last&.strip
170
+
171
+ log_if_version_malformed(package_manager, version)
172
+
173
+ version&.match?(/^\d+(?:\.\d+)*$/) ? version : UNDETECTED_PACKAGE_MANAGER_VERSION
174
+ rescue StandardError
175
+ nil
176
+ end
177
+
178
+ sig { params(package_manager: String).returns(T.any(String, T.untyped)) }
179
+ def package_manager_version(package_manager)
180
+ version_info = SharedHelpers.run_shell_command("pyenv exec #{package_manager} --version")
181
+ Dependabot.logger.info("Package manager #{package_manager}, Info : #{version_info}")
182
+
183
+ version_info
184
+ rescue StandardError => e
185
+ Dependabot.logger.error(e.message)
186
+ nil
187
+ end
188
+
189
+ # setup python local setup on file parser stage
190
+ sig { void }
191
+ def setup_python_environment
192
+ language_version_manager.install_required_python
193
+
194
+ SharedHelpers.run_shell_command("pyenv local #{language_version_manager.python_major_minor}")
195
+ rescue StandardError => e
196
+ Dependabot.logger.error(e.message)
197
+ nil
198
+ end
199
+
200
+ sig { params(package_manager: String, version: String).void }
201
+ def log_if_version_malformed(package_manager, version)
202
+ # logs warning if malformed version is found
203
+ return true if version.match?(/^\d+(?:\.\d+)*$/)
204
+
205
+ Dependabot.logger.warn(
206
+ "Detected #{package_manager} with malformed version #{version}"
207
+ )
208
+ end
209
+
210
+ sig { returns(String) }
211
+ def python_raw_version
212
+ if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
213
+ Dependabot.logger.info("Detected python version: #{language_version_manager.python_version}")
214
+ Dependabot.logger.info("Detected python major minor version: #{language_version_manager.python_major_minor}")
215
+ end
216
+
217
+ language_version_manager.python_version
218
+ end
219
+
220
+ sig { returns(T.nilable(Ecosystem::VersionManager)) }
221
+ def language
222
+ Language.new(python_raw_version)
223
+ end
224
+
53
225
  def requirement_files
54
226
  dependency_files.select { |f| f.name.end_with?(".txt", ".in") }
55
227
  end
@@ -164,6 +336,18 @@ module Dependabot
164
336
  end
165
337
  end
166
338
 
339
+ def pipcompile_in_file
340
+ requirement_files.any? { |f| f.end_with?(".in") }
341
+ end
342
+
343
+ def pipenv_files
344
+ dependency_files.any? { |f| f.name == PipenvPackageManager::LOCKFILE_FILENAME }
345
+ end
346
+
347
+ def poetry_files
348
+ true if get_original_file(PoetryPackageManager::LOCKFILE_NAME)
349
+ end
350
+
167
351
  def write_temporary_dependency_files
168
352
  dependency_files
169
353
  .reject { |f| f.name == ".python-version" }
@@ -0,0 +1,21 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "dependabot/python/version"
6
+ require "dependabot/ecosystem"
7
+
8
+ module Dependabot
9
+ module Python
10
+ LANGUAGE = "python"
11
+
12
+ class Language < Dependabot::Ecosystem::VersionManager
13
+ extend T::Sig
14
+
15
+ sig { params(raw_version: String, requirement: T.nilable(Requirement)).void }
16
+ def initialize(raw_version, requirement = nil)
17
+ super(LANGUAGE, Version.new(raw_version), [], [], requirement)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,166 @@
1
+ # typed: strong
2
+ # frozen_string_literal: true
3
+
4
+ require "sorbet-runtime"
5
+ require "dependabot/python/version"
6
+ require "dependabot/ecosystem"
7
+ require "dependabot/python/requirement"
8
+
9
+ module Dependabot
10
+ module Python
11
+ ECOSYSTEM = "Python"
12
+
13
+ SUPPORTED_PYTHON_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
14
+
15
+ DEPRECATED_PYTHON_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
16
+
17
+ class PipPackageManager < Dependabot::Ecosystem::VersionManager
18
+ extend T::Sig
19
+
20
+ NAME = "pip"
21
+
22
+ SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
23
+
24
+ DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
25
+
26
+ sig do
27
+ params(
28
+ raw_version: String,
29
+ requirement: T.nilable(Requirement)
30
+ ).void
31
+ end
32
+ def initialize(raw_version, requirement = nil)
33
+ super(
34
+ NAME,
35
+ Version.new(raw_version),
36
+ SUPPORTED_VERSIONS,
37
+ DEPRECATED_VERSIONS,
38
+ requirement,
39
+ )
40
+ end
41
+
42
+ sig { override.returns(T::Boolean) }
43
+ def deprecated?
44
+ false
45
+ end
46
+
47
+ sig { override.returns(T::Boolean) }
48
+ def unsupported?
49
+ false
50
+ end
51
+ end
52
+
53
+ class PoetryPackageManager < Dependabot::Ecosystem::VersionManager
54
+ extend T::Sig
55
+
56
+ NAME = "poetry"
57
+
58
+ LOCKFILE_NAME = "poetry.lock"
59
+
60
+ SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
61
+
62
+ DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
63
+
64
+ sig do
65
+ params(
66
+ raw_version: String,
67
+ requirement: T.nilable(Requirement)
68
+ ).void
69
+ end
70
+ def initialize(raw_version, requirement = nil)
71
+ super(
72
+ NAME,
73
+ Version.new(raw_version),
74
+ SUPPORTED_VERSIONS,
75
+ DEPRECATED_VERSIONS,
76
+ requirement,
77
+ )
78
+ end
79
+
80
+ sig { override.returns(T::Boolean) }
81
+ def deprecated?
82
+ false
83
+ end
84
+
85
+ sig { override.returns(T::Boolean) }
86
+ def unsupported?
87
+ false
88
+ end
89
+ end
90
+
91
+ class PipCompilePackageManager < Dependabot::Ecosystem::VersionManager
92
+ extend T::Sig
93
+
94
+ NAME = "pip-compile"
95
+
96
+ SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
97
+
98
+ DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
99
+
100
+ sig do
101
+ params(
102
+ raw_version: String,
103
+ requirement: T.nilable(Requirement)
104
+ ).void
105
+ end
106
+ def initialize(raw_version, requirement = nil)
107
+ super(
108
+ NAME,
109
+ Version.new(raw_version),
110
+ SUPPORTED_VERSIONS,
111
+ DEPRECATED_VERSIONS,
112
+ requirement,
113
+ )
114
+ end
115
+
116
+ sig { override.returns(T::Boolean) }
117
+ def deprecated?
118
+ false
119
+ end
120
+
121
+ sig { override.returns(T::Boolean) }
122
+ def unsupported?
123
+ false
124
+ end
125
+ end
126
+
127
+ class PipenvPackageManager < Dependabot::Ecosystem::VersionManager
128
+ extend T::Sig
129
+
130
+ NAME = "pipenv"
131
+
132
+ MANIFEST_FILENAME = "Pipfile"
133
+ LOCKFILE_FILENAME = "Pipfile.lock"
134
+
135
+ SUPPORTED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
136
+
137
+ DEPRECATED_VERSIONS = T.let([].freeze, T::Array[Dependabot::Version])
138
+
139
+ sig do
140
+ params(
141
+ raw_version: String,
142
+ requirement: T.nilable(Requirement)
143
+ ).void
144
+ end
145
+ def initialize(raw_version, requirement = nil)
146
+ super(
147
+ NAME,
148
+ Version.new(raw_version),
149
+ SUPPORTED_VERSIONS,
150
+ DEPRECATED_VERSIONS,
151
+ requirement,
152
+ )
153
+ end
154
+
155
+ sig { override.returns(T::Boolean) }
156
+ def deprecated?
157
+ false
158
+ end
159
+
160
+ sig { override.returns(T::Boolean) }
161
+ def unsupported?
162
+ false
163
+ end
164
+ end
165
+ end
166
+ end
@@ -113,6 +113,10 @@ module Dependabot
113
113
  end
114
114
 
115
115
  def resolver
116
+ if Dependabot::Experiments.enabled?(:enable_file_parser_python_local)
117
+ Dependabot.logger.info("Python package resolver : #{resolver_type}")
118
+ end
119
+
116
120
  case resolver_type
117
121
  when :pip_compile then pip_compile_version_resolver
118
122
  when :pipenv then pipenv_version_resolver
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-python
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.288.0
4
+ version: 0.289.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-21 00:00:00.000000000 Z
11
+ date: 2024-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dependabot-common
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - '='
18
18
  - !ruby/object:Gem::Version
19
- version: 0.288.0
19
+ version: 0.289.0
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - '='
25
25
  - !ruby/object:Gem::Version
26
- version: 0.288.0
26
+ version: 0.289.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -266,10 +266,12 @@ files:
266
266
  - lib/dependabot/python/file_updater/requirement_file_updater.rb
267
267
  - lib/dependabot/python/file_updater/requirement_replacer.rb
268
268
  - lib/dependabot/python/file_updater/setup_file_sanitizer.rb
269
+ - lib/dependabot/python/language.rb
269
270
  - lib/dependabot/python/language_version_manager.rb
270
271
  - lib/dependabot/python/metadata_finder.rb
271
272
  - lib/dependabot/python/name_normaliser.rb
272
273
  - lib/dependabot/python/native_helpers.rb
274
+ - lib/dependabot/python/package_manager.rb
273
275
  - lib/dependabot/python/pip_compile_file_matcher.rb
274
276
  - lib/dependabot/python/pipenv_runner.rb
275
277
  - lib/dependabot/python/requirement.rb
@@ -288,7 +290,7 @@ licenses:
288
290
  - MIT
289
291
  metadata:
290
292
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
291
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.288.0
293
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.289.0
292
294
  post_install_message:
293
295
  rdoc_options: []
294
296
  require_paths: