test-kitchen 2.5.4 → 2.8.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: ba11941e2fb1db16f6bdb83f86c9822ad222f18f0e26e37a94683fb6fda29042
4
- data.tar.gz: 57b12bd55f5b39b0be4fd482dc22666fb62eeb7182a44199b7aadcd90857330f
3
+ metadata.gz: b776d094e27dc25c3f569ad96100866c9015d60593d9d99b54e30b8b6b0e4b03
4
+ data.tar.gz: 598635116f83455b7852cee81a77efc907f6ea2a9c52f8312526b9a7e6ca0922
5
5
  SHA512:
6
- metadata.gz: '095582d89c5645bbace34075c30b95170f9c0d5a5a06067c58e7b348bf4d711d5a068101940b0b035ad371f213eaebef70a695d620aa230fafc4ca86828005f4'
7
- data.tar.gz: 7b2c76fcea81d87b976745081682122ed7dec1d63ffba2d99180913871c595c7e17adc511223a996a0e25b277f8e782ec8cd1623479a93d79092eda0ce5a3d03
6
+ metadata.gz: ae5d8636e834c68d3565a73b9cb5a3af46246fb9b2427a80166716366cd254947049667a80a23c569f1f9eda26eb28bac4bc50fbb8eceaf55fa54cf5548a6554
7
+ data.tar.gz: d91650528d01dcac17ad882cfd260d41b2d7c1ce3118aa0a8ddecfafd935ed1b237cf5507067a512ef5fe7dc003e23d57983f5f5f5cde994e5766a02385ea8af
data/Rakefile CHANGED
@@ -42,7 +42,7 @@ desc "Run all quality tasks"
42
42
  task quality: %i{style stats}
43
43
 
44
44
  begin
45
- require "yard"
45
+ require "yard" unless defined?(YARD)
46
46
  YARD::Rake::YardocTask.new
47
47
  rescue LoadError
48
48
  puts "yard is not available. (sudo) gem install yard to generate yard documentation."
@@ -4,7 +4,7 @@
4
4
  Signal.trap("INT") { exit 1 }
5
5
 
6
6
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), %w{.. lib})
7
- require "rubygems"
7
+ require "rubygems" unless defined?(Gem)
8
8
  require "kitchen/cli"
9
9
  require "kitchen/errors"
10
10
 
@@ -15,9 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "pathname"
19
- require "thread"
20
-
18
+ require "pathname" unless defined?(Pathname)
21
19
  require_relative "kitchen/errors"
22
20
  require_relative "kitchen/logger"
23
21
  require_relative "kitchen/logging"
@@ -67,7 +65,7 @@ module Kitchen
67
65
  #
68
66
  # @return [Pathname] root path of gem
69
67
  def source_root
70
- @source_root ||= Pathname.new(File.expand_path("../../", __FILE__))
68
+ @source_root ||= Pathname.new(File.expand_path("..", __dir__))
71
69
  end
72
70
 
73
71
  # Returns a default logger which emits on standard output.
@@ -15,7 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "thor"
18
+ # CI tests fail without an explicit unconditional require of Thor
19
+ require "thor" # rubocop:disable ChefRuby/UnlessDefinedRequire
19
20
 
20
21
  require_relative "../kitchen"
21
22
  require_relative "generator/init"
@@ -15,8 +15,6 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "thread"
19
-
20
18
  module Kitchen
21
19
  module Command
22
20
  # Base class for CLI commands.
@@ -17,7 +17,7 @@
17
17
 
18
18
  require_relative "../command"
19
19
 
20
- require "benchmark"
20
+ require "benchmark" unless defined?(Benchmark)
21
21
 
22
22
  module Kitchen
23
23
  module Command
@@ -18,7 +18,7 @@
18
18
  require_relative "../command"
19
19
  require_relative "../diagnostic"
20
20
 
21
- require "yaml"
21
+ autoload :YAML, "yaml"
22
22
 
23
23
  module Kitchen
24
24
  module Command
@@ -32,9 +32,9 @@ module Kitchen
32
32
 
33
33
  loader = record_failure { load_loader }
34
34
 
35
- puts Kitchen::Diagnostic.new(
35
+ puts YAML.dump(Kitchen::Diagnostic.new(
36
36
  loader: loader, instances: instances, plugins: plugins?
37
- ).read.to_yaml
37
+ ).read)
38
38
  end
39
39
 
40
40
  private
@@ -16,7 +16,7 @@
16
16
  # limitations under the License.
17
17
 
18
18
  require_relative "../command"
19
- require "json"
19
+ require "json" unless defined?(JSON)
20
20
 
21
21
  module Kitchen
22
22
  module Command
@@ -17,7 +17,7 @@
17
17
 
18
18
  require_relative "../command"
19
19
 
20
- require "benchmark"
20
+ require "benchmark" unless defined?(Benchmark)
21
21
 
22
22
  module Kitchen
23
23
  module Command
@@ -213,7 +213,7 @@ module Kitchen
213
213
  provisioner: Provisioner::DEFAULT_PLUGIN,
214
214
  verifier: Verifier::DEFAULT_PLUGIN,
215
215
  transport: lambda do |_suite, platform|
216
- platform =~ /^win/i ? "winrm" : Transport::DEFAULT_PLUGIN
216
+ /^win/i.match?(platform) ? "winrm" : Transport::DEFAULT_PLUGIN
217
217
  end,
218
218
  },
219
219
  kitchen_root: kitchen_root,
@@ -19,6 +19,7 @@ require_relative "../configurable"
19
19
  require_relative "../errors"
20
20
  require_relative "../lazy_hash"
21
21
  require_relative "../logging"
22
+ require_relative "../plugin_base"
22
23
  require_relative "../shell_out"
23
24
 
24
25
  module Kitchen
@@ -26,7 +27,7 @@ module Kitchen
26
27
  # Base class for a driver.
27
28
  #
28
29
  # @author Fletcher Nichol <fnichol@nichol.ca>
29
- class Base
30
+ class Base < Kitchen::Plugin::Base
30
31
  include Configurable
31
32
  include Logging
32
33
  include ShellOut
@@ -69,43 +70,6 @@ module Kitchen
69
70
  false
70
71
  end
71
72
 
72
- class << self
73
- # @return [Array<Symbol>] an array of action method names that cannot
74
- # be run concurrently and must be run in serial via a shared mutex
75
- attr_reader :serial_actions
76
- end
77
-
78
- # Registers certain driver actions that cannot be safely run concurrently
79
- # in threads across multiple instances. Typically this might be used
80
- # for create or destroy actions that use an underlying resource that
81
- # cannot be used at the same time.
82
- #
83
- # A shared mutex for this driver object will be used to synchronize all
84
- # registered methods.
85
- #
86
- # @example a single action method that cannot be run concurrently
87
- #
88
- # no_parallel_for :create
89
- #
90
- # @example multiple action methods that cannot be run concurrently
91
- #
92
- # no_parallel_for :create, :destroy
93
- #
94
- # @param methods [Array<Symbol>] one or more actions as symbols
95
- # @raise [ClientError] if any method is not a valid action method name
96
- def self.no_parallel_for(*methods)
97
- action_methods = %i{create setup converge verify destroy}
98
-
99
- Array(methods).each do |meth|
100
- next if action_methods.include?(meth)
101
-
102
- raise ClientError, "##{meth} is not a valid no_parallel_for method"
103
- end
104
-
105
- @serial_actions ||= []
106
- @serial_actions += methods
107
- end
108
-
109
73
  # Sets the API version for this driver. If the driver does not set this
110
74
  # value, then `nil` will be used and reported.
111
75
  #
@@ -18,7 +18,8 @@
18
18
  require "thor/util"
19
19
 
20
20
  require_relative "../lazy_hash"
21
- require "benchmark"
21
+ require_relative "../plugin_base"
22
+ require "benchmark" unless defined?(Benchmark)
22
23
 
23
24
  module Kitchen
24
25
  module Driver
@@ -42,7 +43,7 @@ module Kitchen
42
43
  # Transport, and Verifier subsystems may not be picked up in these
43
44
  # Drivers. When legacy Driver::SSHBase support is removed, this class
44
45
  # will no longer be available.
45
- class SSHBase
46
+ class SSHBase < Kitchen::Plugin::Base
46
47
  include ShellOut
47
48
  include Configurable
48
49
  include Logging
@@ -179,43 +180,6 @@ module Kitchen
179
180
  # documented dependency is missing from the system
180
181
  def verify_dependencies; end
181
182
 
182
- class << self
183
- # @return [Array<Symbol>] an array of action method names that cannot
184
- # be run concurrently and must be run in serial via a shared mutex
185
- attr_reader :serial_actions
186
- end
187
-
188
- # Registers certain driver actions that cannot be safely run concurrently
189
- # in threads across multiple instances. Typically this might be used
190
- # for create or destroy actions that use an underlying resource that
191
- # cannot be used at the same time.
192
- #
193
- # A shared mutex for this driver object will be used to synchronize all
194
- # registered methods.
195
- #
196
- # @example a single action method that cannot be run concurrently
197
- #
198
- # no_parallel_for :create
199
- #
200
- # @example multiple action methods that cannot be run concurrently
201
- #
202
- # no_parallel_for :create, :destroy
203
- #
204
- # @param methods [Array<Symbol>] one or more actions as symbols
205
- # @raise [ClientError] if any method is not a valid action method name
206
- def self.no_parallel_for(*methods)
207
- action_methods = %i{create converge setup verify destroy}
208
-
209
- Array(methods).each do |meth|
210
- next if action_methods.include?(meth)
211
-
212
- raise ClientError, "##{meth} is not a valid no_parallel_for method"
213
- end
214
-
215
- @serial_actions ||= []
216
- @serial_actions += methods
217
- end
218
-
219
183
  # Cache directory that a driver could implement to inform the provisioner
220
184
  # that it can leverage it internally
221
185
  #
@@ -15,8 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "benchmark"
19
- require "fileutils"
18
+ require "benchmark" unless defined?(Benchmark)
19
+ require "fileutils" unless defined?(FileUtils)
20
20
 
21
21
  module Kitchen
22
22
  # An instance of a suite running on a platform. A created instance may be a
@@ -28,7 +28,7 @@ module Kitchen
28
28
  include Logging
29
29
 
30
30
  class << self
31
- # @return [Hash] a hash of mutxes, arranged by Driver class names
31
+ # @return [Hash] a hash of mutexes, arranged by Plugin class names
32
32
  # @api private
33
33
  attr_accessor :mutexes
34
34
 
@@ -322,21 +322,29 @@ module Kitchen
322
322
  end
323
323
  end
324
324
 
325
- # Perform any final configuration or preparation needed for the driver
326
- # object carry out its duties.
325
+ # If a plugin has declared via .no_parallel_for that it is not
326
+ # thread-safe for certain actions, create a mutex to track it.
327
327
  #
328
+ # @param plugin_class[Class] Kitchen::Plugin::Base
328
329
  # @api private
329
- def setup_driver
330
- @driver.finalize_config!(self)
331
-
332
- if driver.class.serial_actions
330
+ def setup_plugin_mutexes(plugin_class)
331
+ if plugin_class.serial_actions
333
332
  Kitchen.mutex.synchronize do
334
333
  self.class.mutexes ||= {}
335
- self.class.mutexes[driver.class] = Mutex.new
334
+ self.class.mutexes[plugin_class] = Mutex.new
336
335
  end
337
336
  end
338
337
  end
339
338
 
339
+ # Perform any final configuration or preparation needed for the driver
340
+ # object carry out its duties.
341
+ #
342
+ # @api private
343
+ def setup_driver
344
+ @driver.finalize_config!(self)
345
+ setup_plugin_mutexes(driver.class)
346
+ end
347
+
340
348
  # Perform any final configuration or preparation needed for the lifecycle hooks
341
349
  # object carry out its duties.
342
350
  #
@@ -351,6 +359,7 @@ module Kitchen
351
359
  # @api private
352
360
  def setup_provisioner
353
361
  @provisioner.finalize_config!(self)
362
+ setup_plugin_mutexes(provisioner.class)
354
363
  end
355
364
 
356
365
  # Perform any final configuration or preparation needed for the transport
@@ -359,6 +368,7 @@ module Kitchen
359
368
  # @api private
360
369
  def setup_transport
361
370
  transport.finalize_config!(self)
371
+ setup_plugin_mutexes(transport.class)
362
372
  end
363
373
 
364
374
  # Perform any final configuration or preparation needed for the verifier
@@ -367,6 +377,7 @@ module Kitchen
367
377
  # @api private
368
378
  def setup_verifier
369
379
  verifier.finalize_config!(self)
380
+ setup_plugin_mutexes(verifier.class)
370
381
  end
371
382
 
372
383
  # Perform all actions in order from last state to desired state.
@@ -541,10 +552,11 @@ module Kitchen
541
552
  # @param block [Proc] a block to be called
542
553
  # @api private
543
554
  def synchronize_or_call(what, state)
544
- if Array(driver.class.serial_actions).include?(what)
545
- debug("#{to_str} is synchronizing on #{driver.class}##{what}")
546
- self.class.mutexes[driver.class].synchronize do
547
- debug("#{to_str} is messaging #{driver.class}##{what}")
555
+ plugin_class = plugin_class_for_action(what)
556
+ if Array(plugin_class.serial_actions).include?(what)
557
+ debug("#{to_str} is synchronizing on #{plugin_class}##{what}")
558
+ self.class.mutexes[plugin_class].synchronize do
559
+ debug("#{to_str} is messaging #{plugin_class}##{what}")
548
560
  yield(state)
549
561
  end
550
562
  else
@@ -552,6 +564,21 @@ module Kitchen
552
564
  end
553
565
  end
554
566
 
567
+ # Maps the given action to the plugin class associated with the action
568
+ #
569
+ # @param what[Symbol] action
570
+ # @return [Class] Kitchen::Plugin::Base
571
+ # @api private
572
+ def plugin_class_for_action(what)
573
+ {
574
+ create: driver,
575
+ setup: transport,
576
+ converge: provisioner,
577
+ verify: verifier,
578
+ destroy: driver,
579
+ }[what].class
580
+ end
581
+
555
582
  # Writes a high level message for logging and/or output.
556
583
  #
557
584
  # In this case, all instance banner messages will be written to the common
@@ -15,9 +15,9 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "erb"
18
+ require "erb" unless defined?(Erb)
19
19
  require_relative "../../vendor/hash_recursive_merge"
20
- require "yaml"
20
+ require "yaml" unless defined?(YAML)
21
21
 
22
22
  module Kitchen
23
23
  module Loader
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "fileutils"
18
+ require "fileutils" unless defined?(FileUtils)
19
19
  require "logger"
20
20
 
21
21
  module Kitchen
@@ -0,0 +1,60 @@
1
+ #
2
+ # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
+ #
4
+ # Copyright (C) 2014, Fletcher Nichol
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ module Kitchen
19
+ module Plugin
20
+ class Base
21
+ class << self
22
+ # @return [Array<Symbol>] an array of action method names that cannot
23
+ # be run concurrently and must be run in serial via a shared mutex
24
+ attr_reader :serial_actions
25
+ end
26
+
27
+ # Registers certain driver actions that cannot be safely run concurrently
28
+ # in threads across multiple instances. Typically this might be used
29
+ # for create or destroy actions that use an underlying resource that
30
+ # cannot be used at the same time.
31
+ #
32
+ # A shared mutex for this driver object will be used to synchronize all
33
+ # registered methods.
34
+ #
35
+ # @example a single action method that cannot be run concurrently
36
+ #
37
+ # no_parallel_for :create
38
+ #
39
+ # @example multiple action methods that cannot be run concurrently
40
+ #
41
+ # no_parallel_for :create, :destroy
42
+ #
43
+ # @param methods [Array<Symbol>] one or more actions as symbols
44
+ # @raise [ClientError] if any method is not a valid action method name
45
+ def self.no_parallel_for(*methods)
46
+ action_methods = %i{create setup converge verify destroy}
47
+
48
+ Array(methods).each do |meth|
49
+ next if action_methods.include?(meth)
50
+
51
+ raise ClientError, "##{meth} is not a valid no_parallel_for method"
52
+ end
53
+
54
+ @serial_actions ||= []
55
+ @serial_actions += methods
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -18,13 +18,14 @@
18
18
  require_relative "../configurable"
19
19
  require_relative "../errors"
20
20
  require_relative "../logging"
21
+ require_relative "../plugin_base"
21
22
 
22
23
  module Kitchen
23
24
  module Provisioner
24
25
  # Base class for a provisioner.
25
26
  #
26
27
  # @author Fletcher Nichol <fnichol@nichol.ca>
27
- class Base
28
+ class Base < Kitchen::Plugin::Base
28
29
  include Configurable
29
30
  include Logging
30
31
 
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "json"
18
+ require "json" unless defined?(JSON)
19
19
 
20
20
  module Kitchen
21
21
  module Provisioner
@@ -15,8 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "shellwords"
19
- require "rbconfig"
18
+ require "shellwords" unless defined?(Shellwords)
19
+ require "rbconfig" unless defined?(RbConfig)
20
20
 
21
21
  require_relative "../../errors"
22
22
  require_relative "../../logging"
@@ -110,13 +110,13 @@ module Kitchen
110
110
  # @return [String]
111
111
  # @api private
112
112
  def escape_path(path)
113
- if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
113
+ if /mswin|mingw/.match?(RbConfig::CONFIG["host_os"])
114
114
  # I know what you're thinking: "just use Shellwords.escape". That
115
115
  # method produces incorrect results on Windows with certain input
116
116
  # which would be a metacharacter in Sh but is not for one or more of
117
117
  # Windows command line parsing libraries. This covers the 99% case of
118
118
  # spaces in the path without breaking other stuff.
119
- if path =~ /[ \t\n\v"]/
119
+ if /[ \t\n\v"]/.match?(path)
120
120
  "\"#{path.gsub(/[ \t\n\v\"\\]/) { |m| '\\' + m[0] }}\""
121
121
  else
122
122
  path
@@ -136,7 +136,7 @@ module Kitchen
136
136
  # @api private
137
137
  def detect_chef_command!(logger)
138
138
  unless ENV["PATH"].split(File::PATH_SEPARATOR).any? do |path|
139
- if RbConfig::CONFIG["host_os"] =~ /mswin|mingw/
139
+ if /mswin|mingw/.match?(RbConfig::CONFIG["host_os"])
140
140
  # Windows could have different extentions: BAT, EXE or NONE
141
141
  %w{chef chef.exe chef.bat}.each do |bin|
142
142
  File.exist?(File.join(path, bin))
@@ -15,18 +15,18 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "fileutils"
19
- require "pathname"
20
- require "json"
21
- require "cgi"
18
+ require "fileutils" unless defined?(FileUtils)
19
+ require "pathname" unless defined?(Pathname)
20
+ require "json" unless defined?(JSON)
21
+ require "cgi" unless defined?(CGI)
22
22
 
23
23
  require_relative "chef/policyfile"
24
24
  require_relative "chef/berkshelf"
25
25
  require_relative "chef/common_sandbox"
26
26
  require_relative "../util"
27
- require "mixlib/install"
28
- require "mixlib/install/script_generator"
29
- require "license_acceptance/acceptor"
27
+ module LicenseAcceptance
28
+ autoload :Acceptor, "license_acceptance/acceptor"
29
+ end
30
30
 
31
31
  begin
32
32
  require "chef-config/config"
@@ -156,7 +156,7 @@ module Kitchen
156
156
  product_name: <chef or chef-workstation>
157
157
  install_strategy: skip
158
158
  MSG
159
- when provisioner[:require_chef_omnibus].to_s.match(/\d/)
159
+ when provisioner[:require_chef_omnibus].to_s.match?(/\d/)
160
160
  Util.outdent!(<<-MSG)
161
161
  The 'require_chef_omnibus' attribute with version values will change
162
162
  to use the new 'product_version' attribute.
@@ -328,7 +328,7 @@ module Kitchen
328
328
  return unless config[:require_chef_omnibus] || config[:product_name]
329
329
  return if config[:product_name] && config[:install_strategy] == "skip"
330
330
 
331
- prefix_command(sudo(install_script_contents))
331
+ prefix_command(install_script_contents)
332
332
  end
333
333
 
334
334
  private
@@ -503,6 +503,7 @@ module Kitchen
503
503
  # @return [String] contents of product based install script
504
504
  # @api private
505
505
  def script_for_product
506
+ require "mixlib/install"
506
507
  installer = Mixlib::Install.new({
507
508
  product_name: config[:product_name],
508
509
  product_version: config[:product_version],
@@ -516,6 +517,12 @@ module Kitchen
516
517
  opts[key] = config[key] if config[key]
517
518
  end
518
519
 
520
+ unless windows_os?
521
+ # omnitruck installer does not currently support a tmp dir option on windows
522
+ opts[:install_command_options][:tmp_dir] = config[:root_path]
523
+ opts[:install_command_options]["TMPDIR"] = config[:root_path]
524
+ end
525
+
519
526
  if config[:download_url]
520
527
  opts[:install_command_options][:download_url_override] = config[:download_url]
521
528
  opts[:install_command_options][:checksum] = config[:checksum] if config[:checksum]
@@ -534,7 +541,6 @@ module Kitchen
534
541
  # install.ps1 only supports http_proxy
535
542
  prox.delete_if { |p| %i{https_proxy ftp_proxy no_proxy}.include?(p) } if powershell_shell?
536
543
  end
537
-
538
544
  opts[:install_command_options].merge!(proxies)
539
545
  end)
540
546
  config[:chef_omnibus_root] = installer.root
@@ -553,8 +559,14 @@ module Kitchen
553
559
  end
554
560
 
555
561
  def install_from_file(command)
556
- install_file = "/tmp/chef-installer.sh"
557
- script = ["cat > #{install_file} <<\"EOL\""]
562
+ install_file = "#{config[:root_path]}/chef-installer.sh"
563
+ script = []
564
+ script << "mkdir -p #{config[:root_path]}"
565
+ script << "if [ $? -ne 0 ]; then"
566
+ script << " echo Kitchen config setting root_path: '#{config[:root_path]}' not creatable by regular user "
567
+ script << " exit 1"
568
+ script << "fi"
569
+ script << "cat > #{install_file} <<\"EOL\""
558
570
  script << command
559
571
  script << "EOL"
560
572
  script << "chmod +x #{install_file}"
@@ -565,11 +577,12 @@ module Kitchen
565
577
  # @return [String] contents of version based install script
566
578
  # @api private
567
579
  def script_for_omnibus_version
580
+ require "mixlib/install/script_generator"
568
581
  installer = Mixlib::Install::ScriptGenerator.new(
569
582
  config[:require_chef_omnibus], powershell_shell?, install_options
570
583
  )
571
584
  config[:chef_omnibus_root] = installer.root
572
- installer.install_command
585
+ sudo(installer.install_command)
573
586
  end
574
587
 
575
588
  # Hook used in subclasses to indicate support for policyfiles.
@@ -27,6 +27,10 @@ module Kitchen
27
27
 
28
28
  plugin_version Kitchen::VERSION
29
29
 
30
+ # ChefSolo is dependent on Berkshelf, which is not thread-safe.
31
+ # See discussion on https://github.com/test-kitchen/test-kitchen/issues/1307
32
+ no_parallel_for :converge
33
+
30
34
  default_config :solo_rb, {}
31
35
 
32
36
  default_config :chef_solo_path do |provisioner|
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "shellwords"
18
+ require "shellwords" unless defined?(Shellwords)
19
19
 
20
20
  require_relative "base"
21
21
  require_relative "../version"
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "mixlib/shellout"
18
+ require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
19
19
 
20
20
  module Kitchen
21
21
  # Mixin that wraps a command shell out invocation, providing a #run_command
@@ -16,9 +16,10 @@
16
16
  # limitations under the License.
17
17
 
18
18
  require "logger"
19
- require "net/ssh"
20
- require "net/scp"
21
- require "socket"
19
+ module Net
20
+ autoload :SSH, "net/ssh"
21
+ end
22
+ require "socket" unless defined?(Socket)
22
23
 
23
24
  require_relative "errors"
24
25
  require_relative "login_command"
@@ -90,6 +91,7 @@ module Kitchen
90
91
  # `Net::SCP.upload`
91
92
  # @see http://net-ssh.github.io/net-scp/classes/Net/SCP.html#method-i-upload
92
93
  def upload!(local, remote, options = {}, &progress)
94
+ require "net/scp" unless defined?(Net::SCP)
93
95
  if progress.nil?
94
96
  progress = lambda do |_ch, name, sent, total|
95
97
  logger.debug("Uploaded #{name} (#{total} bytes)") if sent == total
@@ -100,6 +102,7 @@ module Kitchen
100
102
  end
101
103
 
102
104
  def upload(local, remote, options = {}, &progress)
105
+ require "net/scp" unless defined?(Net::SCP)
103
106
  if progress.nil?
104
107
  progress = lambda do |_ch, name, sent, total|
105
108
  if sent == total
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "yaml"
18
+ autoload :YAML, "yaml"
19
19
 
20
20
  module Kitchen
21
21
  # Exception class for any exceptions raised when reading and parsing a state
@@ -15,7 +15,7 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "thor"
18
+ require "thor" unless defined?(Thor)
19
19
 
20
20
  require_relative "../kitchen"
21
21
 
@@ -21,6 +21,7 @@ require_relative "../errors"
21
21
  require_relative "../lazy_hash"
22
22
  require_relative "../logging"
23
23
  require_relative "../login_command"
24
+ require_relative "../plugin_base"
24
25
 
25
26
  module Kitchen
26
27
  module Transport
@@ -40,7 +41,7 @@ module Kitchen
40
41
  #
41
42
  # @author Salim Afiune <salim@afiunemaya.com.mx>
42
43
  # @author Fletcher Nichol <fnichol@nichol.ca>
43
- class Base
44
+ class Base < Kitchen::Plugin::Base
44
45
  include Configurable
45
46
  include Logging
46
47
 
@@ -11,7 +11,7 @@
11
11
  # See the License for the specific language governing permissions and
12
12
  # limitations under the License.
13
13
 
14
- require "fileutils"
14
+ require "fileutils" unless defined?(FileUtils)
15
15
 
16
16
  require_relative "../shell_out"
17
17
  require_relative "base"
@@ -28,7 +28,7 @@ module Kitchen
28
28
  plugin_version Kitchen::VERSION
29
29
 
30
30
  def connection(state, &block)
31
- options = config.to_hash.merge(state)
31
+ options = connection_options(config.to_hash.merge(state))
32
32
  Kitchen::Transport::Exec::Connection.new(options, &block)
33
33
  end
34
34
 
@@ -40,19 +40,105 @@ module Kitchen
40
40
  def execute(command)
41
41
  return if command.nil?
42
42
 
43
- run_command(command)
43
+ if host_os_windows?
44
+ run_command(run_from_file_command(command))
45
+ close
46
+ else
47
+ run_command(command)
48
+ end
49
+ end
50
+
51
+ def close
52
+ if host_os_windows?
53
+ FileUtils.remove(exec_script_file)
54
+ end
44
55
  end
45
56
 
46
57
  # "Upload" the files by copying them locally.
47
58
  #
48
59
  # @see Base#upload
49
60
  def upload(locals, remote)
50
- FileUtils.mkdir_p(remote)
61
+ # evaluate $env:temp on Windows
62
+ real_remote = remote.to_s == "\$env:TEMP\\kitchen" ? kitchen_temp : remote
63
+ FileUtils.mkdir_p(real_remote)
51
64
  Array(locals).each do |local|
52
- FileUtils.cp_r(local, remote)
65
+ FileUtils.cp_r(local, real_remote)
66
+ end
67
+ end
68
+
69
+ # (see Base#init_options)
70
+ def init_options(options)
71
+ super
72
+ @instance_name = @options.delete(:instance_name)
73
+ @kitchen_root = @options.delete(:kitchen_root)
74
+ end
75
+
76
+ private
77
+
78
+ # @return [String] display name for the associated instance
79
+ # @api private
80
+ attr_reader :instance_name
81
+
82
+ # @return [String] local path to the root of the project
83
+ # @api private
84
+ attr_reader :kitchen_root
85
+
86
+ # Takes a long command and saves it to a file and uploads it to
87
+ # the test instance. Windows has cli character limits.
88
+ #
89
+ # @param command [String] a long command to be saved and uploaded
90
+ # @return [String] a command that executes the uploaded script
91
+ # @api private
92
+ def run_from_file_command(command)
93
+ if logger.debug?
94
+ debug("Creating exec script for #{instance_name} (#{exec_script_file})")
95
+ debug("Executing #{exec_script_file}")
96
+ end
97
+ File.open(exec_script_file, "wb") { |file| file.write(command) }
98
+ %{powershell -file "#{exec_script_file}"}
99
+ end
100
+
101
+ # @return [String] evaluated $env:temp variable
102
+ # @api private
103
+ def kitchen_temp
104
+ "#{ENV["temp"]}/kitchen"
105
+ end
106
+
107
+ # @return [String] name of script using instance name
108
+ # @api private
109
+ def exec_script_name
110
+ "#{instance_name}-exec-script.ps1"
111
+ end
112
+
113
+ # @return [String] file path for exec script to be run
114
+ # @api private
115
+ def exec_script_file
116
+ File.join(kitchen_root, ".kitchen", exec_script_name)
117
+ end
118
+
119
+ def host_os_windows?
120
+ case RbConfig::CONFIG["host_os"]
121
+ when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
122
+ true
123
+ else
124
+ false
53
125
  end
54
126
  end
127
+ end
128
+
129
+ private
55
130
 
131
+ # Builds the hash of options needed by the Connection object on construction.
132
+ #
133
+ # @param data [Hash] merged configuration and mutable state data
134
+ # @return [Hash] hash of connection options
135
+ # @api private
136
+ def connection_options(data)
137
+ opts = {
138
+ instance_name: instance.name,
139
+ kitchen_root: Dir.pwd,
140
+ }
141
+ opts
56
142
  end
57
143
  end
58
144
  end
@@ -17,13 +17,13 @@
17
17
 
18
18
  require_relative "../../kitchen"
19
19
 
20
- require "fileutils"
21
- require "net/ssh"
20
+ require "fileutils" unless defined?(FileUtils)
21
+ require "net/ssh" unless defined?(Net::SSH)
22
22
  require "net/ssh/gateway"
23
23
  require "net/ssh/proxy/http"
24
24
  require "net/scp"
25
- require "timeout"
26
- require "benchmark"
25
+ require "timeout" unless defined?(Timeout)
26
+ require "benchmark" unless defined?(Benchmark)
27
27
 
28
28
  module Kitchen
29
29
  module Transport
@@ -17,10 +17,10 @@
17
17
  # See the License for the specific language governing permissions and
18
18
  # limitations under the License.
19
19
 
20
- require "rbconfig"
21
- require "uri"
20
+ require "rbconfig" unless defined?(RbConfig)
21
+ require "uri" unless defined?(URI)
22
22
  require_relative "../../kitchen"
23
- require "winrm"
23
+ require "winrm" unless defined?(WinRM::Connection)
24
24
 
25
25
  module Kitchen
26
26
  module Transport
@@ -110,7 +110,7 @@ module Kitchen
110
110
  def self.wrap_command(cmd)
111
111
  cmd = "false" if cmd.nil?
112
112
  cmd = "true" if cmd.to_s.empty?
113
- cmd = cmd.sub(/\n\Z/, "") if cmd =~ /\n\Z/
113
+ cmd = cmd.sub(/\n\Z/, "") if /\n\Z/.match?(cmd)
114
114
 
115
115
  "sh -c '\n#{cmd}\n'"
116
116
  end
@@ -18,13 +18,14 @@
18
18
  require_relative "../errors"
19
19
  require_relative "../configurable"
20
20
  require_relative "../logging"
21
+ require_relative "../plugin_base"
21
22
 
22
23
  module Kitchen
23
24
  module Verifier
24
25
  # Base class for a verifier.
25
26
  #
26
27
  # @author Fletcher Nichol <fnichol@nichol.ca>
27
- class Base
28
+ class Base < Kitchen::Plugin::Base
28
29
  include Configurable
29
30
  include Logging
30
31
 
@@ -15,8 +15,8 @@
15
15
  # See the License for the specific language governing permissions and
16
16
  # limitations under the License.
17
17
 
18
- require "base64"
19
- require "digest"
18
+ require "base64" unless defined?(Base64)
19
+ require "digest" unless defined?(Digest)
20
20
 
21
21
  require_relative "base"
22
22
 
@@ -168,7 +168,7 @@ module Kitchen
168
168
  # @api private
169
169
  def gem_install_args
170
170
  gem, version = config[:version].split("@")
171
- if gem =~ /^\d+\.\d+\.\d+/
171
+ if /^\d+\.\d+\.\d+/.match?(gem)
172
172
  version = gem
173
173
  gem = "busser"
174
174
  end
@@ -23,7 +23,7 @@ module Kitchen
23
23
  #
24
24
  # @author SAWANOBORI Yukihiko (<sawanoboriyu@higanworks.com>)
25
25
  class Shell < Kitchen::Verifier::Base
26
- require "mixlib/shellout"
26
+ require "mixlib/shellout" unless defined?(Mixlib::ShellOut)
27
27
 
28
28
  kitchen_verifier_api_version 1
29
29
 
@@ -16,5 +16,5 @@
16
16
  # limitations under the License.
17
17
 
18
18
  module Kitchen
19
- VERSION = "2.5.4".freeze
19
+ VERSION = "2.8.0".freeze
20
20
  end
@@ -1,4 +1,4 @@
1
- lib = File.expand_path("../lib", __FILE__)
1
+ lib = File.expand_path("lib", __dir__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require "kitchen/version"
4
4
  require "English"
@@ -15,12 +15,12 @@ Gem::Specification.new do |gem|
15
15
  gem.summary = gem.description
16
16
  gem.homepage = "https://kitchen.ci/"
17
17
 
18
- # The gemfile and gemspec are necessary for appbundler in Chef-DK / Workstation
18
+ # The gemfile and gemspec are necessary for appbundler in ChefDK / Workstation
19
19
  gem.files = %w{LICENSE test-kitchen.gemspec Gemfile Rakefile} + Dir.glob("{bin,lib,templates,support}/**/*")
20
20
  gem.executables = %w{kitchen}
21
21
  gem.require_paths = ["lib"]
22
22
 
23
- gem.required_ruby_version = ">= 2.3"
23
+ gem.required_ruby_version = ">= 2.4"
24
24
 
25
25
  gem.add_dependency "mixlib-shellout", ">= 1.2", "< 4.0"
26
26
  gem.add_dependency "net-scp", ">= 1.1", "< 4.0" # pinning until we can confirm 4+ works
@@ -35,7 +35,7 @@ Gem::Specification.new do |gem|
35
35
  gem.add_dependency "winrm-fs", "~> 1.1"
36
36
  # Required to run the Chef provisioner local license check for remote systems
37
37
  # TK is not under Chef EULA
38
- gem.add_dependency "license-acceptance", "~> 1.0", ">= 1.0.11"
38
+ gem.add_dependency "license-acceptance", ">= 1.0.11", "< 3.0" # pinning until we can confirm 3+ works
39
39
 
40
40
  gem.add_development_dependency "rb-readline"
41
41
  gem.add_development_dependency "bundler"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: test-kitchen
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.5.4
4
+ version: 2.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fletcher Nichol
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-29 00:00:00.000000000 Z
11
+ date: 2020-12-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mixlib-shellout
@@ -198,22 +198,22 @@ dependencies:
198
198
  name: license-acceptance
199
199
  requirement: !ruby/object:Gem::Requirement
200
200
  requirements:
201
- - - "~>"
202
- - !ruby/object:Gem::Version
203
- version: '1.0'
204
201
  - - ">="
205
202
  - !ruby/object:Gem::Version
206
203
  version: 1.0.11
204
+ - - "<"
205
+ - !ruby/object:Gem::Version
206
+ version: '3.0'
207
207
  type: :runtime
208
208
  prerelease: false
209
209
  version_requirements: !ruby/object:Gem::Requirement
210
210
  requirements:
211
- - - "~>"
212
- - !ruby/object:Gem::Version
213
- version: '1.0'
214
211
  - - ">="
215
212
  - !ruby/object:Gem::Version
216
213
  version: 1.0.11
214
+ - - "<"
215
+ - !ruby/object:Gem::Version
216
+ version: '3.0'
217
217
  - !ruby/object:Gem::Dependency
218
218
  name: rb-readline
219
219
  requirement: !ruby/object:Gem::Requirement
@@ -423,6 +423,7 @@ files:
423
423
  - lib/kitchen/metadata_chopper.rb
424
424
  - lib/kitchen/platform.rb
425
425
  - lib/kitchen/plugin.rb
426
+ - lib/kitchen/plugin_base.rb
426
427
  - lib/kitchen/provisioner.rb
427
428
  - lib/kitchen/provisioner/base.rb
428
429
  - lib/kitchen/provisioner/chef/berkshelf.rb
@@ -492,14 +493,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
492
493
  requirements:
493
494
  - - ">="
494
495
  - !ruby/object:Gem::Version
495
- version: '2.3'
496
+ version: '2.4'
496
497
  required_rubygems_version: !ruby/object:Gem::Requirement
497
498
  requirements:
498
499
  - - ">="
499
500
  - !ruby/object:Gem::Version
500
501
  version: '0'
501
502
  requirements: []
502
- rubygems_version: 3.1.2
503
+ rubygems_version: 3.1.4
503
504
  signing_key:
504
505
  specification_version: 4
505
506
  summary: Test Kitchen is an integration tool for developing and testing infrastructure