dependabot-core 0.78.0 → 0.79.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/helpers/npm/lib/updater.js +11 -5
  4. data/helpers/npm/package.json +2 -2
  5. data/helpers/npm/yarn.lock +26 -28
  6. data/helpers/yarn/lib/replace-lockfile-declaration.js +15 -3
  7. data/helpers/yarn/lib/updater.js +17 -5
  8. data/helpers/yarn/package.json +2 -2
  9. data/helpers/yarn/yarn.lock +24 -31
  10. data/lib/dependabot/file_fetchers.rb +0 -2
  11. data/lib/dependabot/file_parsers.rb +0 -2
  12. data/lib/dependabot/file_updaters.rb +0 -2
  13. data/lib/dependabot/metadata_finders.rb +0 -2
  14. data/lib/dependabot/update_checkers.rb +0 -2
  15. data/lib/dependabot/utils.rb +0 -4
  16. data/lib/dependabot/version.rb +1 -1
  17. metadata +3 -34
  18. data/helpers/python/lib/__init__.py +0 -0
  19. data/helpers/python/lib/hasher.py +0 -23
  20. data/helpers/python/lib/parser.py +0 -130
  21. data/helpers/python/requirements.txt +0 -9
  22. data/helpers/python/run.py +0 -18
  23. data/lib/dependabot/file_fetchers/python/pip.rb +0 -305
  24. data/lib/dependabot/file_parsers/python/pip.rb +0 -223
  25. data/lib/dependabot/file_parsers/python/pip/pipfile_files_parser.rb +0 -154
  26. data/lib/dependabot/file_parsers/python/pip/poetry_files_parser.rb +0 -141
  27. data/lib/dependabot/file_parsers/python/pip/setup_file_parser.rb +0 -164
  28. data/lib/dependabot/file_updaters/python/pip.rb +0 -147
  29. data/lib/dependabot/file_updaters/python/pip/pip_compile_file_updater.rb +0 -363
  30. data/lib/dependabot/file_updaters/python/pip/pipfile_file_updater.rb +0 -397
  31. data/lib/dependabot/file_updaters/python/pip/pipfile_preparer.rb +0 -125
  32. data/lib/dependabot/file_updaters/python/pip/poetry_file_updater.rb +0 -289
  33. data/lib/dependabot/file_updaters/python/pip/pyproject_preparer.rb +0 -105
  34. data/lib/dependabot/file_updaters/python/pip/requirement_file_updater.rb +0 -166
  35. data/lib/dependabot/file_updaters/python/pip/requirement_replacer.rb +0 -95
  36. data/lib/dependabot/file_updaters/python/pip/setup_file_sanitizer.rb +0 -91
  37. data/lib/dependabot/file_updaters/ruby/.DS_Store +0 -0
  38. data/lib/dependabot/metadata_finders/python/pip.rb +0 -120
  39. data/lib/dependabot/update_checkers/python/pip.rb +0 -227
  40. data/lib/dependabot/update_checkers/python/pip/latest_version_finder.rb +0 -252
  41. data/lib/dependabot/update_checkers/python/pip/pip_compile_version_resolver.rb +0 -380
  42. data/lib/dependabot/update_checkers/python/pip/pipfile_version_resolver.rb +0 -559
  43. data/lib/dependabot/update_checkers/python/pip/poetry_version_resolver.rb +0 -300
  44. data/lib/dependabot/update_checkers/python/pip/requirements_updater.rb +0 -367
  45. data/lib/dependabot/utils/python/requirement.rb +0 -130
  46. data/lib/dependabot/utils/python/version.rb +0 -88
  47. data/lib/python_requirement_parser.rb +0 -33
  48. data/lib/python_versions.rb +0 -21
@@ -1,252 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "excon"
4
-
5
- require "dependabot/update_checkers/python/pip"
6
- require "dependabot/shared_helpers"
7
-
8
- module Dependabot
9
- module UpdateCheckers
10
- module Python
11
- class Pip
12
- class LatestVersionFinder
13
- def initialize(dependency:, dependency_files:, credentials:,
14
- ignored_versions:)
15
- @dependency = dependency
16
- @dependency_files = dependency_files
17
- @credentials = credentials
18
- @ignored_versions = ignored_versions
19
- end
20
-
21
- def latest_version
22
- @latest_version ||= fetch_latest_version
23
- end
24
-
25
- def latest_version_with_no_unlock
26
- @latest_version_with_no_unlock ||=
27
- fetch_latest_version_with_no_unlock
28
- end
29
-
30
- private
31
-
32
- attr_reader :dependency, :dependency_files, :credentials,
33
- :ignored_versions
34
-
35
- def fetch_latest_version
36
- versions = available_versions
37
- versions.reject! { |v| ignore_reqs.any? { |r| r.satisfied_by?(v) } }
38
- versions.reject!(&:prerelease?) unless wants_prerelease?
39
- versions.max
40
- end
41
-
42
- def fetch_latest_version_with_no_unlock
43
- versions = available_versions
44
- reqs = dependency.requirements.map do |r|
45
- reqs = (r.fetch(:requirement) || "").split(",").map(&:strip)
46
- requirement_class.new(reqs)
47
- end
48
- versions.reject!(&:prerelease?) unless wants_prerelease?
49
- versions.sort.reverse.
50
- reject { |v| ignore_reqs.any? { |r| r.satisfied_by?(v) } }.
51
- find { |v| reqs.all? { |r| r.satisfied_by?(v) } }
52
- end
53
-
54
- def wants_prerelease?
55
- if dependency.version
56
- version = version_class.new(dependency.version.tr("+", "."))
57
- return version.prerelease?
58
- end
59
-
60
- dependency.requirements.any? do |req|
61
- reqs = (req.fetch(:requirement) || "").split(",").map(&:strip)
62
- reqs.any? { |r| r.match?(/[A-Za-z]/) }
63
- end
64
- end
65
-
66
- # See https://www.python.org/dev/peps/pep-0503/ for details of the
67
- # Simple Repository API we use here.
68
- def available_versions
69
- index_urls.flat_map do |index_url|
70
- sanitized_url = index_url.gsub(%r{(?<=//).*(?=@)}, "redacted")
71
- index_response = registry_response_for_dependency(index_url)
72
-
73
- if [401, 403].include?(index_response.status) &&
74
- [401, 403].include?(registry_index_response(index_url).status)
75
- raise PrivateSourceAuthenticationFailure, sanitized_url
76
- end
77
-
78
- index_response.body.
79
- scan(%r{<a\s.*?>(.*?)</a>}m).flatten.
80
- select { |n| n.match?(name_regex) }.
81
- map do |filename|
82
- version =
83
- filename.
84
- gsub(/#{name_regex}-/i, "").
85
- split(/-|(\.tar\.)/).
86
- first
87
- next unless version_class.correct?(version)
88
-
89
- version_class.new(version)
90
- end.compact
91
- rescue Excon::Error::Timeout, Excon::Error::Socket
92
- next if MAIN_PYPI_INDEXES.include?(index_url)
93
-
94
- raise PrivateSourceAuthenticationFailure, sanitized_url
95
- end
96
- end
97
-
98
- def index_urls
99
- main_index_url =
100
- config_variable_index_urls[:main] ||
101
- pipfile_index_urls[:main] ||
102
- requirement_file_index_urls[:main] ||
103
- pip_conf_index_urls[:main] ||
104
- "https://pypi.python.org/simple/"
105
-
106
- if main_index_url
107
- main_index_url = main_index_url.strip.gsub(%r{/*$}, "") + "/"
108
- end
109
-
110
- extra_index_urls =
111
- config_variable_index_urls[:extra] +
112
- pipfile_index_urls[:extra] +
113
- requirement_file_index_urls[:extra] +
114
- pip_conf_index_urls[:extra]
115
-
116
- extra_index_urls =
117
- extra_index_urls.map { |url| url.strip.gsub(%r{/*$}, "") + "/" }
118
-
119
- [main_index_url, *extra_index_urls].uniq
120
- end
121
-
122
- def registry_response_for_dependency(index_url)
123
- Excon.get(
124
- index_url + normalised_name + "/",
125
- idempotent: true,
126
- **SharedHelpers.excon_defaults
127
- )
128
- end
129
-
130
- def registry_index_response(index_url)
131
- Excon.get(
132
- index_url,
133
- idempotent: true,
134
- **SharedHelpers.excon_defaults
135
- )
136
- end
137
-
138
- def requirement_file_index_urls
139
- urls = { main: nil, extra: [] }
140
-
141
- requirements_files.each do |file|
142
- if file.content.match?(/^--index-url\s(.+)/)
143
- urls[:main] =
144
- file.content.match(/^--index-url\s(.+)/).captures.first
145
- end
146
- urls[:extra] += file.content.scan(/^--extra-index-url\s(.+)/).
147
- flatten
148
- end
149
-
150
- urls
151
- end
152
-
153
- def pip_conf_index_urls
154
- urls = { main: nil, extra: [] }
155
-
156
- return urls unless pip_conf
157
-
158
- content = pip_conf.content
159
-
160
- if content.match?(/^index-url\s*=/x)
161
- urls[:main] = content.match(/^index-url\s*=\s*(.+)/).
162
- captures.first
163
- end
164
- urls[:extra] += content.scan(/^extra-index-url\s*=(.+)/).flatten
165
-
166
- urls
167
- end
168
-
169
- def pipfile_index_urls
170
- urls = { main: nil, extra: [] }
171
-
172
- return urls unless pipfile
173
-
174
- pipfile_object = TomlRB.parse(pipfile.content)
175
-
176
- urls[:main] = pipfile_object["source"]&.first&.fetch("url", nil)
177
-
178
- pipfile_object["source"]&.each do |source|
179
- urls[:extra] << source.fetch("url") if source["url"]
180
- end
181
- urls[:extra] = urls[:extra].uniq
182
-
183
- urls
184
- rescue TomlRB::ParseError
185
- urls
186
- end
187
-
188
- def config_variable_index_urls
189
- urls = { main: nil, extra: [] }
190
-
191
- index_url_creds = credentials.
192
- select { |cred| cred["type"] == "python_index" }
193
- urls[:main] =
194
- index_url_creds.
195
- find { |cred| cred["replaces-base"] }&.
196
- fetch("index-url")
197
- urls[:extra] =
198
- index_url_creds.
199
- reject { |cred| cred["replaces-base"] }.
200
- map { |cred| cred["index-url"] }
201
-
202
- urls
203
- end
204
-
205
- def ignore_reqs
206
- ignored_versions.map { |req| requirement_class.new(req.split(",")) }
207
- end
208
-
209
- # See https://www.python.org/dev/peps/pep-0503/#normalized-names
210
- def normalised_name
211
- dependency.name.downcase.gsub(/[-_.]+/, "-")
212
- end
213
-
214
- def name_regex
215
- parts = dependency.name.split(/[\s_.-]/).map { |n| Regexp.quote(n) }
216
- /#{parts.join("[\s_.-]")}/i
217
- end
218
-
219
- def pip_conf
220
- dependency_files.find { |f| f.name == "pip.conf" }
221
- end
222
-
223
- def pipfile
224
- dependency_files.find { |f| f.name == "Pipfile" }
225
- end
226
-
227
- def pyproject
228
- dependency_files.find { |f| f.name == "pyproject.toml" }
229
- end
230
-
231
- def requirements_files
232
- dependency_files.select { |f| f.name.match?(/requirements/x) }
233
- end
234
-
235
- def pip_compile_files
236
- dependency_files.select { |f| f.name.end_with?(".in") }
237
- end
238
-
239
- def version_class
240
- Utils.version_class_for_package_manager(dependency.package_manager)
241
- end
242
-
243
- def requirement_class
244
- Utils.requirement_class_for_package_manager(
245
- dependency.package_manager
246
- )
247
- end
248
- end
249
- end
250
- end
251
- end
252
- end
@@ -1,380 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "python_requirement_parser"
4
- require "dependabot/file_fetchers/python/pip"
5
- require "dependabot/file_parsers/python/pip"
6
- require "dependabot/update_checkers/python/pip"
7
- require "dependabot/file_updaters/python/pip/requirement_replacer"
8
- require "dependabot/file_updaters/python/pip/setup_file_sanitizer"
9
- require "dependabot/utils/python/version"
10
- require "dependabot/shared_helpers"
11
-
12
- # rubocop:disable Metrics/ClassLength
13
- module Dependabot
14
- module UpdateCheckers
15
- module Python
16
- class Pip
17
- # This class does version resolution for pip-compile. Its approach is:
18
- # - Unlock the dependency we're checking in the requirements.in file
19
- # - Run `pip-compile` and see what the result is
20
- class PipCompileVersionResolver
21
- VERSION_REGEX = /[0-9]+(?:\.[A-Za-z0-9\-_]+)*/.freeze
22
-
23
- attr_reader :dependency, :dependency_files, :credentials
24
-
25
- def initialize(dependency:, dependency_files:, credentials:,
26
- unlock_requirement:, latest_allowable_version:)
27
- @dependency = dependency
28
- @dependency_files = dependency_files
29
- @credentials = credentials
30
- @latest_allowable_version = latest_allowable_version
31
- @unlock_requirement = unlock_requirement
32
- end
33
-
34
- def latest_resolvable_version
35
- return @latest_resolvable_version if @resolution_already_attempted
36
-
37
- @resolution_already_attempted = true
38
- @latest_resolvable_version ||= fetch_latest_resolvable_version
39
- end
40
-
41
- private
42
-
43
- attr_reader :latest_allowable_version
44
-
45
- def unlock_requirement?
46
- @unlock_requirement
47
- end
48
-
49
- def fetch_latest_resolvable_version
50
- @latest_resolvable_version_string ||=
51
- SharedHelpers.in_a_temporary_directory do
52
- SharedHelpers.with_git_configured(credentials: credentials) do
53
- write_temporary_dependency_files
54
-
55
- filenames_to_compile.each do |filename|
56
- # Shell out to pip-compile.
57
- # This is slow, as pip-compile needs to do installs.
58
- cmd = "pyenv exec pip-compile --allow-unsafe "\
59
- "-P #{dependency.name} #{filename}"
60
- run_command(cmd)
61
- end
62
-
63
- # Remove any .python-version file before parsing the reqs
64
- FileUtils.remove_entry(".python-version", true)
65
-
66
- parse_updated_files
67
- end
68
- rescue SharedHelpers::HelperSubprocessFailed => error
69
- handle_pip_compile_errors(error)
70
- end
71
- return unless @latest_resolvable_version_string
72
-
73
- Utils::Python::Version.new(@latest_resolvable_version_string)
74
- end
75
-
76
- def parse_requirements_from_cwd_files
77
- SharedHelpers.run_helper_subprocess(
78
- command: "pyenv exec python #{python_helper_path}",
79
- function: "parse_requirements",
80
- args: [Dir.pwd]
81
- )
82
- end
83
-
84
- def handle_pip_compile_errors(error)
85
- if error.message.include?("Could not find a version")
86
- check_original_requirements_resolvable
87
- # If the original requirements are resolvable but we get an
88
- # incompatibility update after unlocking then it's likely to be
89
- # due to problems with pip-compile's cascading resolution
90
- return nil
91
- end
92
-
93
- if error.message.include?('Command "python setup.py egg_info') &&
94
- error.message.include?(dependency.name)
95
- # The latest version of the dependency we're updating is borked
96
- # (because it has an unevaluatable setup.py). Skip the update.
97
- return nil
98
- end
99
-
100
- if error.message.include?("Could not find a version ") &&
101
- !error.message.include?(dependency.name)
102
- # Sometimes pip-tools gets confused and can't work around
103
- # sub-dependency incompatibilities. Ignore those cases.
104
- return nil
105
- end
106
-
107
- raise
108
- end
109
-
110
- # Needed because pip-compile's resolver isn't perfect.
111
- # Note: We raise errors from this method, rather than returning a
112
- # boolean, so that all deps for this repo will raise identical
113
- # errors when failing to update
114
- def check_original_requirements_resolvable
115
- SharedHelpers.in_a_temporary_directory do
116
- SharedHelpers.with_git_configured(credentials: credentials) do
117
- write_temporary_dependency_files(unlock_requirement: false)
118
-
119
- filenames_to_compile.each do |filename|
120
- cmd = "pyenv exec pip-compile --allow-unsafe #{filename}"
121
- run_command(cmd)
122
- end
123
-
124
- true
125
- rescue SharedHelpers::HelperSubprocessFailed => error
126
- raise unless error.message.include?("Could not find a version")
127
-
128
- msg = clean_error_message(error.message)
129
- raise if msg.empty?
130
-
131
- raise DependencyFileNotResolvable, msg
132
- end
133
- end
134
- end
135
-
136
- def run_command(command)
137
- command = command.dup
138
- raw_response = nil
139
- IO.popen(command, err: %i(child out)) do |process|
140
- raw_response = process.read
141
- end
142
-
143
- # Raise an error with the output from the shell session if
144
- # pip-compile returns a non-zero status
145
- return if $CHILD_STATUS.success?
146
-
147
- raise SharedHelpers::HelperSubprocessFailed.new(
148
- raw_response,
149
- command
150
- )
151
- rescue SharedHelpers::HelperSubprocessFailed => error
152
- original_error ||= error
153
- msg = error.message
154
-
155
- relevant_error =
156
- if error_suggests_bad_python_version?(msg) then original_error
157
- else error
158
- end
159
-
160
- raise relevant_error unless error_suggests_bad_python_version?(msg)
161
- raise relevant_error if File.exist?(".python-version")
162
-
163
- command = "pyenv local 2.7.15 && " + command
164
- retry
165
- ensure
166
- FileUtils.remove_entry(".python-version", true)
167
- end
168
-
169
- def error_suggests_bad_python_version?(message)
170
- return true if message.include?("not find a version that satisfies")
171
-
172
- message.include?('Command "python setup.py egg_info" failed')
173
- end
174
-
175
- def write_temporary_dependency_files(unlock_requirement: true)
176
- dependency_files.each do |file|
177
- next if file.name == ".python-version"
178
-
179
- path = file.name
180
- FileUtils.mkdir_p(Pathname.new(path).dirname)
181
- File.write(
182
- path,
183
- unlock_requirement ? unlock_dependency(file) : file.content
184
- )
185
- end
186
-
187
- setup_files.each do |file|
188
- path = file.name
189
- FileUtils.mkdir_p(Pathname.new(path).dirname)
190
- File.write(path, sanitized_setup_file_content(file))
191
- end
192
-
193
- setup_cfg_files.each do |file|
194
- path = file.name
195
- FileUtils.mkdir_p(Pathname.new(path).dirname)
196
- File.write(path, "[metadata]\nname = sanitized-package\n")
197
- end
198
- end
199
-
200
- def sanitized_setup_file_content(file)
201
- @sanitized_setup_file_content ||= {}
202
- if @sanitized_setup_file_content[file.name]
203
- return @sanitized_setup_file_content[file.name]
204
- end
205
-
206
- @sanitized_setup_file_content[file.name] =
207
- FileUpdaters::Python::Pip::SetupFileSanitizer.
208
- new(setup_file: file, setup_cfg: setup_cfg(file)).
209
- sanitized_content
210
- end
211
-
212
- def setup_cfg(file)
213
- dependency_files.find do |f|
214
- f.name == file.name.sub(/\.py$/, ".cfg")
215
- end
216
- end
217
-
218
- def unlock_dependency(file)
219
- return file.content unless file.name.end_with?(".in")
220
- return file.content unless dependency.version
221
- return file.content unless unlock_requirement?
222
-
223
- req = dependency.requirements.find { |r| r[:file] == file.name }
224
- return file.content unless req&.fetch(:requirement)
225
-
226
- FileUpdaters::Python::Pip::RequirementReplacer.new(
227
- content: file.content,
228
- dependency_name: dependency.name,
229
- old_requirement: req[:requirement],
230
- new_requirement: updated_version_requirement_string
231
- ).updated_content
232
- end
233
-
234
- def updated_version_requirement_string
235
- lower_bound_req = updated_version_req_lower_bound
236
-
237
- # Add the latest_allowable_version as an upper bound. This means
238
- # ignore conditions are considered when checking for the latest
239
- # resolvable version.
240
- #
241
- # NOTE: This isn't perfect. If v2.x is ignored and v3 is out but
242
- # unresolvable then the `latest_allowable_version` will be v3, and
243
- # we won't be ignoring v2.x releases like we should be.
244
- return lower_bound_req if latest_allowable_version.nil?
245
- unless Utils::Python::Version.correct?(latest_allowable_version)
246
- return lower_bound_req
247
- end
248
-
249
- lower_bound_req + ", <= #{latest_allowable_version}"
250
- end
251
-
252
- def updated_version_req_lower_bound
253
- if dependency.version
254
- ">= #{dependency.version}"
255
- else
256
- version_for_requirement =
257
- dependency.requirements.map { |r| r[:requirement] }.compact.
258
- reject { |req_string| req_string.start_with?("<") }.
259
- select { |req_string| req_string.match?(VERSION_REGEX) }.
260
- map { |req_string| req_string.match(VERSION_REGEX) }.
261
- select { |version| Gem::Version.correct?(version) }.
262
- max_by { |version| Gem::Version.new(version) }
263
-
264
- ">= #{version_for_requirement || 0}"
265
- end
266
- end
267
-
268
- def python_helper_path
269
- project_root = File.join(File.dirname(__FILE__), "../../../../..")
270
- File.join(project_root, "helpers/python/run.py")
271
- end
272
-
273
- # See https://www.python.org/dev/peps/pep-0503/#normalized-names
274
- def normalise(name)
275
- name.downcase.gsub(/[-_.]+/, "-")
276
- end
277
-
278
- def clean_error_message(message)
279
- # Redact any URLs, as they may include credentials
280
- message.gsub(/http.*?(?=\s)/, "<redacted>")
281
- end
282
-
283
- def filenames_to_compile
284
- files_from_reqs =
285
- dependency.requirements.
286
- map { |r| r[:file] }.
287
- select { |fn| fn.end_with?(".in") }
288
-
289
- files_from_compiled_files =
290
- pip_compile_files.map(&:name).select do |fn|
291
- compiled_file = dependency_files.
292
- find { |f| f.name == fn.gsub(/\.in$/, ".txt") }
293
- compiled_file_includes_dependency?(compiled_file)
294
- end
295
-
296
- filenames = [*files_from_reqs, *files_from_compiled_files].uniq
297
-
298
- order_filenames_for_compilation(filenames)
299
- end
300
-
301
- def compiled_file_includes_dependency?(compiled_file)
302
- return false unless compiled_file
303
-
304
- regex = PythonRequirementParser::INSTALL_REQ_WITH_REQUIREMENT
305
-
306
- matches = []
307
- compiled_file.content.scan(regex) { matches << Regexp.last_match }
308
- matches.any? { |m| normalise(m[:name]) == dependency.name }
309
- end
310
-
311
- # If the files we need to update require one another then we need to
312
- # update them in the right order
313
- def order_filenames_for_compilation(filenames)
314
- ordered_filenames = []
315
-
316
- while (remaining_filenames = filenames - ordered_filenames).any?
317
- ordered_filenames +=
318
- remaining_filenames.
319
- select do |fn|
320
- unupdated_reqs = requirement_map[fn] - ordered_filenames
321
- (unupdated_reqs & filenames).empty?
322
- end
323
- end
324
-
325
- ordered_filenames
326
- end
327
-
328
- def requirement_map
329
- child_req_regex = FileFetchers::Python::Pip::CHILD_REQUIREMENT_REGEX
330
- @requirement_map ||=
331
- pip_compile_files.each_with_object({}) do |file, req_map|
332
- paths = file.content.scan(child_req_regex).flatten
333
- current_dir = File.dirname(file.name)
334
-
335
- req_map[file.name] =
336
- paths.map do |path|
337
- path = File.join(current_dir, path) if current_dir != "."
338
- path = Pathname.new(path).cleanpath.to_path
339
- path = path.gsub(/\.txt$/, ".in")
340
- next if path == file.name
341
-
342
- path
343
- end.uniq.compact
344
- end
345
- end
346
-
347
- def parse_updated_files
348
- updated_files =
349
- dependency_files.map do |file|
350
- next file if file.name == ".python-version"
351
-
352
- updated_file = file.dup
353
- updated_file.content = File.read(file.name)
354
- updated_file
355
- end
356
-
357
- FileParsers::Python::Pip.new(
358
- dependency_files: updated_files,
359
- source: nil,
360
- credentials: credentials
361
- ).parse.find { |d| d.name == dependency.name }&.version
362
- end
363
-
364
- def setup_files
365
- dependency_files.select { |f| f.name.end_with?("setup.py") }
366
- end
367
-
368
- def pip_compile_files
369
- dependency_files.select { |f| f.name.end_with?(".in") }
370
- end
371
-
372
- def setup_cfg_files
373
- dependency_files.select { |f| f.name.end_with?("setup.cfg") }
374
- end
375
- end
376
- end
377
- end
378
- end
379
- end
380
- # rubocop:enable Metrics/ClassLength