dependabot-npm_and_yarn 0.239.0 → 0.241.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: 4a56edd19122fd01bf494ccd5c3e4f9641f32289ebabf6bb08915d869ee58f2b
4
- data.tar.gz: 0c9883cde9e28dc7a60056db9766eb1ada8a8b5f3890bba671423571d2164697
3
+ metadata.gz: 854c8f9873cf47c2a5ee76f65a96e3dd91baf4dbe78ed09bee56687377291d80
4
+ data.tar.gz: 603392ebc98a3d0b27744767d8e6cc64c3b3d54e973472378b659da095a3bc38
5
5
  SHA512:
6
- metadata.gz: d74b8568ea273f503b4168667f33fade47048e3364236560a409a9399676b4ed3e5c344435b982f1112ca8340deecb0141d60ca842c080fc0a054c4b49d0b5b0
7
- data.tar.gz: 02af05f027efc8e1e5e429e4485d36d29f1bf636cfb05ae61025e3ce2ef8a77e09292c09e279bf9ab457da0a6533f4faa7c7e7219c2256094cdb28a81fc71ab8
6
+ metadata.gz: 5c259c7e0232109e4b7f936698f56e366f0ea3df09a4bcaada13e2df3c61ae7784d52521778b4fb8e389f823c07d263e3c80e029d7b8141095308dc8d1c5ea8b
7
+ data.tar.gz: 4a5d44748870b26da01b337b4faa75df767ee4f8146245d2650bfe11e0708f20c1beb9701856b967fec3ffcff07c98f183d6740a9bbd3734acb33fd2764c39d6
@@ -8,11 +8,11 @@
8
8
  "hasInstallScript": true,
9
9
  "dependencies": {
10
10
  "@dependabot/yarn-lib": "^1.22.19",
11
- "@npmcli/arborist": "^7.2.1",
11
+ "@npmcli/arborist": "^7.3.0",
12
12
  "@pnpm/dependency-path": "^2.1.1",
13
13
  "@pnpm/lockfile-file": "^8.1.4",
14
14
  "detect-indent": "^6.1.0",
15
- "nock": "^13.3.8",
15
+ "nock": "^13.5.0",
16
16
  "npm": "6.14.18",
17
17
  "patch-package": "^8.0.0",
18
18
  "semver": "^7.4.0"
@@ -1939,9 +1939,9 @@
1939
1939
  }
1940
1940
  },
1941
1941
  "node_modules/@npmcli/arborist": {
1942
- "version": "7.2.1",
1943
- "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.2.1.tgz",
1944
- "integrity": "sha512-o1QIAX56FC8HEPF+Hf4V4/hck9j0a3UiLnMX4aDHPbtU4Po1tUOUSmc2GAx947VWT+acrdMYTDkqUt2CaSXt7A==",
1942
+ "version": "7.3.0",
1943
+ "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.3.0.tgz",
1944
+ "integrity": "sha512-ZElIE9L14fEYiL4KqgqRHmo8fRKiTSOFU3hVS1mNm0zJE7hu4FHmof+OFsA7fAAXfkNDJrDByvD0o7Le0ISHMw==",
1945
1945
  "dependencies": {
1946
1946
  "@isaacs/string-locale-compare": "^1.1.0",
1947
1947
  "@npmcli/fs": "^3.1.0",
@@ -8587,9 +8587,9 @@
8587
8587
  }
8588
8588
  },
8589
8589
  "node_modules/nock": {
8590
- "version": "13.3.8",
8591
- "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.8.tgz",
8592
- "integrity": "sha512-96yVFal0c/W1lG7mmfRe7eO+hovrhJYd2obzzOZ90f6fjpeU/XNvd9cYHZKZAQJumDfhXgoTpkpJ9pvMj+hqHw==",
8590
+ "version": "13.5.0",
8591
+ "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.0.tgz",
8592
+ "integrity": "sha512-9hc1eCS2HtOz+sE9W7JQw/tXJktg0zoPSu48s/pYe73e25JW9ywiowbqnUSd7iZPeVawLcVpPZeZS312fwSY+g==",
8593
8593
  "dependencies": {
8594
8594
  "debug": "^4.1.0",
8595
8595
  "json-stringify-safe": "^5.0.1",
@@ -17168,9 +17168,9 @@
17168
17168
  }
17169
17169
  },
17170
17170
  "@npmcli/arborist": {
17171
- "version": "7.2.1",
17172
- "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.2.1.tgz",
17173
- "integrity": "sha512-o1QIAX56FC8HEPF+Hf4V4/hck9j0a3UiLnMX4aDHPbtU4Po1tUOUSmc2GAx947VWT+acrdMYTDkqUt2CaSXt7A==",
17171
+ "version": "7.3.0",
17172
+ "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-7.3.0.tgz",
17173
+ "integrity": "sha512-ZElIE9L14fEYiL4KqgqRHmo8fRKiTSOFU3hVS1mNm0zJE7hu4FHmof+OFsA7fAAXfkNDJrDByvD0o7Le0ISHMw==",
17174
17174
  "requires": {
17175
17175
  "@isaacs/string-locale-compare": "^1.1.0",
17176
17176
  "@npmcli/fs": "^3.1.0",
@@ -22158,9 +22158,9 @@
22158
22158
  "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="
22159
22159
  },
22160
22160
  "nock": {
22161
- "version": "13.3.8",
22162
- "resolved": "https://registry.npmjs.org/nock/-/nock-13.3.8.tgz",
22163
- "integrity": "sha512-96yVFal0c/W1lG7mmfRe7eO+hovrhJYd2obzzOZ90f6fjpeU/XNvd9cYHZKZAQJumDfhXgoTpkpJ9pvMj+hqHw==",
22161
+ "version": "13.5.0",
22162
+ "resolved": "https://registry.npmjs.org/nock/-/nock-13.5.0.tgz",
22163
+ "integrity": "sha512-9hc1eCS2HtOz+sE9W7JQw/tXJktg0zoPSu48s/pYe73e25JW9ywiowbqnUSd7iZPeVawLcVpPZeZS312fwSY+g==",
22164
22164
  "requires": {
22165
22165
  "debug": "^4.1.0",
22166
22166
  "json-stringify-safe": "^5.0.1",
data/helpers/package.json CHANGED
@@ -11,9 +11,9 @@
11
11
  },
12
12
  "dependencies": {
13
13
  "@dependabot/yarn-lib": "^1.22.19",
14
- "@npmcli/arborist": "^7.2.1",
14
+ "@npmcli/arborist": "^7.3.0",
15
15
  "detect-indent": "^6.1.0",
16
- "nock": "^13.3.8",
16
+ "nock": "^13.5.0",
17
17
  "npm": "6.14.18",
18
18
  "@pnpm/lockfile-file": "^8.1.4",
19
19
  "@pnpm/dependency-path": "^2.1.1",
@@ -11,7 +11,7 @@ describe("findConflictingDependencies", () => {
11
11
  beforeEach(() => {
12
12
  tempDir = fs.mkdtempSync(os.tmpdir() + path.sep);
13
13
  });
14
- afterEach(() => fs.rmdir(tempDir, { recursive: true }, () => {}));
14
+ afterEach(() => fs.rm(tempDir, { recursive: true }, () => {}));
15
15
 
16
16
  it("finds conflicting dependencies", async () => {
17
17
  helpers.copyDependencies("conflicting-dependency-parser/simple", tempDir);
@@ -60,10 +60,9 @@ module Dependabot
60
60
  def ecosystem_versions
61
61
  package_managers = {}
62
62
 
63
- package_managers["npm"] = npm_version if package_lock
63
+ package_managers["npm"] = npm_version if npm_version
64
64
  package_managers["yarn"] = yarn_version if yarn_version
65
65
  package_managers["pnpm"] = pnpm_version if pnpm_version
66
- package_managers["shrinkwrap"] = 1 if shrinkwrap
67
66
  package_managers["unknown"] = 1 if package_managers.empty?
68
67
 
69
68
  {
@@ -75,9 +74,10 @@ module Dependabot
75
74
  def fetch_files
76
75
  fetched_files = []
77
76
  fetched_files << package_json
78
- fetched_files += npm_files
79
- fetched_files += yarn_files
80
- fetched_files += pnpm_files
77
+ fetched_files << npmrc if npmrc
78
+ fetched_files += npm_files if npm_version
79
+ fetched_files += yarn_files if yarn_version
80
+ fetched_files += pnpm_files if pnpm_version
81
81
  fetched_files += lerna_files
82
82
  fetched_files += workspace_package_jsons
83
83
  fetched_files += path_dependencies(fetched_files)
@@ -93,9 +93,8 @@ module Dependabot
93
93
 
94
94
  def npm_files
95
95
  fetched_npm_files = []
96
- fetched_npm_files << package_lock if package_lock
96
+ fetched_npm_files << package_lock if package_lock && !skip_package_lock?
97
97
  fetched_npm_files << shrinkwrap if shrinkwrap
98
- fetched_npm_files << npmrc if npmrc
99
98
  fetched_npm_files << inferred_npmrc if inferred_npmrc
100
99
  fetched_npm_files
101
100
  end
@@ -110,7 +109,7 @@ module Dependabot
110
109
 
111
110
  def pnpm_files
112
111
  fetched_pnpm_files = []
113
- fetched_pnpm_files << pnpm_lock if pnpm_lock
112
+ fetched_pnpm_files << pnpm_lock if pnpm_lock && !skip_pnpm_lock?
114
113
  fetched_pnpm_files << pnpm_workspace_yaml if pnpm_workspace_yaml
115
114
  fetched_pnpm_files += pnpm_workspace_package_jsons
116
115
  fetched_pnpm_files
@@ -131,7 +130,7 @@ module Dependabot
131
130
  return @inferred_npmrc = nil unless npmrc.nil? && package_lock
132
131
 
133
132
  known_registries = []
134
- JSON.parse(package_lock.content).fetch("dependencies", {}).each do |dependency_name, details|
133
+ FileParser::JsonLock.new(package_lock).parsed.fetch("dependencies", {}).each do |dependency_name, details|
135
134
  resolved = details.fetch("resolved", DEFAULT_NPM_REGISTRY)
136
135
 
137
136
  begin
@@ -171,41 +170,28 @@ module Dependabot
171
170
  end
172
171
 
173
172
  def npm_version
174
- Helpers.npm_version_numeric(package_lock.content)
173
+ return @npm_version if defined?(@npm_version)
174
+
175
+ @npm_version = package_manager.setup("npm")
175
176
  end
176
177
 
177
178
  def yarn_version
178
179
  return @yarn_version if defined?(@yarn_version)
179
180
 
180
- @yarn_version = package_manager.requested_version("yarn") || guess_yarn_version
181
- end
182
-
183
- def guess_yarn_version
184
- return unless yarn_lock
185
-
186
- Helpers.yarn_version_numeric(yarn_lock)
181
+ @yarn_version = package_manager.setup("yarn")
187
182
  end
188
183
 
189
184
  def pnpm_version
190
185
  return @pnpm_version if defined?(@pnpm_version)
191
186
 
192
- version = package_manager.requested_version("pnpm") || guess_pnpm_version
193
-
194
- if version && Version.new(version.to_s) < Version.new("7")
195
- raise ToolVersionNotSupported.new("PNPM", version.to_s, "7.*, 8.*")
196
- end
197
-
198
- @pnpm_version = version
199
- end
200
-
201
- def guess_pnpm_version
202
- return unless pnpm_lock
203
-
204
- Helpers.pnpm_version_numeric(pnpm_lock)
187
+ @pnpm_version = package_manager.setup("pnpm")
205
188
  end
206
189
 
207
190
  def package_manager
208
- @package_manager ||= PackageManager.new(parsed_package_json)
191
+ @package_manager ||= PackageManager.new(
192
+ parsed_package_json,
193
+ lockfiles: { npm: package_lock || shrinkwrap, yarn: yarn_lock, pnpm: pnpm_lock }
194
+ )
209
195
  end
210
196
 
211
197
  def package_json
@@ -215,7 +201,7 @@ module Dependabot
215
201
  def package_lock
216
202
  return @package_lock if defined?(@package_lock)
217
203
 
218
- @package_lock = fetch_file_if_present("package-lock.json") unless skip_package_lock?
204
+ @package_lock = fetch_file_if_present("package-lock.json")
219
205
  end
220
206
 
221
207
  def yarn_lock
@@ -227,7 +213,7 @@ module Dependabot
227
213
  def pnpm_lock
228
214
  return @pnpm_lock if defined?(@pnpm_lock)
229
215
 
230
- @pnpm_lock = fetch_file_if_present("pnpm-lock.yaml") unless skip_pnpm_lock?
216
+ @pnpm_lock = fetch_file_if_present("pnpm-lock.yaml")
231
217
  end
232
218
 
233
219
  def shrinkwrap
@@ -379,7 +365,7 @@ module Dependabot
379
365
  current_depth = File.join(directory, file.name).split("/").count { |path| !path.empty? }
380
366
  path_to_directory = "../" * current_depth
381
367
 
382
- dep_types = NpmAndYarn::FileParser::DEPENDENCY_TYPES
368
+ dep_types = FileParser::DEPENDENCY_TYPES
383
369
  parsed_manifest = JSON.parse(file.content)
384
370
  dependency_objects = parsed_manifest.values_at(*dep_types).compact
385
371
  # Fetch yarn "file:" path "resolutions" so the lockfile can be resolved
@@ -24,7 +24,7 @@ module Dependabot
24
24
  end
25
25
 
26
26
  def details(dependency_name, _requirement, manifest_name)
27
- if Helpers.npm_version(@dependency_file.content) == "npm8"
27
+ if Helpers.npm8?(@dependency_file)
28
28
  # NOTE: npm 8 sometimes doesn't install workspace dependencies in the
29
29
  # workspace folder so we need to fallback to checking top-level
30
30
  nested_details = parsed.dig("packages", node_modules_path(manifest_name, dependency_name))
@@ -248,7 +248,6 @@ module Dependabot
248
248
  # run when installing git dependencies
249
249
  def run_npm_install_lockfile_only(*install_args)
250
250
  command = [
251
- "npm",
252
251
  "install",
253
252
  *install_args,
254
253
  "--force",
@@ -259,7 +258,6 @@ module Dependabot
259
258
  ].join(" ")
260
259
 
261
260
  fingerprint = [
262
- "npm",
263
261
  "install",
264
262
  install_args.empty? ? "" : "<install_args>",
265
263
  "--force",
@@ -269,7 +267,7 @@ module Dependabot
269
267
  "--package-lock-only"
270
268
  ].join(" ")
271
269
 
272
- SharedHelpers.run_shell_command(command, fingerprint: fingerprint)
270
+ Helpers.run_npm_command(command, fingerprint: fingerprint)
273
271
  end
274
272
 
275
273
  def npm_install_args(dependency)
@@ -830,7 +828,7 @@ module Dependabot
830
828
  def npm8?
831
829
  return @npm8 if defined?(@npm8)
832
830
 
833
- @npm8 = Dependabot::NpmAndYarn::Helpers.npm_version(lockfile.content) == "npm8"
831
+ @npm8 = Dependabot::NpmAndYarn::Helpers.npm8?(lockfile)
834
832
  end
835
833
 
836
834
  def sanitize_package_name(package_name)
@@ -62,15 +62,15 @@ module Dependabot
62
62
  "#{d.name}@#{d.version}"
63
63
  end.join(" ")
64
64
 
65
- SharedHelpers.run_shell_command(
66
- "pnpm install #{dependency_updates} --lockfile-only --ignore-workspace-root-check",
67
- fingerprint: "pnpm install <dependency_updates> --lockfile-only --ignore-workspace-root-check"
65
+ Helpers.run_pnpm_command(
66
+ "install #{dependency_updates} --lockfile-only --ignore-workspace-root-check",
67
+ fingerprint: "install <dependency_updates> --lockfile-only --ignore-workspace-root-check"
68
68
  )
69
69
  end
70
70
 
71
71
  def run_pnpm_install
72
- SharedHelpers.run_shell_command(
73
- "pnpm install --lockfile-only"
72
+ Helpers.run_pnpm_command(
73
+ "install --lockfile-only"
74
74
  )
75
75
  end
76
76
 
@@ -152,15 +152,15 @@ module Dependabot
152
152
  # the lockfile.
153
153
 
154
154
  if top_level_dependency_updates.all? { |dep| requirements_changed?(dep[:name]) }
155
- Helpers.run_yarn_command("yarn install #{yarn_berry_args}".strip)
155
+ Helpers.run_yarn_command("install #{yarn_berry_args}".strip)
156
156
  else
157
157
  updates = top_level_dependency_updates.collect do |dep|
158
158
  dep[:name]
159
159
  end
160
160
 
161
161
  Helpers.run_yarn_command(
162
- "yarn up -R #{updates.join(' ')} #{yarn_berry_args}".strip,
163
- fingerprint: "yarn up -R <dependency_names> #{yarn_berry_args}".strip
162
+ "up -R #{updates.join(' ')} #{yarn_berry_args}".strip,
163
+ fingerprint: "up -R <dependency_names> #{yarn_berry_args}".strip
164
164
  )
165
165
  end
166
166
  { yarn_lock.name => File.read(yarn_lock.name) }
@@ -176,9 +176,9 @@ module Dependabot
176
176
  update = "#{dep.name}@#{dep.version}"
177
177
 
178
178
  commands = [
179
- ["yarn add #{update} #{yarn_berry_args}".strip, "yarn add <update> #{yarn_berry_args}".strip],
180
- ["yarn dedupe #{dep.name} #{yarn_berry_args}".strip, "yarn dedupe <dep_name> #{yarn_berry_args}".strip],
181
- ["yarn remove #{dep.name} #{yarn_berry_args}".strip, "yarn remove <dep_name> #{yarn_berry_args}".strip]
179
+ ["add #{update} #{yarn_berry_args}".strip, "add <update> #{yarn_berry_args}".strip],
180
+ ["dedupe #{dep.name} #{yarn_berry_args}".strip, "dedupe <dep_name> #{yarn_berry_args}".strip],
181
+ ["remove #{dep.name} #{yarn_berry_args}".strip, "remove <dep_name> #{yarn_berry_args}".strip]
182
182
  ]
183
183
 
184
184
  Helpers.run_yarn_commands(*commands)
@@ -7,13 +7,9 @@ module Dependabot
7
7
  YARN_PATH_NOT_FOUND =
8
8
  /^.*(?<error>The "yarn-path" option has been set \(in [^)]+\), but the specified location doesn't exist)/
9
9
 
10
- def self.npm_version(lockfile_content)
11
- "npm#{npm_version_numeric(lockfile_content)}"
12
- end
13
-
14
- def self.npm_version_numeric(lockfile_content)
15
- return 8 unless lockfile_content
16
- return 8 if JSON.parse(lockfile_content)["lockfileVersion"] >= 2
10
+ def self.npm_version_numeric(lockfile)
11
+ lockfile_content = lockfile.content
12
+ return 8 if JSON.parse(lockfile_content)["lockfileVersion"].to_i >= 2
17
13
 
18
14
  6
19
15
  rescue JSON::ParserError
@@ -31,8 +27,10 @@ module Dependabot
31
27
  # Mapping from lockfile versions to PNPM versions is at
32
28
  # https://github.com/pnpm/spec/tree/274ff02de23376ad59773a9f25ecfedd03a41f64/lockfile, but simplify it for now.
33
29
  def self.pnpm_version_numeric(pnpm_lock)
34
- if pnpm_lockfile_version(pnpm_lock).to_f >= 5.4
30
+ if pnpm_lockfile_version(pnpm_lock).to_f >= 6.0
35
31
  8
32
+ elsif pnpm_lockfile_version(pnpm_lock).to_f >= 5.4
33
+ 7
36
34
  else
37
35
  6
38
36
  end
@@ -46,6 +44,12 @@ module Dependabot
46
44
  end
47
45
  end
48
46
 
47
+ def self.npm8?(package_lock)
48
+ return true unless package_lock
49
+
50
+ npm_version_numeric(package_lock) == 8
51
+ end
52
+
49
53
  def self.yarn_berry?(yarn_lock)
50
54
  yaml = YAML.safe_load(yarn_lock.content)
51
55
  yaml.key?("__metadata")
@@ -55,7 +59,7 @@ module Dependabot
55
59
 
56
60
  def self.yarn_major_version
57
61
  retries = 0
58
- output = SharedHelpers.run_shell_command("yarn --version")
62
+ output = run_single_yarn_command("--version")
59
63
  Version.new(output).major
60
64
  rescue Dependabot::SharedHelpers::HelperSubprocessFailed => e
61
65
  # Should never happen, can probably be removed once this settles
@@ -118,23 +122,23 @@ module Dependabot
118
122
 
119
123
  def self.setup_yarn_berry
120
124
  # Always disable immutable installs so yarn's CI detection doesn't prevent updates.
121
- SharedHelpers.run_shell_command("yarn config set enableImmutableInstalls false")
125
+ run_single_yarn_command("config set enableImmutableInstalls false")
122
126
  # Do not generate a cache if offline cache disabled. Otherwise side effects may confuse further checks
123
- SharedHelpers.run_shell_command("yarn config set enableGlobalCache true") unless yarn_berry_skip_build?
127
+ run_single_yarn_command("config set enableGlobalCache true") unless yarn_berry_skip_build?
124
128
  # We never want to execute postinstall scripts, either set this config or mode=skip-build must be set
125
- SharedHelpers.run_shell_command("yarn config set enableScripts false") if yarn_berry_disable_scripts?
129
+ run_single_yarn_command("config set enableScripts false") if yarn_berry_disable_scripts?
126
130
  if (http_proxy = ENV.fetch("HTTP_PROXY", false))
127
- SharedHelpers.run_shell_command("yarn config set httpProxy #{http_proxy}")
131
+ run_single_yarn_command("config set httpProxy #{http_proxy}", fingerprint: "config set httpProxy <proxy>")
128
132
  end
129
133
  if (https_proxy = ENV.fetch("HTTPS_PROXY", false))
130
- SharedHelpers.run_shell_command("yarn config set httpsProxy #{https_proxy}")
134
+ run_single_yarn_command("config set httpsProxy #{https_proxy}", fingerprint: "config set httpsProxy <proxy>")
131
135
  end
132
136
  return unless (ca_file_path = ENV.fetch("NODE_EXTRA_CA_CERTS", false))
133
137
 
134
138
  if yarn_4_or_higher?
135
- SharedHelpers.run_shell_command("yarn config set httpsCaFilePath #{ca_file_path}")
139
+ run_single_yarn_command("config set httpsCaFilePath #{ca_file_path}")
136
140
  else
137
- SharedHelpers.run_shell_command("yarn config set caFilePath #{ca_file_path}")
141
+ run_single_yarn_command("config set caFilePath #{ca_file_path}")
138
142
  end
139
143
  end
140
144
 
@@ -144,14 +148,34 @@ module Dependabot
144
148
  # contain malicious code.
145
149
  def self.run_yarn_commands(*commands)
146
150
  setup_yarn_berry
147
- commands.each { |cmd, fingerprint| SharedHelpers.run_shell_command(cmd, fingerprint: fingerprint) }
151
+ commands.each { |cmd, fingerprint| run_single_yarn_command(cmd, fingerprint: fingerprint) }
148
152
  end
149
153
 
150
- # Run a single yarn command returning stdout/stderr
154
+ # Run single npm command returning stdout/stderr.
155
+ #
156
+ # NOTE: Needs to be explicitly run through corepack to respect the
157
+ # `packageManager` setting in `package.json`, because corepack does not
158
+ # add shims for NPM.
159
+ def self.run_npm_command(command, fingerprint: command)
160
+ SharedHelpers.run_shell_command("corepack npm #{command}", fingerprint: "corepack npm #{fingerprint}")
161
+ end
162
+
163
+ # Setup yarn and run a single yarn command returning stdout/stderr
151
164
  def self.run_yarn_command(command, fingerprint: nil)
152
165
  setup_yarn_berry
153
- SharedHelpers.run_shell_command(command, fingerprint: fingerprint)
166
+ run_single_yarn_command(command, fingerprint: fingerprint)
167
+ end
168
+
169
+ # Run single pnpm command returning stdout/stderr
170
+ def self.run_pnpm_command(command, fingerprint: nil)
171
+ SharedHelpers.run_shell_command("pnpm #{command}", fingerprint: "pnpm #{fingerprint || command}")
172
+ end
173
+
174
+ # Run single yarn command returning stdout/stderr
175
+ def self.run_single_yarn_command(command, fingerprint: nil)
176
+ SharedHelpers.run_shell_command("yarn #{command}", fingerprint: "yarn #{fingerprint || command}")
154
177
  end
178
+ private_class_method :run_single_yarn_command
155
179
 
156
180
  def self.pnpm_lockfile_version(pnpm_lock)
157
181
  pnpm_lock.content.match(/^lockfileVersion: ['"]?(?<version>[\d.]+)/)[:version]
@@ -23,7 +23,6 @@ module Dependabot
23
23
  # - `--ignore-scripts` disables prepare and prepack scripts which are run
24
24
  # when installing git dependencies
25
25
  command = [
26
- "npm",
27
26
  "update",
28
27
  *dependency_names,
29
28
  "--force",
@@ -34,7 +33,6 @@ module Dependabot
34
33
  ].join(" ")
35
34
 
36
35
  fingerprint = [
37
- "npm",
38
36
  "update",
39
37
  "<dependency_names>",
40
38
  "--force",
@@ -44,7 +42,7 @@ module Dependabot
44
42
  "--package-lock-only"
45
43
  ].join(" ")
46
44
 
47
- SharedHelpers.run_shell_command(command, fingerprint: fingerprint)
45
+ Helpers.run_npm_command(command, fingerprint: fingerprint)
48
46
  end
49
47
  end
50
48
  end
@@ -1,19 +1,69 @@
1
1
  # typed: true
2
2
  # frozen_string_literal: true
3
3
 
4
+ require "dependabot/shared_helpers"
5
+
4
6
  module Dependabot
5
7
  module NpmAndYarn
6
8
  class PackageManager
7
- def initialize(package_json)
9
+ def initialize(package_json, lockfiles:)
8
10
  @package_json = package_json
11
+ @lockfiles = lockfiles
12
+ @package_manager = package_json.fetch("packageManager", nil)
13
+ end
14
+
15
+ def setup(name)
16
+ return unless @package_manager.nil? || @package_manager.start_with?("#{name}@")
17
+
18
+ version = requested_version(name)
19
+
20
+ if version
21
+ raise_if_unsupported!(name, version)
22
+
23
+ install(name, version)
24
+ else
25
+ version = guessed_version(name)
26
+
27
+ if version
28
+ raise_if_unsupported!(name, version.to_s)
29
+
30
+ install(name, version) if name == "pnpm"
31
+ end
32
+ end
33
+
34
+ version
35
+ end
36
+
37
+ private
38
+
39
+ def raise_if_unsupported!(name, version)
40
+ return unless name == "pnpm"
41
+ return unless Version.new(version) < Version.new("7")
42
+
43
+ raise ToolVersionNotSupported.new("PNPM", version, "7.*, 8.*")
44
+ end
45
+
46
+ def install(name, version)
47
+ SharedHelpers.run_shell_command(
48
+ "corepack install #{name}@#{version} --global --cache-only",
49
+ fingerprint: "corepack install <name>@<version> --global --cache-only"
50
+ )
9
51
  end
10
52
 
11
53
  def requested_version(name)
12
- version = @package_json.fetch("packageManager", nil)
13
- return unless version
54
+ return unless @package_manager
55
+
56
+ match = @package_manager.match(/#{name}@(?<version>\d+.\d+.\d+)/)
57
+ return unless match
58
+
59
+ match["version"]
60
+ end
61
+
62
+ def guessed_version(name)
63
+ lockfile = @lockfiles[name.to_sym]
64
+ return unless lockfile
14
65
 
15
- version_match = version.match(/#{name}@(?<version>\d+.\d+.\d+)/)
16
- version_match&.named_captures&.fetch("version", nil)
66
+ Helpers.send(:"#{name}_version_numeric", lockfile)
17
67
  end
18
68
  end
19
69
  end
@@ -34,7 +34,7 @@ module Dependabot
34
34
 
35
35
  return DefaultRequirement if matches[1] == ">=" && matches[2] == "0"
36
36
 
37
- [matches[1] || "=", NpmAndYarn::Version.new(matches[2])]
37
+ [matches[1] || "=", NpmAndYarn::Version.new(T.must(matches[2]))]
38
38
  end
39
39
 
40
40
  # Returns an array of requirements. At least one requirement from the
@@ -66,8 +66,10 @@ module Dependabot
66
66
  run_yarn_updater(path, lockfile_name)
67
67
  elsif lockfile.name.end_with?("pnpm-lock.yaml")
68
68
  run_pnpm_updater(path, lockfile_name)
69
+ elsif Helpers.npm8?(lockfile)
70
+ run_npm8_updater(path, lockfile_name)
69
71
  else
70
- run_npm_updater(path, lockfile_name, lockfile.content)
72
+ run_npm_updater(path, lockfile_name)
71
73
  end
72
74
 
73
75
  updated_files.fetch(lockfile_name)
@@ -116,8 +118,8 @@ module Dependabot
116
118
  SharedHelpers.with_git_configured(credentials: credentials) do
117
119
  Dir.chdir(path) do
118
120
  Helpers.run_yarn_command(
119
- "yarn up -R #{dependency.name} #{Helpers.yarn_berry_args}".strip,
120
- fingerprint: "yarn up -R <dependency_name> #{Helpers.yarn_berry_args}".strip
121
+ "up -R #{dependency.name} #{Helpers.yarn_berry_args}".strip,
122
+ fingerprint: "up -R <dependency_name> #{Helpers.yarn_berry_args}".strip
121
123
  )
122
124
  { lockfile_name => File.read(lockfile_name) }
123
125
  end
@@ -127,30 +129,33 @@ module Dependabot
127
129
  def run_pnpm_updater(path, lockfile_name)
128
130
  SharedHelpers.with_git_configured(credentials: credentials) do
129
131
  Dir.chdir(path) do
130
- SharedHelpers.run_shell_command(
131
- "pnpm update #{dependency.name} --lockfile-only",
132
- fingerprint: "pnpm update <dependency_name> --lockfile-only"
132
+ Helpers.run_pnpm_command(
133
+ "update #{dependency.name} --lockfile-only",
134
+ fingerprint: "update <dependency_name> --lockfile-only"
133
135
  )
134
136
  { lockfile_name => File.read(lockfile_name) }
135
137
  end
136
138
  end
137
139
  end
138
140
 
139
- def run_npm_updater(path, lockfile_name, lockfile_content)
141
+ def run_npm8_updater(path, lockfile_name)
140
142
  SharedHelpers.with_git_configured(credentials: credentials) do
141
143
  Dir.chdir(path) do
142
- npm_version = Dependabot::NpmAndYarn::Helpers.npm_version(lockfile_content)
143
-
144
- if npm_version == "npm8"
145
- NativeHelpers.run_npm8_subdependency_update_command([dependency.name])
146
- { lockfile_name => File.read(lockfile_name) }
147
- else
148
- SharedHelpers.run_helper_subprocess(
149
- command: NativeHelpers.helper_path,
150
- function: "npm6:updateSubdependency",
151
- args: [Dir.pwd, lockfile_name, [dependency.to_h]]
152
- )
153
- end
144
+ NativeHelpers.run_npm8_subdependency_update_command([dependency.name])
145
+
146
+ { lockfile_name => File.read(lockfile_name) }
147
+ end
148
+ end
149
+ end
150
+
151
+ def run_npm_updater(path, lockfile_name)
152
+ SharedHelpers.with_git_configured(credentials: credentials) do
153
+ Dir.chdir(path) do
154
+ SharedHelpers.run_helper_subprocess(
155
+ command: NativeHelpers.helper_path,
156
+ function: "npm6:updateSubdependency",
157
+ args: [Dir.pwd, lockfile_name, [dependency.to_h]]
158
+ )
154
159
  end
155
160
  end
156
161
  end
@@ -539,9 +539,9 @@ module Dependabot
539
539
  def run_pnpm_checker(path:, version:)
540
540
  SharedHelpers.with_git_configured(credentials: credentials) do
541
541
  Dir.chdir(path) do
542
- output = SharedHelpers.run_shell_command(
543
- "pnpm update #{dependency.name}@#{version} --lockfile-only",
544
- fingerprint: "pnpm update <dependency_name>@<version> --lockfile-only"
542
+ output = Helpers.run_pnpm_command(
543
+ "update #{dependency.name}@#{version} --lockfile-only",
544
+ fingerprint: "update <dependency_name>@<version> --lockfile-only"
545
545
  )
546
546
  if PNPM_PEER_DEP_ERROR_REGEX.match?(output)
547
547
  raise SharedHelpers::HelperSubprocessFailed.new(
@@ -562,7 +562,7 @@ module Dependabot
562
562
  SharedHelpers.with_git_configured(credentials: credentials) do
563
563
  Dir.chdir(path) do
564
564
  output = Helpers.run_yarn_command(
565
- "yarn add #{dependency.name}@#{version} #{Helpers.yarn_berry_args}".strip
565
+ "add #{dependency.name}@#{version} #{Helpers.yarn_berry_args}".strip
566
566
  )
567
567
  if output.include?("YN0060")
568
568
  raise SharedHelpers::HelperSubprocessFailed.new(
@@ -598,9 +598,8 @@ module Dependabot
598
598
  # Find the lockfile that's in the current directory
599
599
  f.name == [path, "package-lock.json"].join("/").sub(%r{\A.?\/}, "")
600
600
  end
601
- npm_version = Dependabot::NpmAndYarn::Helpers.npm_version(package_lock&.content)
602
601
 
603
- return run_npm8_checker(version: version) if npm_version == "npm8"
602
+ return run_npm8_checker(version: version) if Dependabot::NpmAndYarn::Helpers.npm8?(package_lock)
604
603
 
605
604
  SharedHelpers.run_helper_subprocess(
606
605
  command: NativeHelpers.helper_path,
@@ -619,8 +618,8 @@ module Dependabot
619
618
 
620
619
  def run_npm8_checker(version:)
621
620
  cmd =
622
- "npm install #{version_install_arg(version: version)} --package-lock-only --dry-run=true --ignore-scripts"
623
- output = SharedHelpers.run_shell_command(cmd)
621
+ "install #{version_install_arg(version: version)} --package-lock-only --dry-run=true --ignore-scripts"
622
+ output = Helpers.run_npm_command(cmd)
624
623
  if output.match?(NPM8_PEER_DEP_ERROR_REGEX)
625
624
  error_context = { command: cmd, process_exit_value: 1 }
626
625
  raise SharedHelpers::HelperSubprocessFailed.new(message: output, error_context: error_context)
@@ -21,7 +21,20 @@ module Dependabot
21
21
  VERSION_PATTERN = T.let(Gem::Version::VERSION_PATTERN + '(\+[0-9a-zA-Z\-.]+)?', String)
22
22
  ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/
23
23
 
24
- sig { override.params(version: T.nilable(T.any(String, Gem::Version))).returns(T::Boolean) }
24
+ sig do
25
+ override
26
+ .overridable
27
+ .params(
28
+ version: T.any(
29
+ String,
30
+ Integer,
31
+ Float,
32
+ Gem::Version,
33
+ NilClass
34
+ )
35
+ )
36
+ .returns(T::Boolean)
37
+ end
25
38
  def self.correct?(version)
26
39
  version = version.gsub(/^v/, "") if version.is_a?(String)
27
40
 
@@ -42,29 +55,58 @@ module Dependabot
42
55
  version
43
56
  end
44
57
 
45
- sig { override.params(version: T.any(String, Gem::Version)).void }
58
+ sig do
59
+ override
60
+ .params(
61
+ version: T.any(
62
+ String,
63
+ Integer,
64
+ Float,
65
+ Gem::Version,
66
+ NilClass
67
+ )
68
+ )
69
+ .void
70
+ end
46
71
  def initialize(version)
47
72
  @version_string = T.let(version.to_s, String)
48
73
  version = version.gsub(/^v/, "") if version.is_a?(String)
49
74
 
50
75
  version, @build_info = version.to_s.split("+") if version.to_s.include?("+")
51
76
 
52
- super
77
+ super(T.must(version))
78
+ end
79
+
80
+ sig do
81
+ override
82
+ .params(
83
+ version: T.any(
84
+ String,
85
+ Integer,
86
+ Float,
87
+ Gem::Version,
88
+ NilClass
89
+ )
90
+ )
91
+ .returns(Dependabot::NpmAndYarn::Version)
92
+ end
93
+ def self.new(version)
94
+ T.cast(super, Dependabot::NpmAndYarn::Version)
53
95
  end
54
96
 
55
97
  sig { returns(Integer) }
56
98
  def major
57
- @major ||= T.let(segments[0] || 0, T.nilable(Integer))
99
+ @major ||= T.let(segments[0].to_i, T.nilable(Integer))
58
100
  end
59
101
 
60
102
  sig { returns(Integer) }
61
103
  def minor
62
- @minor ||= T.let(segments[1] || 0, T.nilable(Integer))
104
+ @minor ||= T.let(segments[1].to_i, T.nilable(Integer))
63
105
  end
64
106
 
65
107
  sig { returns(Integer) }
66
108
  def patch
67
- @patch ||= T.let(segments[2] || 0, T.nilable(Integer))
109
+ @patch ||= T.let(segments[2].to_i, T.nilable(Integer))
68
110
  end
69
111
 
70
112
  sig { params(other: Dependabot::NpmAndYarn::Version).returns(T::Boolean) }
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.239.0
4
+ version: 0.241.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-12-28 00:00:00.000000000 Z
11
+ date: 2024-01-18 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.239.0
19
+ version: 0.241.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.239.0
26
+ version: 0.241.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -206,6 +206,20 @@ dependencies:
206
206
  - - "~>"
207
207
  - !ruby/object:Gem::Version
208
208
  version: '3.18'
209
+ - !ruby/object:Gem::Dependency
210
+ name: webrick
211
+ requirement: !ruby/object:Gem::Requirement
212
+ requirements:
213
+ - - ">="
214
+ - !ruby/object:Gem::Version
215
+ version: '1.7'
216
+ type: :development
217
+ prerelease: false
218
+ version_requirements: !ruby/object:Gem::Requirement
219
+ requirements:
220
+ - - ">="
221
+ - !ruby/object:Gem::Version
222
+ version: '1.7'
209
223
  description: Dependabot-NPM_And_Yarn provides support for bumping Javascript (npm
210
224
  and yarn) libraries via Dependabot. If you want support for multiple package managers,
211
225
  you probably want the meta-gem dependabot-omnibus.
@@ -310,7 +324,7 @@ licenses:
310
324
  - Nonstandard
311
325
  metadata:
312
326
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
313
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.239.0
327
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.241.0
314
328
  post_install_message:
315
329
  rdoc_options: []
316
330
  require_paths: