bundler 2.4.19 → 2.4.22

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +83 -2
  3. data/README.md +1 -2
  4. data/lib/bundler/build_metadata.rb +3 -3
  5. data/lib/bundler/cli/check.rb +1 -1
  6. data/lib/bundler/cli/gem.rb +4 -3
  7. data/lib/bundler/cli/info.rb +1 -1
  8. data/lib/bundler/cli/install.rb +2 -2
  9. data/lib/bundler/cli/lock.rb +26 -23
  10. data/lib/bundler/cli/open.rb +5 -7
  11. data/lib/bundler/cli/update.rb +1 -0
  12. data/lib/bundler/definition.rb +43 -26
  13. data/lib/bundler/endpoint_specification.rb +1 -1
  14. data/lib/bundler/env.rb +2 -2
  15. data/lib/bundler/errors.rb +15 -0
  16. data/lib/bundler/fetcher/base.rb +2 -2
  17. data/lib/bundler/fetcher/compact_index.rb +1 -5
  18. data/lib/bundler/fetcher/dependency.rb +1 -1
  19. data/lib/bundler/fetcher.rb +31 -30
  20. data/lib/bundler/gem_helpers.rb +7 -0
  21. data/lib/bundler/gem_version_promoter.rb +2 -2
  22. data/lib/bundler/index.rb +62 -31
  23. data/lib/bundler/injector.rb +1 -1
  24. data/lib/bundler/installer/gem_installer.rb +5 -5
  25. data/lib/bundler/installer/parallel_installer.rb +0 -26
  26. data/lib/bundler/installer/standalone.rb +15 -1
  27. data/lib/bundler/lazy_specification.rb +4 -0
  28. data/lib/bundler/lockfile_parser.rb +32 -39
  29. data/lib/bundler/man/bundle-add.1 +1 -1
  30. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  31. data/lib/bundler/man/bundle-cache.1 +1 -1
  32. data/lib/bundler/man/bundle-check.1 +1 -1
  33. data/lib/bundler/man/bundle-clean.1 +1 -1
  34. data/lib/bundler/man/bundle-config.1 +1 -1
  35. data/lib/bundler/man/bundle-console.1 +1 -1
  36. data/lib/bundler/man/bundle-doctor.1 +1 -1
  37. data/lib/bundler/man/bundle-exec.1 +2 -2
  38. data/lib/bundler/man/bundle-exec.1.ronn +2 -3
  39. data/lib/bundler/man/bundle-gem.1 +1 -1
  40. data/lib/bundler/man/bundle-help.1 +1 -1
  41. data/lib/bundler/man/bundle-info.1 +1 -1
  42. data/lib/bundler/man/bundle-init.1 +1 -1
  43. data/lib/bundler/man/bundle-inject.1 +1 -1
  44. data/lib/bundler/man/bundle-install.1 +1 -1
  45. data/lib/bundler/man/bundle-list.1 +1 -1
  46. data/lib/bundler/man/bundle-lock.1 +1 -1
  47. data/lib/bundler/man/bundle-open.1 +1 -1
  48. data/lib/bundler/man/bundle-outdated.1 +1 -1
  49. data/lib/bundler/man/bundle-platform.1 +1 -1
  50. data/lib/bundler/man/bundle-plugin.1 +17 -17
  51. data/lib/bundler/man/bundle-plugin.1.ronn +5 -5
  52. data/lib/bundler/man/bundle-pristine.1 +1 -1
  53. data/lib/bundler/man/bundle-remove.1 +1 -1
  54. data/lib/bundler/man/bundle-show.1 +1 -1
  55. data/lib/bundler/man/bundle-update.1 +1 -1
  56. data/lib/bundler/man/bundle-version.1 +1 -1
  57. data/lib/bundler/man/bundle-viz.1 +1 -1
  58. data/lib/bundler/man/bundle.1 +1 -1
  59. data/lib/bundler/man/gemfile.5 +12 -1
  60. data/lib/bundler/man/gemfile.5.ronn +5 -0
  61. data/lib/bundler/plugin/index.rb +8 -0
  62. data/lib/bundler/plugin.rb +10 -3
  63. data/lib/bundler/resolver/package.rb +5 -0
  64. data/lib/bundler/resolver.rb +45 -10
  65. data/lib/bundler/retry.rb +1 -1
  66. data/lib/bundler/ruby_dsl.rb +23 -2
  67. data/lib/bundler/ruby_version.rb +8 -1
  68. data/lib/bundler/rubygems_ext.rb +3 -4
  69. data/lib/bundler/rubygems_gem_installer.rb +23 -8
  70. data/lib/bundler/self_manager.rb +2 -0
  71. data/lib/bundler/settings.rb +86 -25
  72. data/lib/bundler/shared_helpers.rb +16 -1
  73. data/lib/bundler/source/git/git_proxy.rb +35 -6
  74. data/lib/bundler/source/metadata.rb +1 -1
  75. data/lib/bundler/source/rubygems.rb +22 -25
  76. data/lib/bundler/spec_set.rb +7 -4
  77. data/lib/bundler/stub_specification.rb +4 -2
  78. data/lib/bundler/templates/newgem/Rakefile.tt +6 -2
  79. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +1 -1
  80. data/lib/bundler/templates/newgem/newgem.gemspec.tt +1 -1
  81. data/lib/bundler/ui/shell.rb +1 -1
  82. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +1 -0
  83. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +21 -9
  84. data/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +1 -1
  85. data/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb +3 -2
  86. data/lib/bundler/vendor/thor/lib/thor/actions/directory.rb +1 -1
  87. data/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +1 -1
  88. data/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +8 -10
  89. data/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +15 -4
  90. data/lib/bundler/vendor/thor/lib/thor/actions.rb +15 -15
  91. data/lib/bundler/vendor/thor/lib/thor/base.rb +140 -14
  92. data/lib/bundler/vendor/thor/lib/thor/command.rb +13 -4
  93. data/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +4 -0
  94. data/lib/bundler/vendor/thor/lib/thor/error.rb +16 -25
  95. data/lib/bundler/vendor/thor/lib/thor/group.rb +1 -1
  96. data/lib/bundler/vendor/thor/lib/thor/invocation.rb +1 -1
  97. data/lib/bundler/vendor/thor/lib/thor/nested_context.rb +2 -2
  98. data/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +20 -1
  99. data/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +33 -17
  100. data/lib/bundler/vendor/thor/lib/thor/parser/option.rb +27 -8
  101. data/lib/bundler/vendor/thor/lib/thor/parser/options.rb +44 -6
  102. data/lib/bundler/vendor/thor/lib/thor/rake_compat.rb +2 -2
  103. data/lib/bundler/vendor/thor/lib/thor/runner.rb +40 -30
  104. data/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +26 -150
  105. data/lib/bundler/vendor/thor/lib/thor/shell/color.rb +4 -46
  106. data/lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb +29 -0
  107. data/lib/bundler/vendor/thor/lib/thor/shell/html.rb +3 -45
  108. data/lib/bundler/vendor/thor/lib/thor/shell/lcs_diff.rb +49 -0
  109. data/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb +134 -0
  110. data/lib/bundler/vendor/thor/lib/thor/shell/terminal.rb +42 -0
  111. data/lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb +38 -0
  112. data/lib/bundler/vendor/thor/lib/thor/shell.rb +1 -1
  113. data/lib/bundler/vendor/thor/lib/thor/util.rb +8 -7
  114. data/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  115. data/lib/bundler/vendor/thor/lib/thor.rb +155 -8
  116. data/lib/bundler/version.rb +1 -1
  117. data/lib/bundler/yaml_serializer.rb +12 -8
  118. data/lib/bundler.rb +0 -8
  119. metadata +8 -3
@@ -65,8 +65,15 @@ class Bundler::Thor
65
65
 
66
66
  # Defines the long description of the next command.
67
67
  #
68
+ # Long description is by default indented, line-wrapped and repeated whitespace merged.
69
+ # In order to print long description verbatim, with indentation and spacing exactly
70
+ # as found in the code, use the +wrap+ option
71
+ #
72
+ # long_desc 'your very long description', wrap: false
73
+ #
68
74
  # ==== Parameters
69
75
  # long description<String>
76
+ # options<Hash>
70
77
  #
71
78
  def long_desc(long_description, options = {})
72
79
  if options[:for]
@@ -74,6 +81,7 @@ class Bundler::Thor
74
81
  command.long_description = long_description if long_description
75
82
  else
76
83
  @long_desc = long_description
84
+ @long_desc_wrap = options[:wrap] != false
77
85
  end
78
86
  end
79
87
 
@@ -133,7 +141,7 @@ class Bundler::Thor
133
141
  # # magic
134
142
  # end
135
143
  #
136
- # method_option :foo => :bar, :for => :previous_command
144
+ # method_option :foo, :for => :previous_command
137
145
  #
138
146
  # def next_command
139
147
  # # magic
@@ -153,6 +161,9 @@ class Bundler::Thor
153
161
  # :hide - If you want to hide this option from the help.
154
162
  #
155
163
  def method_option(name, options = {})
164
+ unless [ Symbol, String ].any? { |klass| name.is_a?(klass) }
165
+ raise ArgumentError, "Expected a Symbol or String, got #{name.inspect}"
166
+ end
156
167
  scope = if options[:for]
157
168
  find_and_refresh_command(options[:for]).options
158
169
  else
@@ -163,6 +174,81 @@ class Bundler::Thor
163
174
  end
164
175
  alias_method :option, :method_option
165
176
 
177
+ # Adds and declares option group for exclusive options in the
178
+ # block and arguments. You can declare options as the outside of the block.
179
+ #
180
+ # If :for is given as option, it allows you to change the options from
181
+ # a previous defined command.
182
+ #
183
+ # ==== Parameters
184
+ # Array[Bundler::Thor::Option.name]
185
+ # options<Hash>:: :for is applied for previous defined command.
186
+ #
187
+ # ==== Examples
188
+ #
189
+ # exclusive do
190
+ # option :one
191
+ # option :two
192
+ # end
193
+ #
194
+ # Or
195
+ #
196
+ # option :one
197
+ # option :two
198
+ # exclusive :one, :two
199
+ #
200
+ # If you give "--one" and "--two" at the same time ExclusiveArgumentsError
201
+ # will be raised.
202
+ #
203
+ def method_exclusive(*args, &block)
204
+ register_options_relation_for(:method_options,
205
+ :method_exclusive_option_names, *args, &block)
206
+ end
207
+ alias_method :exclusive, :method_exclusive
208
+
209
+ # Adds and declares option group for required at least one of options in the
210
+ # block of arguments. You can declare options as the outside of the block.
211
+ #
212
+ # If :for is given as option, it allows you to change the options from
213
+ # a previous defined command.
214
+ #
215
+ # ==== Parameters
216
+ # Array[Bundler::Thor::Option.name]
217
+ # options<Hash>:: :for is applied for previous defined command.
218
+ #
219
+ # ==== Examples
220
+ #
221
+ # at_least_one do
222
+ # option :one
223
+ # option :two
224
+ # end
225
+ #
226
+ # Or
227
+ #
228
+ # option :one
229
+ # option :two
230
+ # at_least_one :one, :two
231
+ #
232
+ # If you do not give "--one" and "--two" AtLeastOneRequiredArgumentError
233
+ # will be raised.
234
+ #
235
+ # You can use at_least_one and exclusive at the same time.
236
+ #
237
+ # exclusive do
238
+ # at_least_one do
239
+ # option :one
240
+ # option :two
241
+ # end
242
+ # end
243
+ #
244
+ # Then it is required either only one of "--one" or "--two".
245
+ #
246
+ def method_at_least_one(*args, &block)
247
+ register_options_relation_for(:method_options,
248
+ :method_at_least_one_option_names, *args, &block)
249
+ end
250
+ alias_method :at_least_one, :method_at_least_one
251
+
166
252
  # Prints help information for the given command.
167
253
  #
168
254
  # ==== Parameters
@@ -178,9 +264,16 @@ class Bundler::Thor
178
264
  shell.say " #{banner(command).split("\n").join("\n ")}"
179
265
  shell.say
180
266
  class_options_help(shell, nil => command.options.values)
267
+ print_exclusive_options(shell, command)
268
+ print_at_least_one_required_options(shell, command)
269
+
181
270
  if command.long_description
182
271
  shell.say "Description:"
183
- shell.print_wrapped(command.long_description, :indent => 2)
272
+ if command.wrap_long_description
273
+ shell.print_wrapped(command.long_description, indent: 2)
274
+ else
275
+ shell.say command.long_description
276
+ end
184
277
  else
185
278
  shell.say command.description
186
279
  end
@@ -197,7 +290,7 @@ class Bundler::Thor
197
290
  Bundler::Thor::Util.thor_classes_in(self).each do |klass|
198
291
  list += klass.printable_commands(false)
199
292
  end
200
- list.sort! { |a, b| a[0] <=> b[0] }
293
+ sort_commands!(list)
201
294
 
202
295
  if defined?(@package_name) && @package_name
203
296
  shell.say "#{@package_name} commands:"
@@ -205,9 +298,11 @@ class Bundler::Thor
205
298
  shell.say "Commands:"
206
299
  end
207
300
 
208
- shell.print_table(list, :indent => 2, :truncate => true)
301
+ shell.print_table(list, indent: 2, truncate: true)
209
302
  shell.say
210
303
  class_options_help(shell)
304
+ print_exclusive_options(shell)
305
+ print_at_least_one_required_options(shell)
211
306
  end
212
307
 
213
308
  # Returns commands ready to be printed.
@@ -238,7 +333,7 @@ class Bundler::Thor
238
333
 
239
334
  define_method(subcommand) do |*args|
240
335
  args, opts = Bundler::Thor::Arguments.split(args)
241
- invoke_args = [args, opts, {:invoked_via_subcommand => true, :class_options => options}]
336
+ invoke_args = [args, opts, {invoked_via_subcommand: true, class_options: options}]
242
337
  invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h")
243
338
  invoke subcommand_class, *invoke_args
244
339
  end
@@ -346,6 +441,24 @@ class Bundler::Thor
346
441
 
347
442
  protected
348
443
 
444
+ # Returns this class exclusive options array set.
445
+ #
446
+ # ==== Returns
447
+ # Array[Array[Bundler::Thor::Option.name]]
448
+ #
449
+ def method_exclusive_option_names #:nodoc:
450
+ @method_exclusive_option_names ||= []
451
+ end
452
+
453
+ # Returns this class at least one of required options array set.
454
+ #
455
+ # ==== Returns
456
+ # Array[Array[Bundler::Thor::Option.name]]
457
+ #
458
+ def method_at_least_one_option_names #:nodoc:
459
+ @method_at_least_one_option_names ||= []
460
+ end
461
+
349
462
  def stop_on_unknown_option #:nodoc:
350
463
  @stop_on_unknown_option ||= []
351
464
  end
@@ -355,8 +468,30 @@ class Bundler::Thor
355
468
  @disable_required_check ||= [:help]
356
469
  end
357
470
 
471
+ def print_exclusive_options(shell, command = nil) # :nodoc:
472
+ opts = []
473
+ opts = command.method_exclusive_option_names unless command.nil?
474
+ opts += class_exclusive_option_names
475
+ unless opts.empty?
476
+ shell.say "Exclusive Options:"
477
+ shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
478
+ shell.say
479
+ end
480
+ end
481
+
482
+ def print_at_least_one_required_options(shell, command = nil) # :nodoc:
483
+ opts = []
484
+ opts = command.method_at_least_one_option_names unless command.nil?
485
+ opts += class_at_least_one_option_names
486
+ unless opts.empty?
487
+ shell.say "Required At Least One:"
488
+ shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
489
+ shell.say
490
+ end
491
+ end
492
+
358
493
  # The method responsible for dispatching given the args.
359
- def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength
494
+ def dispatch(meth, given_args, given_opts, config) #:nodoc:
360
495
  meth ||= retrieve_command_name(given_args)
361
496
  command = all_commands[normalize_command_name(meth)]
362
497
 
@@ -415,12 +550,16 @@ class Bundler::Thor
415
550
  @usage ||= nil
416
551
  @desc ||= nil
417
552
  @long_desc ||= nil
553
+ @long_desc_wrap ||= nil
418
554
  @hide ||= nil
419
555
 
420
556
  if @usage && @desc
421
557
  base_class = @hide ? Bundler::Thor::HiddenCommand : Bundler::Thor::Command
422
- commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
423
- @usage, @desc, @long_desc, @method_options, @hide = nil
558
+ relations = {exclusive_option_names: method_exclusive_option_names,
559
+ at_least_one_option_names: method_at_least_one_option_names}
560
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @long_desc_wrap, @usage, method_options, relations)
561
+ @usage, @desc, @long_desc, @long_desc_wrap, @method_options, @hide = nil
562
+ @method_exclusive_option_names, @method_at_least_one_option_names = nil
424
563
  true
425
564
  elsif all_commands[meth] || meth == "method_missing"
426
565
  true
@@ -495,6 +634,14 @@ class Bundler::Thor
495
634
  "
496
635
  end
497
636
  alias_method :subtask_help, :subcommand_help
637
+
638
+ # Sort the commands, lexicographically by default.
639
+ #
640
+ # Can be overridden in the subclass to change the display order of the
641
+ # commands.
642
+ def sort_commands!(list)
643
+ list.sort! { |a, b| a[0] <=> b[0] }
644
+ end
498
645
  end
499
646
 
500
647
  include Bundler::Thor::Base
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  module Bundler
4
- VERSION = "2.4.19".freeze
4
+ VERSION = "2.4.22".freeze
5
5
 
6
6
  def self.bundler_major_version
7
7
  @bundler_major_version ||= VERSION.split(".").first.to_i
@@ -17,7 +17,11 @@ module Bundler
17
17
  if v.is_a?(Hash)
18
18
  yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines
19
19
  elsif v.is_a?(Array) # Expected to be array of strings
20
- yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
20
+ if v.empty?
21
+ yaml << " []\n"
22
+ else
23
+ yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
24
+ end
21
25
  else
22
26
  yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n"
23
27
  end
@@ -54,8 +58,8 @@ module Bundler
54
58
  str.split(/\r?\n/).each do |line|
55
59
  if match = HASH_REGEX.match(line)
56
60
  indent, key, quote, val = match.captures
57
- key = convert_to_backward_compatible_key(key)
58
- depth = indent.scan(/ /).length
61
+ convert_to_backward_compatible_key!(key)
62
+ depth = indent.size / 2
59
63
  if quote.empty? && val.empty?
60
64
  new_hash = {}
61
65
  stack[depth][key] = new_hash
@@ -63,6 +67,7 @@ module Bundler
63
67
  last_empty_key = key
64
68
  last_hash = stack[depth]
65
69
  else
70
+ val = [] if val == "[]" # empty array
66
71
  stack[depth][key] = val
67
72
  end
68
73
  elsif match = ARRAY_REGEX.match(line)
@@ -76,14 +81,13 @@ module Bundler
76
81
  end
77
82
 
78
83
  # for settings' keys
79
- def convert_to_backward_compatible_key(key)
80
- key = "#{key}/" if key =~ /https?:/i && key !~ %r{/\Z}
81
- key = key.gsub(".", "__") if key.include?(".")
82
- key
84
+ def convert_to_backward_compatible_key!(key)
85
+ key << "/" if /https?:/i.match?(key) && !%r{/\Z}.match?(key)
86
+ key.gsub!(".", "__")
83
87
  end
84
88
 
85
89
  class << self
86
- private :dump_hash, :convert_to_backward_compatible_key
90
+ private :dump_hash, :convert_to_backward_compatible_key!
87
91
  end
88
92
  end
89
93
  end
data/lib/bundler.rb CHANGED
@@ -330,14 +330,6 @@ module Bundler
330
330
 
331
331
  def rm_rf(path)
332
332
  FileUtils.remove_entry_secure(path) if path && File.exist?(path)
333
- rescue ArgumentError
334
- message = <<EOF
335
- It is a security vulnerability to allow your home directory to be world-writable, and bundler cannot continue.
336
- You should probably consider fixing this issue by running `chmod o-w ~` on *nix.
337
- Please refer to https://ruby-doc.org/stdlib-3.1.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-remove_entry_secure for details.
338
- EOF
339
- File.world_writable?(path) ? Bundler.ui.warn(message) : raise
340
- raise PathError, "Please fix the world-writable issue with your #{path} directory"
341
333
  end
342
334
 
343
335
  def settings
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.19
4
+ version: 2.4.22
5
5
  platform: ruby
6
6
  authors:
7
7
  - André Arko
@@ -22,7 +22,7 @@ authors:
22
22
  autorequire:
23
23
  bindir: exe
24
24
  cert_chain: []
25
- date: 2023-08-17 00:00:00.000000000 Z
25
+ date: 2023-11-09 00:00:00.000000000 Z
26
26
  dependencies: []
27
27
  description: Bundler manages an application's dependencies through its entire life,
28
28
  across many machines, systematically and repeatably
@@ -327,7 +327,12 @@ files:
327
327
  - lib/bundler/vendor/thor/lib/thor/shell.rb
328
328
  - lib/bundler/vendor/thor/lib/thor/shell/basic.rb
329
329
  - lib/bundler/vendor/thor/lib/thor/shell/color.rb
330
+ - lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb
330
331
  - lib/bundler/vendor/thor/lib/thor/shell/html.rb
332
+ - lib/bundler/vendor/thor/lib/thor/shell/lcs_diff.rb
333
+ - lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb
334
+ - lib/bundler/vendor/thor/lib/thor/shell/terminal.rb
335
+ - lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb
331
336
  - lib/bundler/vendor/thor/lib/thor/util.rb
332
337
  - lib/bundler/vendor/thor/lib/thor/version.rb
333
338
  - lib/bundler/vendor/tsort/LICENSE.txt
@@ -381,7 +386,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
381
386
  - !ruby/object:Gem::Version
382
387
  version: 3.0.1
383
388
  requirements: []
384
- rubygems_version: 3.4.19
389
+ rubygems_version: 3.4.22
385
390
  signing_key:
386
391
  specification_version: 4
387
392
  summary: The best way to manage your application's dependencies