dependabot-npm_and_yarn 0.293.0 → 0.294.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d548c0891264c8b407f2b673e39266b3494683e431ac1e8b9ebc899319208f5
4
- data.tar.gz: b43aeb89fb1a1c1e32a9d86eee5ccc188d8fc3da548ee4cbbcfbc4c76cfd59c7
3
+ metadata.gz: 72e338772b3c3aac3cf86538fc2d70dbbc45f5f7cb854cd7fd74913b140fe056
4
+ data.tar.gz: 1856c138b871ebe80e5cc6faa5984ba80c10b342aa8bf0822e325e5a31a3f815
5
5
  SHA512:
6
- metadata.gz: 95eef6390619686a8017fc949e5a5609e34f3675920fea726975fb42c55904e9901ef55b80df005ffa43bf74e87623ed00a9a287005af9446c93b78fcb0c010d
7
- data.tar.gz: 9a104350702acef102f005bdc0c4649b7713288de3685992538f9e58384487802f48a1f1c6e57dd6ac244fb11e849fd89b72f2f3648355eb3115d1174846e21f
6
+ metadata.gz: 0e3267d0aafcf35e345505c87a23b2b783cfc36377e46f5f10875a4bd8b0c4fe201b6dea0dbed75463b75dccba175014af850451cfc52b39c0a2a410a5c5ab34
7
+ data.tar.gz: a1c6be5ccbebcf43a76a51d7871a37743428f052c734a985a48fc90d4b1e2944679a8b6eb17910a8ef7e14c69dbe46d9761319b28d6a57d7dcbac7e94fbb9c09
@@ -97,9 +97,9 @@ async function findVulnerableDependencies(directory, advisories) {
97
97
 
98
98
  for (const group of groupedFixUpdateChains.values()) {
99
99
  const fixUpdateNode = group[0].nodes[0]
100
- const groupTopLevelAncestors = group.reduce((anc, chain) => {
100
+ const groupTopLevelAncestors = group.reduce((ancestor, chain) => {
101
101
  const topLevelNode = chain.nodes[chain.nodes.length - 1]
102
- return anc.add(topLevelNode.name)
102
+ return ancestor.add(topLevelNode.name)
103
103
  }, new Set())
104
104
 
105
105
  // Add group's top-level ancestors to the set of all top-level ancestors of
@@ -269,23 +269,23 @@ const maybeReadFile = file => {
269
269
  }
270
270
 
271
271
  function loadCACerts(npmConfig) {
272
- if (npmConfig.ca) {
273
- return npmConfig.ca
274
- }
272
+ if (npmConfig.ca) {
273
+ return npmConfig.ca
274
+ }
275
275
 
276
- if (!npmConfig.cafile) {
277
- return
278
- }
276
+ if (!npmConfig.cafile) {
277
+ return
278
+ }
279
279
 
280
- const raw = maybeReadFile(npmConfig.cafile)
281
- if (!raw) {
282
- return
283
- }
280
+ const raw = maybeReadFile(npmConfig.cafile)
281
+ if (!raw) {
282
+ return
283
+ }
284
284
 
285
- const delim = '-----END CERTIFICATE-----'
286
- return raw.replace(/\r\n/g, '\n').split(delim)
287
- .filter(section => section.trim())
288
- .map(section => section.trimStart() + delim)
285
+ const delim = '-----END CERTIFICATE-----'
286
+ return raw.replace(/\r\n/g, '\n').split(delim)
287
+ .filter(section => section.trim())
288
+ .map(section => section.trimStart() + delim)
289
289
  }
290
290
 
291
291
  module.exports = { findVulnerableDependencies }
@@ -113,7 +113,7 @@ function flattenAllDependencies(manifest) {
113
113
  );
114
114
  }
115
115
 
116
- // NOTE: Re-used in npm 7 updater
116
+ // NOTE: Reused in npm 7 updater
117
117
  function installArgs(
118
118
  depName,
119
119
  desiredVersion,
@@ -39,7 +39,7 @@ module Dependabot
39
39
 
40
40
  sig { override.returns(T::Boolean) }
41
41
  def unsupported?
42
- supported_versions.all? { |supported| supported > version }
42
+ false
43
43
  end
44
44
  end
45
45
  end
@@ -213,7 +213,7 @@ module Dependabot
213
213
 
214
214
  sig { returns(T.nilable(T.any(Integer, String))) }
215
215
  def bun_version
216
- return @bun_version = nil unless Experiments.enabled?(:bun_updates)
216
+ return @bun_version = nil unless allow_beta_ecosystems?
217
217
 
218
218
  @bun_version ||= T.let(
219
219
  package_manager_helper.setup(BunPackageManager::NAME),
@@ -453,6 +453,15 @@ module Dependabot
453
453
 
454
454
  resolution_deps = resolution_objects.flat_map(&:to_a)
455
455
  .map do |path, value|
456
+ # skip dependencies that contain invalid values such as inline comments, null, etc.
457
+
458
+ unless value.is_a?(String)
459
+ Dependabot.logger.warn("File fetcher: Skipping dependency \"#{path}\" " \
460
+ "with value: \"#{value}\"")
461
+
462
+ next
463
+ end
464
+
456
465
  convert_dependency_path_to_name(path, value)
457
466
  end
458
467
 
@@ -645,8 +654,8 @@ module Dependabot
645
654
  def parsed_pnpm_workspace_yaml
646
655
  return {} unless pnpm_workspace_yaml
647
656
 
648
- YAML.safe_load(T.must(T.must(pnpm_workspace_yaml).content))
649
- rescue Psych::SyntaxError
657
+ YAML.safe_load(T.must(T.must(pnpm_workspace_yaml).content), aliases: true)
658
+ rescue Psych::SyntaxError, Psych::BadAlias
650
659
  raise Dependabot::DependencyFileNotParseable, T.must(pnpm_workspace_yaml).path
651
660
  end
652
661
 
@@ -143,56 +143,56 @@ module Dependabot
143
143
  sig { returns(T.nilable(Dependabot::DependencyFile)) }
144
144
  def shrinkwrap
145
145
  @shrinkwrap ||= T.let(dependency_files.find do |f|
146
- f.name == NpmPackageManager::SHRINKWRAP_LOCKFILE_NAME
146
+ f.name.end_with?(NpmPackageManager::SHRINKWRAP_LOCKFILE_NAME)
147
147
  end, T.nilable(Dependabot::DependencyFile))
148
148
  end
149
149
 
150
150
  sig { returns(T.nilable(Dependabot::DependencyFile)) }
151
151
  def package_lock
152
152
  @package_lock ||= T.let(dependency_files.find do |f|
153
- f.name == NpmPackageManager::LOCKFILE_NAME
153
+ f.name.end_with?(NpmPackageManager::LOCKFILE_NAME)
154
154
  end, T.nilable(Dependabot::DependencyFile))
155
155
  end
156
156
 
157
157
  sig { returns(T.nilable(Dependabot::DependencyFile)) }
158
158
  def yarn_lock
159
159
  @yarn_lock ||= T.let(dependency_files.find do |f|
160
- f.name == YarnPackageManager::LOCKFILE_NAME
160
+ f.name.end_with?(YarnPackageManager::LOCKFILE_NAME)
161
161
  end, T.nilable(Dependabot::DependencyFile))
162
162
  end
163
163
 
164
164
  sig { returns(T.nilable(Dependabot::DependencyFile)) }
165
165
  def pnpm_lock
166
166
  @pnpm_lock ||= T.let(dependency_files.find do |f|
167
- f.name == PNPMPackageManager::LOCKFILE_NAME
167
+ f.name.end_with?(PNPMPackageManager::LOCKFILE_NAME)
168
168
  end, T.nilable(Dependabot::DependencyFile))
169
169
  end
170
170
 
171
171
  sig { returns(T.nilable(Dependabot::DependencyFile)) }
172
172
  def bun_lock
173
173
  @bun_lock ||= T.let(dependency_files.find do |f|
174
- f.name == BunPackageManager::LOCKFILE_NAME
174
+ f.name.end_with?(BunPackageManager::LOCKFILE_NAME)
175
175
  end, T.nilable(Dependabot::DependencyFile))
176
176
  end
177
177
 
178
178
  sig { returns(T.nilable(Dependabot::DependencyFile)) }
179
179
  def npmrc
180
180
  @npmrc ||= T.let(dependency_files.find do |f|
181
- f.name == NpmPackageManager::RC_FILENAME
181
+ f.name.end_with?(NpmPackageManager::RC_FILENAME)
182
182
  end, T.nilable(Dependabot::DependencyFile))
183
183
  end
184
184
 
185
185
  sig { returns(T.nilable(Dependabot::DependencyFile)) }
186
186
  def yarnrc
187
187
  @yarnrc ||= T.let(dependency_files.find do |f|
188
- f.name == YarnPackageManager::RC_FILENAME
188
+ f.name.end_with?(YarnPackageManager::RC_FILENAME)
189
189
  end, T.nilable(Dependabot::DependencyFile))
190
190
  end
191
191
 
192
192
  sig { returns(T.nilable(DependencyFile)) }
193
193
  def yarnrc_yml
194
194
  @yarnrc_yml ||= T.let(dependency_files.find do |f|
195
- f.name == YarnPackageManager::RC_YML_FILENAME
195
+ f.name.end_with?(YarnPackageManager::RC_YML_FILENAME)
196
196
  end, T.nilable(Dependabot::DependencyFile))
197
197
  end
198
198
 
@@ -212,7 +212,7 @@ module Dependabot
212
212
  next unless requirement.is_a?(String)
213
213
 
214
214
  # Skip dependencies using Yarn workspace cross-references as requirements
215
- next if requirement.start_with?("workspace:")
215
+ next if requirement.start_with?("workspace:", "catalog:")
216
216
 
217
217
  requirement = "*" if requirement == ""
218
218
  dep = build_dependency(
@@ -18,6 +18,10 @@ module Dependabot
18
18
  @dependency_files = dependency_files
19
19
  @repo_contents_path = repo_contents_path
20
20
  @credentials = credentials
21
+ @error_handler = PnpmErrorHandler.new(
22
+ dependencies: dependencies,
23
+ dependency_files: dependency_files
24
+ )
21
25
  end
22
26
 
23
27
  def updated_pnpm_lock_content(pnpm_lock)
@@ -36,6 +40,7 @@ module Dependabot
36
40
  attr_reader :dependency_files
37
41
  attr_reader :repo_contents_path
38
42
  attr_reader :credentials
43
+ attr_reader :error_handler
39
44
 
40
45
  IRRESOLVABLE_PACKAGE = "ERR_PNPM_NO_MATCHING_VERSION"
41
46
  INVALID_REQUIREMENT = "ERR_PNPM_SPEC_NOT_SUPPORTED_BY_ANY_RESOLVER"
@@ -46,12 +51,12 @@ module Dependabot
46
51
  UNAUTHORIZED_PACKAGE = /ERR_PNPM_FETCH_401[ [^:print:]]+GET (?<dependency_url>.*): Unauthorized - 401/
47
52
 
48
53
  # ERR_PNPM_FETCH ERROR CODES
49
- ERR_PNPM_FETCH_401 = /ERR_PNPM_FETCH_401.*GET (?<dependency_url>.*): - 401/
50
- ERR_PNPM_FETCH_403 = /ERR_PNPM_FETCH_403.*GET (?<dependency_url>.*): - 403/
51
- ERR_PNPM_FETCH_404 = /ERR_PNPM_FETCH_404.*GET (?<dependency_url>.*): - 404/
52
- ERR_PNPM_FETCH_500 = /ERR_PNPM_FETCH_500.*GET (?<dependency_url>.*): - 500/
53
- ERR_PNPM_FETCH_502 = /ERR_PNPM_FETCH_502.*GET (?<dependency_url>.*): - 502/
54
- ERR_PNPM_FETCH_503 = /ERR_PNPM_FETCH_503.*GET (?<dependency_url>.*): - 503/
54
+ ERR_PNPM_FETCH_401 = /ERR_PNPM_FETCH_401.*GET (?<dependency_url>.*):/
55
+ ERR_PNPM_FETCH_403 = /ERR_PNPM_FETCH_403.*GET (?<dependency_url>.*):/
56
+ ERR_PNPM_FETCH_404 = /ERR_PNPM_FETCH_404.*GET (?<dependency_url>.*):/
57
+ ERR_PNPM_FETCH_500 = /ERR_PNPM_FETCH_500.*GET (?<dependency_url>.*):/
58
+ ERR_PNPM_FETCH_502 = /ERR_PNPM_FETCH_502.*GET (?<dependency_url>.*):/
59
+ ERR_PNPM_FETCH_503 = /ERR_PNPM_FETCH_503.*GET (?<dependency_url>.*):/
55
60
 
56
61
  # ERR_PNPM_UNSUPPORTED_ENGINE
57
62
  ERR_PNPM_UNSUPPORTED_ENGINE = /ERR_PNPM_UNSUPPORTED_ENGINE/
@@ -100,7 +105,7 @@ module Dependabot
100
105
  File.write(".npmrc", npmrc_content(pnpm_lock))
101
106
 
102
107
  SharedHelpers.with_git_configured(credentials: credentials) do
103
- run_pnpm_updater
108
+ run_pnpm_update_packages
104
109
 
105
110
  write_final_package_json_files
106
111
 
@@ -111,15 +116,22 @@ module Dependabot
111
116
  end
112
117
  end
113
118
 
114
- def run_pnpm_updater
119
+ def run_pnpm_update_packages
115
120
  dependency_updates = dependencies.map do |d|
116
121
  "#{d.name}@#{d.version}"
117
122
  end.join(" ")
118
123
 
119
- Helpers.run_pnpm_command(
120
- "install #{dependency_updates} --lockfile-only --ignore-workspace-root-check",
121
- fingerprint: "install <dependency_updates> --lockfile-only --ignore-workspace-root-check"
122
- )
124
+ if Dependabot::Experiments.enabled?(:enable_fix_for_pnpm_no_change_error)
125
+ Helpers.run_pnpm_command(
126
+ "update #{dependency_updates} --lockfile-only --no-save -r",
127
+ fingerprint: "update <dependency_updates> --lockfile-only --no-save -r"
128
+ )
129
+ else
130
+ Helpers.run_pnpm_command(
131
+ "install #{dependency_updates} --lockfile-only --ignore-workspace-root-check",
132
+ fingerprint: "install <dependency_updates> --lockfile-only --ignore-workspace-root-check"
133
+ )
134
+ end
123
135
  end
124
136
 
125
137
  def run_pnpm_install
@@ -251,6 +263,8 @@ module Dependabot
251
263
  pnpm_lock)
252
264
  end
253
265
 
266
+ error_handler.handle_pnpm_error(error)
267
+
254
268
  raise
255
269
  end
256
270
  # rubocop:enable Metrics/AbcSize
@@ -360,5 +374,60 @@ module Dependabot
360
374
  end
361
375
  end
362
376
  end
377
+
378
+ class PnpmErrorHandler
379
+ extend T::Sig
380
+
381
+ # remote connection closed
382
+ ECONNRESET_ERROR = /ECONNRESET/
383
+
384
+ # socket hang up error code
385
+ SOCKET_HANG_UP = /socket hang up/
386
+
387
+ # ERR_PNPM_CATALOG_ENTRY_NOT_FOUND_FOR_SPEC error
388
+ ERR_PNPM_CATALOG_ENTRY_NOT_FOUND_FOR_SPEC = /ERR_PNPM_CATALOG_ENTRY_NOT_FOUND_FOR_SPEC/
389
+
390
+ # duplicate package error code
391
+ DUPLICATE_PACKAGE = /Found duplicates/
392
+
393
+ ERR_PNPM_NO_VERSIONS = /ERR_PNPM_NO_VERSIONS/
394
+
395
+ # Initializes the YarnErrorHandler with dependencies and dependency files
396
+ sig do
397
+ params(
398
+ dependencies: T::Array[Dependabot::Dependency],
399
+ dependency_files: T::Array[Dependabot::DependencyFile]
400
+ ).void
401
+ end
402
+ def initialize(dependencies:, dependency_files:)
403
+ @dependencies = dependencies
404
+ @dependency_files = dependency_files
405
+ end
406
+
407
+ private
408
+
409
+ sig { returns(T::Array[Dependabot::Dependency]) }
410
+ attr_reader :dependencies
411
+
412
+ sig { returns(T::Array[Dependabot::DependencyFile]) }
413
+ attr_reader :dependency_files
414
+
415
+ public
416
+
417
+ # Handles errors with specific to yarn error codes
418
+ sig { params(error: SharedHelpers::HelperSubprocessFailed).void }
419
+ def handle_pnpm_error(error)
420
+ if error.message.match?(DUPLICATE_PACKAGE) || error.message.match?(ERR_PNPM_NO_VERSIONS) ||
421
+ error.message.match?(ERR_PNPM_CATALOG_ENTRY_NOT_FOUND_FOR_SPEC)
422
+
423
+ raise DependencyFileNotResolvable, "Error resolving dependency"
424
+ end
425
+
426
+ ## Clean error message from ANSI escape codes
427
+ return unless error.message.match?(ECONNRESET_ERROR) || error.message.match?(SOCKET_HANG_UP)
428
+
429
+ raise InconsistentRegistryResponse, "Inconsistent registry response while resolving dependency"
430
+ end
431
+ end
363
432
  end
364
433
  end
@@ -48,6 +48,7 @@ module Dependabot
48
48
  ]
49
49
  end
50
50
 
51
+ # rubocop:disable Metrics/PerceivedComplexity
51
52
  sig { override.returns(T::Array[DependencyFile]) }
52
53
  def updated_dependency_files
53
54
  updated_files = T.let([], T::Array[DependencyFile])
@@ -56,6 +57,22 @@ module Dependabot
56
57
  updated_files += updated_lockfiles
57
58
 
58
59
  if updated_files.none?
60
+
61
+ if Dependabot::Experiments.enabled?(:enable_fix_for_pnpm_no_change_error)
62
+ # when all dependencies are transitive
63
+ all_transitive = dependencies.none?(&:top_level?)
64
+ # when there is no update in package.json
65
+ no_package_json_update = package_files.empty?
66
+ # handle the no change error for transitive dependency updates
67
+ if pnpm_locks.any? && dependencies.length.positive? && all_transitive && no_package_json_update
68
+ raise ToolFeatureNotSupported.new(
69
+ tool_name: "pnpm",
70
+ tool_type: "package_manager",
71
+ feature: "updating transitive dependencies"
72
+ )
73
+ end
74
+ end
75
+
59
76
  raise NoChangeError.new(
60
77
  message: "No files were updated!",
61
78
  error_context: error_context(updated_files: updated_files)
@@ -72,6 +89,7 @@ module Dependabot
72
89
 
73
90
  vendor_updated_files(updated_files)
74
91
  end
92
+ # rubocop:enable Metrics/PerceivedComplexity
75
93
 
76
94
  private
77
95
 
@@ -40,6 +40,9 @@ module Dependabot
40
40
  YARN_DEFAULT_VERSION = YARN_V3
41
41
  YARN_FALLBACK_VERSION = YARN_V1
42
42
 
43
+ # corepack supported package managers
44
+ SUPPORTED_COREPACK_PACKAGE_MANAGERS = %w(npm yarn pnpm).freeze
45
+
43
46
  # Determines the npm version depends to the feature flag
44
47
  # If the feature flag is enabled, we are going to use the minimum version npm 8
45
48
  # Otherwise, we are going to use old versionining npm 6
@@ -324,8 +327,8 @@ module Dependabot
324
327
  package_manager_run_command(NpmPackageManager::NAME, command, fingerprint: fingerprint)
325
328
  else
326
329
  Dependabot::SharedHelpers.run_shell_command(
327
- "corepack npm #{command}",
328
- fingerprint: "corepack npm #{fingerprint}"
330
+ "npm #{command}",
331
+ fingerprint: "npm #{fingerprint}"
329
332
  )
330
333
  end
331
334
  end
@@ -484,6 +487,8 @@ module Dependabot
484
487
  .returns(String)
485
488
  end
486
489
  def self.package_manager_install(name, version, env: {})
490
+ return "Corepack does not support #{name}" unless corepack_supported_package_manager?(name)
491
+
487
492
  Dependabot::SharedHelpers.run_shell_command(
488
493
  "corepack install #{name}@#{version} --global --cache-only",
489
494
  fingerprint: "corepack install <name>@<version> --global --cache-only",
@@ -494,6 +499,8 @@ module Dependabot
494
499
  # Prepare the package manager for use by using corepack
495
500
  sig { params(name: String, version: String).returns(String) }
496
501
  def self.package_manager_activate(name, version)
502
+ return "Corepack does not support #{name}" unless corepack_supported_package_manager?(name)
503
+
497
504
  Dependabot::SharedHelpers.run_shell_command(
498
505
  "corepack prepare #{name}@#{version} --activate",
499
506
  fingerprint: "corepack prepare <name>@<version> --activate"
@@ -566,6 +573,11 @@ module Dependabot
566
573
  dependency
567
574
  end
568
575
  end
576
+
577
+ sig { params(name: String).returns(T::Boolean) }
578
+ def self.corepack_supported_package_manager?(name)
579
+ SUPPORTED_COREPACK_PACKAGE_MANAGERS.include?(name)
580
+ end
569
581
  end
570
582
  end
571
583
  end
@@ -59,14 +59,16 @@ module Dependabot
59
59
  T.any(
60
60
  T.class_of(Dependabot::NpmAndYarn::NpmPackageManager),
61
61
  T.class_of(Dependabot::NpmAndYarn::YarnPackageManager),
62
- T.class_of(Dependabot::NpmAndYarn::PNPMPackageManager)
62
+ T.class_of(Dependabot::NpmAndYarn::PNPMPackageManager),
63
+ T.class_of(Dependabot::NpmAndYarn::BunPackageManager)
63
64
  )
64
65
  end
65
66
 
66
67
  PACKAGE_MANAGER_CLASSES = T.let({
67
68
  NpmPackageManager::NAME => NpmPackageManager,
68
69
  YarnPackageManager::NAME => YarnPackageManager,
69
- PNPMPackageManager::NAME => PNPMPackageManager
70
+ PNPMPackageManager::NAME => PNPMPackageManager,
71
+ BunPackageManager::NAME => BunPackageManager
70
72
  }.freeze, T::Hash[String, NpmAndYarnPackageManagerClassType])
71
73
 
72
74
  # Error malformed version number string
@@ -80,6 +80,10 @@ module Dependabot
80
80
  # Matches @ followed by x.y.z (digits separated by dots)
81
81
  if (match = version.match(/@(\d+\.\d+\.\d+)/))
82
82
  version = match[1] # Just "4.5.3"
83
+
84
+ # Extract version in case the output contains Corepack verbose data
85
+ elsif version.include?("Corepack")
86
+ version = T.must(T.must(version.tr("\n", " ").match(/(\d+\.\d+\.\d+)/))[-1])
83
87
  end
84
88
  version = version&.gsub(/^v/, "")
85
89
  end
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.293.0
4
+ version: 0.294.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dependabot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-01-16 00:00:00.000000000 Z
11
+ date: 2025-01-23 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.293.0
19
+ version: 0.294.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.293.0
26
+ version: 0.294.0
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: debug
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -354,7 +354,7 @@ licenses:
354
354
  - MIT
355
355
  metadata:
356
356
  bug_tracker_uri: https://github.com/dependabot/dependabot-core/issues
357
- changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.293.0
357
+ changelog_uri: https://github.com/dependabot/dependabot-core/releases/tag/v0.294.0
358
358
  post_install_message:
359
359
  rdoc_options: []
360
360
  require_paths: