dependabot-npm_and_yarn 0.287.0 → 0.288.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: a81729237750f9d53bf9197345ac3f563f267d9683ac202ebca543413bd912ef
4
- data.tar.gz: 5caefb54429a28a52aeff8b50ba8f80554f67baa70eaf6e5bef7040d52d7ebaa
3
+ metadata.gz: ef19e7ca0938baa0bee66d3db0500574f6d3b42b181fef8fe38d36396587a2f4
4
+ data.tar.gz: 4905508434d0e5ac9ef7cbe1b71dcc10d466c5932291b8c9abb4473d53d854b1
5
5
  SHA512:
6
- metadata.gz: 2d4fca7ae33a0540e6940de6946420c08e06be84daf21b37c9efe7234af43050de4efe74191254ace8b12e7e977c74d66557067e9a9bdc07eaf5964bc1996060
7
- data.tar.gz: ab4bd3efd5fe75244c87ec30fb31e1585ce26ac586d42a4b9b8ea84fe86a4015d54dbdc515afe228fb319520fdedc1b1aaa1ab89f71f38bd5cf76683c4c780a9
6
+ metadata.gz: 9981d5b93d3b36479e9500d54fcfcc2d0de8aed94ac5d382a84b7189d570277348e5d421e77f0fc8fee9d20c18511352a60ce855cdc95c178e74ff94640fc175
7
+ data.tar.gz: c8015a50c6732baf3435b7be9ebef4393f312c20d154bf15c516bcad80f8dc39d1fd093c09df6aeb70a59feabe02385dcf9ae15e4b46f3eb6a61916736f04f6a
@@ -1,9 +1,10 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/dependency"
5
5
  require "dependabot/file_parsers"
6
6
  require "dependabot/file_parsers/base"
7
+ require "dependabot/shared_helpers"
7
8
  require "sorbet-runtime"
8
9
 
9
10
  module Dependabot
@@ -110,9 +111,14 @@ module Dependabot
110
111
  def self.pnpm_version_numeric(pnpm_lock)
111
112
  lockfile_content = pnpm_lock&.content
112
113
 
113
- return PNPM_DEFAULT_VERSION if lockfile_content.nil? || lockfile_content.strip.empty?
114
+ return PNPM_DEFAULT_VERSION if !lockfile_content || lockfile_content.strip.empty?
115
+
116
+ pnpm_lockfile_version_str = pnpm_lockfile_version(pnpm_lock)
117
+
118
+ return PNPM_FALLBACK_VERSION unless pnpm_lockfile_version_str
119
+
120
+ pnpm_lockfile_version = pnpm_lockfile_version_str.to_f
114
121
 
115
- pnpm_lockfile_version = pnpm_lockfile_version(pnpm_lock).to_f
116
122
  return PNPM_V9 if pnpm_lockfile_version >= 9.0
117
123
  return PNPM_V8 if pnpm_lockfile_version >= 6.0
118
124
  return PNPM_V7 if pnpm_lockfile_version >= 5.4
@@ -120,6 +126,7 @@ module Dependabot
120
126
  PNPM_FALLBACK_VERSION
121
127
  end
122
128
 
129
+ sig { params(key: String, default_value: String).returns(T.untyped) }
123
130
  def self.fetch_yarnrc_yml_value(key, default_value)
124
131
  if File.exist?(".yarnrc.yml") && (yarnrc = YAML.load_file(".yarnrc.yml"))
125
132
  yarnrc.fetch(key, default_value)
@@ -252,9 +259,12 @@ module Dependabot
252
259
  # set to false. Yarn commands should _not_ be ran outside of this helper
253
260
  # to ensure that postinstall scripts are never executed, as they could
254
261
  # contain malicious code.
262
+ sig { params(commands: T::Array[String]).void }
255
263
  def self.run_yarn_commands(*commands)
256
264
  setup_yarn_berry
257
- commands.each { |cmd, fingerprint| run_single_yarn_command(cmd, fingerprint: fingerprint) }
265
+ commands.each do |cmd, fingerprint|
266
+ run_single_yarn_command(cmd, fingerprint: fingerprint) if cmd
267
+ end
258
268
  end
259
269
 
260
270
  # Run single npm command returning stdout/stderr.
@@ -267,7 +277,10 @@ module Dependabot
267
277
  if Dependabot::Experiments.enabled?(:enable_corepack_for_npm_and_yarn)
268
278
  package_manager_run_command(NpmPackageManager::NAME, command, fingerprint: fingerprint)
269
279
  else
270
- SharedHelpers.run_shell_command("corepack npm #{command}", fingerprint: "corepack npm #{fingerprint}")
280
+ Dependabot::SharedHelpers.run_shell_command(
281
+ "corepack npm #{command}",
282
+ fingerprint: "corepack npm #{fingerprint}"
283
+ )
271
284
  end
272
285
  end
273
286
 
@@ -284,7 +297,10 @@ module Dependabot
284
297
  if Dependabot::Experiments.enabled?(:enable_corepack_for_npm_and_yarn)
285
298
  package_manager_run_command(PNPMPackageManager::NAME, command, fingerprint: fingerprint)
286
299
  else
287
- SharedHelpers.run_shell_command("pnpm #{command}", fingerprint: "pnpm #{fingerprint || command}")
300
+ Dependabot::SharedHelpers.run_shell_command(
301
+ "pnpm #{command}",
302
+ fingerprint: "pnpm #{fingerprint || command}"
303
+ )
288
304
  end
289
305
  end
290
306
 
@@ -294,13 +310,16 @@ module Dependabot
294
310
  if Dependabot::Experiments.enabled?(:enable_corepack_for_npm_and_yarn)
295
311
  package_manager_run_command(YarnPackageManager::NAME, command, fingerprint: fingerprint)
296
312
  else
297
- SharedHelpers.run_shell_command("yarn #{command}", fingerprint: "yarn #{fingerprint || command}")
313
+ Dependabot::SharedHelpers.run_shell_command(
314
+ "yarn #{command}",
315
+ fingerprint: "yarn #{fingerprint || command}"
316
+ )
298
317
  end
299
318
  end
300
319
 
301
320
  # Install the package manager for specified version by using corepack
302
321
  # and prepare it for use by using corepack
303
- sig { params(name: String, version: String).void }
322
+ sig { params(name: String, version: String).returns(String) }
304
323
  def self.install(name, version)
305
324
  Dependabot.logger.info("Installing \"#{name}@#{version}\"")
306
325
 
@@ -309,24 +328,26 @@ module Dependabot
309
328
  installed_version = package_manager_version(name)
310
329
 
311
330
  Dependabot.logger.info("Installed version of #{name}: #{installed_version}")
331
+
332
+ installed_version
312
333
  end
313
334
 
314
335
  # Install the package manager for specified version by using corepack
315
336
  sig { params(name: String, version: String).void }
316
337
  def self.package_manager_install(name, version)
317
- SharedHelpers.run_shell_command(
338
+ Dependabot::SharedHelpers.run_shell_command(
318
339
  "corepack install #{name}@#{version} --global --cache-only",
319
340
  fingerprint: "corepack install <name>@<version> --global --cache-only"
320
- )
341
+ ).strip
321
342
  end
322
343
 
323
344
  # Prepare the package manager for use by using corepack
324
345
  sig { params(name: String, version: String).void }
325
346
  def self.package_manager_activate(name, version)
326
- SharedHelpers.run_shell_command(
347
+ Dependabot::SharedHelpers.run_shell_command(
327
348
  "corepack prepare #{name}@#{version} --activate",
328
349
  fingerprint: "corepack prepare --activate"
329
- )
350
+ ).strip
330
351
  end
331
352
 
332
353
  # Get the version of the package manager by using corepack
@@ -344,15 +365,19 @@ module Dependabot
344
365
  ).returns(String)
345
366
  end
346
367
  def self.package_manager_run_command(name, command, fingerprint: nil)
347
- SharedHelpers.run_shell_command(
368
+ Dependabot::SharedHelpers.run_shell_command(
348
369
  "corepack #{name} #{command}",
349
370
  fingerprint: "corepack #{name} #{fingerprint || command}"
350
- )
371
+ ).strip
351
372
  end
352
373
  private_class_method :run_single_yarn_command
353
374
 
375
+ sig { params(pnpm_lock: DependencyFile).returns(T.nilable(String)) }
354
376
  def self.pnpm_lockfile_version(pnpm_lock)
355
- pnpm_lock.content.match(/^lockfileVersion: ['"]?(?<version>[\d.]+)/)[:version]
377
+ match = T.must(pnpm_lock.content).match(/^lockfileVersion: ['"]?(?<version>[\d.]+)/)
378
+ return match[:version] if match
379
+
380
+ nil
356
381
  end
357
382
 
358
383
  sig { params(dependency_set: Dependabot::FileParsers::Base::DependencySet).returns(T::Array[Dependency]) }
@@ -1,4 +1,4 @@
1
- # typed: true
1
+ # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require "dependabot/shared_helpers"
@@ -10,6 +10,7 @@ module Dependabot
10
10
  ECOSYSTEM = "npm_and_yarn"
11
11
  MANIFEST_FILENAME = "package.json"
12
12
  LERNA_JSON_FILENAME = "lerna.json"
13
+ PACKAGE_MANAGER_VERSION_REGEX = /^(?<major>\d+)\.(?<minor>\d+)\.(?<patch>\d+)(?:-(?<pre_release>[a-zA-Z0-9.]+))?(?:\+(?<build>[a-zA-Z0-9.]+))?$/ # rubocop:disable Layout/LineLength
13
14
 
14
15
  MANIFEST_PACKAGE_MANAGER_KEY = "packageManager"
15
16
  MANIFEST_ENGINES_KEY = "engines"
@@ -138,11 +139,20 @@ module Dependabot
138
139
 
139
140
  DEFAULT_PACKAGE_MANAGER = NpmPackageManager::NAME
140
141
 
141
- PACKAGE_MANAGER_CLASSES = {
142
+ # Define a type alias for the expected class interface
143
+ NpmAndYarnPackageManagerClassType = T.type_alias do
144
+ T.any(
145
+ T.class_of(Dependabot::NpmAndYarn::NpmPackageManager),
146
+ T.class_of(Dependabot::NpmAndYarn::YarnPackageManager),
147
+ T.class_of(Dependabot::NpmAndYarn::PNPMPackageManager)
148
+ )
149
+ end
150
+
151
+ PACKAGE_MANAGER_CLASSES = T.let({
142
152
  NpmPackageManager::NAME => NpmPackageManager,
143
153
  YarnPackageManager::NAME => YarnPackageManager,
144
154
  PNPMPackageManager::NAME => PNPMPackageManager
145
- }.freeze
155
+ }.freeze, T::Hash[String, NpmAndYarnPackageManagerClassType])
146
156
 
147
157
  class PackageManagerDetector
148
158
  extend T::Sig
@@ -151,14 +161,14 @@ module Dependabot
151
161
  sig do
152
162
  params(
153
163
  lockfiles: T::Hash[Symbol, T.nilable(Dependabot::DependencyFile)],
154
- package_json: T::Hash[String, T.untyped]
164
+ package_json: T.nilable(T::Hash[String, T.untyped])
155
165
  ).void
156
166
  end
157
167
  def initialize(lockfiles, package_json)
158
168
  @lockfiles = lockfiles
159
169
  @package_json = package_json
160
- @manifest_package_manager = package_json["packageManager"]
161
- @engines = package_json.fetch(MANIFEST_ENGINES_KEY, nil)
170
+ @manifest_package_manager = T.let(package_json&.fetch(MANIFEST_PACKAGE_MANAGER_KEY, nil), T.nilable(String))
171
+ @engines = T.let(package_json&.fetch(MANIFEST_ENGINES_KEY, {}), T::Hash[String, T.untyped])
162
172
  end
163
173
 
164
174
  # Returns npm, yarn, or pnpm based on the lockfiles, package.json, and engines
@@ -201,16 +211,18 @@ module Dependabot
201
211
 
202
212
  sig do
203
213
  params(
204
- package_json: T::Hash[String, T.untyped],
214
+ package_json: T.nilable(T::Hash[String, T.untyped]),
205
215
  lockfiles: T::Hash[Symbol, T.nilable(Dependabot::DependencyFile)]
206
216
  ).void
207
217
  end
208
218
  def initialize(package_json, lockfiles:)
209
219
  @package_json = package_json
210
220
  @lockfiles = lockfiles
211
- @manifest_package_manager = package_json[MANIFEST_PACKAGE_MANAGER_KEY]
212
- @engines = package_json.fetch(MANIFEST_ENGINES_KEY, nil)
213
- @package_manager_detector = PackageManagerDetector.new(@lockfiles, @package_json)
221
+ @package_manager_detector = T.let(PackageManagerDetector.new(lockfiles, package_json), PackageManagerDetector)
222
+ @manifest_package_manager = T.let(package_json&.fetch(MANIFEST_PACKAGE_MANAGER_KEY, nil), T.nilable(String))
223
+ @engines = T.let(package_json&.fetch(MANIFEST_ENGINES_KEY, nil), T.nilable(T::Hash[String, T.untyped]))
224
+
225
+ @installed_versions = T.let({}, T::Hash[String, String])
214
226
  end
215
227
 
216
228
  sig { returns(Ecosystem::VersionManager) }
@@ -222,6 +234,8 @@ module Dependabot
222
234
 
223
235
  # rubocop:disable Metrics/CyclomaticComplexity
224
236
  # rubocop:disable Metrics/PerceivedComplexity
237
+ # rubocop:disable Metrics/AbcSize
238
+ sig { params(name: String).returns(T.nilable(T.any(Integer, String))) }
225
239
  def setup(name)
226
240
  # we prioritize version mentioned in "packageManager" instead of "engines"
227
241
  # i.e. if { engines : "pnpm" : "6" } and { packageManager: "pnpm@6.0.2" },
@@ -257,13 +271,13 @@ module Dependabot
257
271
 
258
272
  if version
259
273
  raise_if_unsupported!(name, version.to_s)
260
- install(name, version)
274
+ install(name, version.to_s)
261
275
  end
262
276
  else
263
277
  version ||= requested_version(name)
264
278
 
265
279
  if version
266
- raise_if_unsupported!(name, version)
280
+ raise_if_unsupported!(name, version.to_s)
267
281
 
268
282
  install(name, version)
269
283
  else
@@ -272,30 +286,56 @@ module Dependabot
272
286
  if version
273
287
  raise_if_unsupported!(name, version.to_s)
274
288
 
275
- install(name, version) if name == PNPMPackageManager::NAME
289
+ install(name, version.to_s) if name == PNPMPackageManager::NAME
276
290
  end
277
291
  end
278
292
  end
279
293
  version
280
294
  end
281
- # rubocop:enable Metrics/CyclomaticComplexity
282
- # rubocop:enable Metrics/PerceivedComplexity
283
-
284
- private
285
295
 
286
296
  sig { params(name: T.nilable(String)).returns(Ecosystem::VersionManager) }
287
297
  def package_manager_by_name(name)
288
- name = DEFAULT_PACKAGE_MANAGER if name.nil? || PACKAGE_MANAGER_CLASSES[name].nil?
298
+ name = ensure_valid_package_manager(name)
289
299
 
290
- package_manager_class = PACKAGE_MANAGER_CLASSES[name]
300
+ package_manager_class = T.must(PACKAGE_MANAGER_CLASSES[name])
291
301
 
292
- package_manager_class ||= PACKAGE_MANAGER_CLASSES[DEFAULT_PACKAGE_MANAGER]
302
+ installed_version = installed_version(name)
293
303
 
294
- version = Helpers.send(:"#{name}_version_numeric", @lockfiles[name.to_sym])
304
+ package_manager_class.new(installed_version)
305
+ end
295
306
 
296
- package_manager_class.new(version.to_s)
307
+ # rubocop:enable Metrics/CyclomaticComplexity
308
+ # rubocop:enable Metrics/PerceivedComplexity
309
+ # rubocop:enable Metrics/AbcSize
310
+ # Retrieve the installed version of the package manager by executing
311
+ # the "corepack <name> -v" command and using the output.
312
+ # If the output does not match the expected version format (PACKAGE_MANAGER_VERSION_REGEX),
313
+ # fall back to the version inferred from the dependency files.
314
+ sig { params(name: String).returns(String) }
315
+ def installed_version(name)
316
+ # Return the memoized version if it has already been computed
317
+ return T.must(@installed_versions[name]) if @installed_versions.key?(name)
318
+
319
+ # Attempt to get the installed version through the package manager version command
320
+ @installed_versions[name] = Helpers.package_manager_version(name)
321
+
322
+ # If we can't get the installed version, we need to install the package manager and get the version
323
+ unless @installed_versions[name]&.match?(PACKAGE_MANAGER_VERSION_REGEX)
324
+ setup(name)
325
+ @installed_versions[name] = Helpers.package_manager_version(name)
326
+ end
327
+
328
+ # If we can't get the installed version or the version is invalid, we need to get inferred version
329
+ unless @installed_versions[name]&.match?(PACKAGE_MANAGER_VERSION_REGEX)
330
+ @installed_versions[name] = Helpers.public_send(:"#{name}_version_numeric", @lockfiles[name.to_sym]).to_s
331
+ end
332
+
333
+ T.must(@installed_versions[name])
297
334
  end
298
335
 
336
+ private
337
+
338
+ sig { params(name: String, version: String).void }
299
339
  def raise_if_unsupported!(name, version)
300
340
  return unless name == PNPMPackageManager::NAME
301
341
  return unless Version.new(version) < Version.new("7")
@@ -303,6 +343,7 @@ module Dependabot
303
343
  raise ToolVersionNotSupported.new(PNPMPackageManager::NAME.upcase, version, "7.*, 8.*")
304
344
  end
305
345
 
346
+ sig { params(name: String, version: T.nilable(String)).void }
306
347
  def install(name, version)
307
348
  if Dependabot::Experiments.enabled?(:enable_corepack_for_npm_and_yarn)
308
349
  return Helpers.install(name, version.to_s)
@@ -316,6 +357,13 @@ module Dependabot
316
357
  )
317
358
  end
318
359
 
360
+ sig { params(name: T.nilable(String)).returns(String) }
361
+ def ensure_valid_package_manager(name)
362
+ name = DEFAULT_PACKAGE_MANAGER if name.nil? || PACKAGE_MANAGER_CLASSES[name].nil?
363
+ name
364
+ end
365
+
366
+ sig { params(name: String).returns(T.nilable(String)) }
319
367
  def requested_version(name)
320
368
  return unless @manifest_package_manager
321
369
 
@@ -326,6 +374,7 @@ module Dependabot
326
374
  match["version"]
327
375
  end
328
376
 
377
+ sig { params(name: String).returns(T.nilable(T.any(Integer, String))) }
329
378
  def guessed_version(name)
330
379
  lockfile = @lockfiles[name.to_sym]
331
380
  return unless lockfile
@@ -339,6 +388,8 @@ module Dependabot
339
388
 
340
389
  sig { params(name: T.untyped).returns(T.nilable(String)) }
341
390
  def check_engine_version(name)
391
+ return if @package_json.nil?
392
+
342
393
  version_selector = VersionSelector.new
343
394
  engine_versions = version_selector.setup(@package_json, name)
344
395
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dependabot-npm_and_yarn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.287.0
4
+ version: 0.288.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-19 00:00:00.000000000 Z
11
+ date: 2024-11-21 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.287.0
19
+ version: 0.288.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.287.0
26
+ version: 0.288.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -346,7 +346,7 @@ licenses:
346
346
  - MIT
347
347
  metadata:
348
348
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
349
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.287.0
349
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.288.0
350
350
  post_install_message:
351
351
  rdoc_options: []
352
352
  require_paths: