test-kitchen 3.7.2 → 3.8.1

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: 2d5084681fcdd3347fff64203a6a4a01e005297e2da8da4a19268e862c015f78
4
- data.tar.gz: a97d9c95641aef0c507f775dbf8164e73acc712bd5efed94324209c8b7a5d725
3
+ metadata.gz: 20202cfa53b2c7701a9cf67fa0d48b8d6975b5adbe0c0a6fdac04ccd6fae227a
4
+ data.tar.gz: 78af76288e703870f132824cd0037cb0e35b5128349e73296d648b75c270fbbe
5
5
  SHA512:
6
- metadata.gz: a1c90dbec6701faa9b16472fea3b46bff2e5743fb08db95d44a305dcfa7bdcea5c92961a5c82d9758e199f128dfbf746474414db8ec1cc910b99e6471b9e5ec0
7
- data.tar.gz: 698c4e4f6a617799ac5930da2ab8e4e934a5cbc523cb7515bc241117e3544166acf81a8fcc8b716c58fa0319b41b78e51a1dbc2846faaa442435d0937764521e
6
+ metadata.gz: 4935e08c83c27064098f9903cc76728b74c5cbb7cd15c3378ab5809c5fbb52b9890b13b4109cac44287307a78537aeeb80ed60cc31439f51f90ccbbe583a5645
7
+ data.tar.gz: 5cf63e66b71ef201bae5157f9cf3dcb94682aa7f78611e2669e24466ddb96b101b3818ec1fab4d96283acb483eaaf2e2d3383854140b34f5a3c741ae412dc83d
data/Gemfile CHANGED
@@ -7,7 +7,7 @@ group :test do
7
7
  gem "rb-readline"
8
8
  gem "aruba", ">= 0.11", "< 3.0"
9
9
  gem "countloc", "~> 0.4"
10
- gem "cucumber", ">= 9.2", "< 10"
10
+ gem "cucumber", ">= 9.2", "< 11"
11
11
  gem "fakefs", "~> 3.0"
12
12
  gem "maruku", "~> 0.6"
13
13
  gem "minitest", "~> 5.3", "< 6.0"
@@ -98,7 +98,7 @@ module Kitchen
98
98
  # directory containing test suites and other testing-related files and
99
99
  # directories (default: `"#{kitchen_root}/test/integration"`)
100
100
  # @option options [Symbol] :log_level the log level verbosity that the
101
- # loggers will use when outputing information (default: `:info`)
101
+ # loggers will use when outputting information (default: `:info`)
102
102
  def initialize(options = {})
103
103
  @loader = options.fetch(:loader) { Kitchen::Loader::YAML.new }
104
104
  @kitchen_root = options.fetch(:kitchen_root) { Dir.pwd }
@@ -485,7 +485,7 @@ module Kitchen
485
485
  # end
486
486
  #
487
487
  # @param attr [String] configuration attribute name
488
- # @param value [Object, nil] whether or not to exand the file path
488
+ # @param value [Object, nil] whether or not to expand the file path
489
489
  # @yieldparam object [Object] a reference to the instantiated object
490
490
  # @yieldreturn [Object, nil] dynamically compute whether or not to
491
491
  # perform the file expansion
@@ -1,8 +1,3 @@
1
- #
2
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
- #
4
- # Copyright (C) 2012, Fletcher Nichol
5
- #
6
1
  # Licensed under the Apache License, Version 2.0 (the "License");
7
2
  # you may not use this file except in compliance with the License.
8
3
  # You may obtain a copy of the License at
@@ -25,8 +20,6 @@ require_relative "../shell_out"
25
20
  module Kitchen
26
21
  module Driver
27
22
  # Base class for a driver.
28
- #
29
- # @author Fletcher Nichol <fnichol@nichol.ca>
30
23
  class Base < Kitchen::Plugin::Base
31
24
  include Configurable
32
25
  include Logging
@@ -1,8 +1,3 @@
1
- #
2
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
- #
4
- # Copyright (C) 2012, 2013, 2014 Fletcher Nichol
5
- #
6
1
  # Licensed under the Apache License, Version 2.0 (the "License");
7
2
  # you may not use this file except in compliance with the License.
8
3
  # You may obtain a copy of the License at
@@ -1,4 +1,3 @@
1
- #
2
1
  # Licensed under the Apache License, Version 2.0 (the "License");
3
2
  # you may not use this file except in compliance with the License.
4
3
  # You may obtain a copy of the License at
@@ -1,9 +1,3 @@
1
- #
2
- # Author:: Seth Chisamore <schisamo@opscode.com>
3
- #
4
- # Copyright:: Copyright (c) 2013 Opscode, Inc.
5
- # License:: Apache License, Version 2.0
6
- #
7
1
  # Licensed under the Apache License, Version 2.0 (the "License");
8
2
  # you may not use this file except in compliance with the License.
9
3
  # You may obtain a copy of the License at
@@ -1,8 +1,3 @@
1
- #
2
- # Author:: Fletcher Nichol (<fnichol@nichol.ca>)
3
- #
4
- # Copyright (C) 2012, Fletcher Nichol
5
- #
6
1
  # Licensed under the Apache License, Version 2.0 (the "License");
7
2
  # you may not use this file except in compliance with the License.
8
3
  # You may obtain a copy of the License at
@@ -70,20 +70,39 @@ module Kitchen
70
70
  # rubocop:disable Metrics/AbcSize
71
71
  def call(state)
72
72
  create_sandbox
73
+ prepare_install_script
73
74
 
74
75
  instance.transport.connection(state) do |conn|
75
76
  config[:uploads].to_h.each do |locals, remote|
76
77
  debug("Uploading #{Array(locals).join(", ")} to #{remote}")
77
78
  conn.upload(locals.to_s, remote)
78
79
  end
79
- conn.execute(install_command)
80
+
81
+ # Run the init command to create the kitchen tmp directory
82
+ conn.execute(encode_for_powershell(init_command))
83
+
84
+ # Upload the install script instead of directly executing the command
85
+ if install_command
86
+ script_filename = windows_os? ? "install_script.ps1" : "install_script"
87
+ remote_script_path = remote_path_join(resolve_remote_path(config[:root_path]), script_filename)
88
+ if install_script_path
89
+ debug("Uploading install script to #{remote_script_path}")
90
+ conn.upload(install_script_path, remote_script_path)
91
+ # Make script executable on remote host
92
+ conn.execute(make_executable_command(remote_script_path))
93
+ # Execute the uploaded script
94
+ conn.execute(run_script_command(remote_script_path))
95
+ end
96
+ end
97
+
98
+ # The install script will remove the kitchen tmp directory, hence creating it again.
80
99
  conn.execute(init_command)
81
100
  info("Transferring files to #{instance.to_str}")
82
- conn.upload(sandbox_dirs, config[:root_path])
101
+ conn.upload(sandbox_dirs, resolve_remote_path(config[:root_path]))
83
102
  debug("Transfer complete")
84
103
  conn.execute(prepare_command)
85
104
  conn.execute_with_retry(
86
- run_command,
105
+ encode_for_powershell(run_command),
87
106
  config[:retry_on_exit_code],
88
107
  config[:max_retries],
89
108
  config[:wait_for_retry]
@@ -195,6 +214,7 @@ module Kitchen
195
214
  return if sandbox_path.nil?
196
215
 
197
216
  debug("Cleaning up local sandbox in #{sandbox_path}")
217
+ @install_script_path = nil
198
218
  FileUtils.rmtree(sandbox_path)
199
219
  end
200
220
 
@@ -270,6 +290,103 @@ module Kitchen
270
290
  def prefix_command(script)
271
291
  config[:command_prefix] ? "#{config[:command_prefix]} #{script}" : script
272
292
  end
293
+
294
+ def encode_for_powershell(script)
295
+ return script unless windows_os?
296
+ return script if script.nil? || script.empty?
297
+
298
+ utf16le = script.encode(Encoding::UTF_16LE)
299
+ encoded = [utf16le].pack("m0")
300
+
301
+ "powershell -NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass -EncodedCommand #{encoded}"
302
+ end
303
+
304
+ # Writes the install command to a file that will be uploaded to the instance
305
+ # and executed.
306
+ #
307
+ # @api private
308
+ def prepare_install_script
309
+ command = install_command
310
+ return if command.nil? || command.empty?
311
+
312
+ info("Preparing install script")
313
+ script_filename = windows_os? ? "install_script.ps1" : "install_script"
314
+ @install_script_path = File.join(sandbox_path, script_filename)
315
+
316
+ debug("Creating install script at #{@install_script_path}")
317
+ File.open(@install_script_path, "wb") do |file|
318
+ unless windows_os?
319
+ file.write("#!/bin/sh\n")
320
+ end
321
+ file.write(command)
322
+ end
323
+
324
+ # Make script executable locally
325
+ FileUtils.chmod(0755, @install_script_path) unless windows_os?
326
+ end
327
+
328
+ def install_script_path
329
+ @install_script_path
330
+ end
331
+
332
+ # Returns a command to make a script executable on the remote host.
333
+ #
334
+ # @param script_path [String] path to the script on the remote host
335
+ # @return [String] command to make the script executable
336
+ # @api private
337
+ def make_executable_command(script_path)
338
+ debug "echo Making script executable"
339
+ return if windows_os?
340
+
341
+ prefix_command(wrap_shell_code(sudo("chmod +x #{script_path}")))
342
+ end
343
+
344
+ # Returns a command to execute a script on the remote host.
345
+ #
346
+ # @param script_path [String] path to the script on the remote host
347
+ # @return [String] command to execute the script
348
+ # @api private
349
+ def run_script_command(script_path)
350
+ if windows_os?
351
+ # Use parameters to suppress PowerShell formatting and control characters
352
+ # that can interfere with console output over SSH
353
+ "powershell -NoProfile -NonInteractive -NoLogo -ExecutionPolicy Bypass -File #{script_path}"
354
+ else
355
+ prefix_command(wrap_shell_code(sudo(script_path)))
356
+ end
357
+ end
358
+
359
+ # Resolves PowerShell environment variables in remote paths to actual paths
360
+ # for use with net/scp and other transport operations that can't handle
361
+ # PowerShell variables like $env:TEMP.
362
+ #
363
+ # @param path [String] the remote path that may contain PowerShell env vars
364
+ # @return [String] the resolved path
365
+ # @api private
366
+ def resolve_remote_path(path)
367
+ return path unless windows_os?
368
+
369
+ # For Windows, resolve common PowerShell environment variables
370
+ resolved_path = path.dup
371
+
372
+ # Replace $env:TEMP with the actual Windows temp directory based on the transport username
373
+ if resolved_path.include?("$env:TEMP")
374
+ # Try to get username from transport configuration
375
+ # For Windows systems, fallback to "Administrator" if not found
376
+ username = begin
377
+ instance.transport[:username]
378
+ rescue
379
+ nil
380
+ end
381
+ username ||= "Administrator"
382
+
383
+ temp_path = "C:/Users/#{username}/AppData/Local/Temp"
384
+ resolved_path = resolved_path.gsub("$env:TEMP", temp_path)
385
+ end
386
+
387
+ # Convert backslashes to forward slashes for cross-platform compatibility
388
+ resolved_path.tr("\\", "/")
389
+ end
273
390
  end
274
391
  end
275
392
  end
@@ -115,7 +115,7 @@ module Kitchen
115
115
  end
116
116
  end
117
117
 
118
- code = powershell_shell? ? %{& #{script}} : sudo(script)
118
+ code = powershell_shell? ? %{& "#{script}"} : sudo(script)
119
119
 
120
120
  prefix_command(wrap_shell_code(code))
121
121
  end
@@ -23,7 +23,7 @@ module Kitchen
23
23
  #
24
24
  # @author Fletcher Nichol <fnichol@nichol.ca>
25
25
  module ShellOut
26
- # Wrapped exception for any interally raised shell out commands.
26
+ # Wrapped exception for any internally raised shell out commands.
27
27
  class ShellCommandFailed < TransientFailure; end
28
28
 
29
29
  # Executes a command in a subshell on the local running system.
@@ -364,7 +364,9 @@ module Kitchen
364
364
  logger.debug(masked_string)
365
365
  yield
366
366
  rescue *RESCUE_EXCEPTIONS_ON_ESTABLISH => e
367
- if (opts[:retries] -= 1) > 0
367
+ retries_left = opts[:retries] - 1
368
+ if retries_left > 0
369
+ opts[:retries] = retries_left
368
370
  message = if opts[:message]
369
371
  logger.debug("[SSH] connection failed (#{e.inspect})")
370
372
  opts[:message]
@@ -16,5 +16,5 @@
16
16
  # limitations under the License.
17
17
 
18
18
  module Kitchen
19
- VERSION = "3.7.2".freeze
19
+ VERSION = "3.8.1".freeze
20
20
  end
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: 3.7.2
4
+ version: 3.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Fletcher Nichol
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-07-03 00:00:00.000000000 Z
11
+ date: 2025-07-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bcrypt_pbkdf