kitchen-pester 0.12.1 → 1.1.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 +4 -4
- data/Gemfile +1 -1
- data/Rakefile +1 -3
- data/kitchen-pester.gemspec +2 -3
- data/lib/kitchen/verifier/pester.rb +483 -192
- data/lib/kitchen/verifier/pester_version.rb +1 -1
- data/lib/support/modules/PesterUtil/PesterUtil.psm1 +158 -0
- metadata +8 -8
- data/lib/support/powershell/PesterUtil/PesterUtil.psm1 +0 -24
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e31dac41f9925e0fb86d2b96a2ead03a1c1dabb42adbf038ef572966aeb6d7db
|
|
4
|
+
data.tar.gz: 9047b382ad4d31572b7515aeb70d495e54019a87207cad463598938a669c38f7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 73bcc2e6ba82f652ca7ffd81d27c05b96d3eb1e0101043b0207d7dd583b8c040979f23a37f1b6c59c719979e026ce2df3ff7f8c319cb1dd41783668d3f0cd3e0
|
|
7
|
+
data.tar.gz: 7b63adcc2817a530bc5ddc8a2feb159353f80217abd739c8aba2019a222c6a841911c0a543dd8cb2fdf4159a3de9ae16aa3426333d71a4dd8175bb52dc0f9d80
|
data/Gemfile
CHANGED
data/Rakefile
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
|
|
3
1
|
require "bundler/gem_tasks"
|
|
4
2
|
|
|
5
3
|
require "rake/testtask"
|
|
@@ -25,7 +23,7 @@ desc "Run all quality tasks"
|
|
|
25
23
|
task quality: :style
|
|
26
24
|
|
|
27
25
|
begin
|
|
28
|
-
require "yard"
|
|
26
|
+
require "yard" unless defined?(YARD)
|
|
29
27
|
YARD::Rake::YardocTask.new
|
|
30
28
|
rescue LoadError
|
|
31
29
|
puts "yard is not available. (sudo) gem install yard to generate yard documentation."
|
data/kitchen-pester.gemspec
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
3
|
|
|
5
4
|
require "kitchen/verifier/pester_version"
|
|
@@ -22,5 +21,5 @@ Gem::Specification.new do |spec|
|
|
|
22
21
|
spec.add_development_dependency "minitest", "~> 5.3", "< 5.15"
|
|
23
22
|
spec.add_development_dependency "mocha", "~> 1.1"
|
|
24
23
|
|
|
25
|
-
spec.add_dependency "test-kitchen", ">= 1.10", "<
|
|
24
|
+
spec.add_dependency "test-kitchen", ">= 1.10", "< 4"
|
|
26
25
|
end
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
|
2
|
-
#
|
|
3
1
|
# Author:: Steven Murawski (<steven.murawski@gmail.com>)
|
|
4
2
|
#
|
|
5
3
|
# Copyright (C) 2015, Steven Murawski
|
|
@@ -16,9 +14,12 @@
|
|
|
16
14
|
# See the License for the specific language governing permissions and
|
|
17
15
|
# limitations under the License.
|
|
18
16
|
|
|
19
|
-
require "
|
|
17
|
+
require "fileutils" unless defined?(FileUtils)
|
|
18
|
+
require "pathname" unless defined?(Pathname)
|
|
19
|
+
require "kitchen/util"
|
|
20
20
|
require "kitchen/verifier/base"
|
|
21
21
|
require "kitchen/version"
|
|
22
|
+
require "base64" unless defined?(Base64)
|
|
22
23
|
require_relative "pester_version"
|
|
23
24
|
|
|
24
25
|
module Kitchen
|
|
@@ -32,9 +33,39 @@ module Kitchen
|
|
|
32
33
|
plugin_version Kitchen::Verifier::PESTER_VERSION
|
|
33
34
|
|
|
34
35
|
default_config :restart_winrm, false
|
|
35
|
-
default_config :test_folder
|
|
36
|
-
default_config :
|
|
37
|
-
default_config :
|
|
36
|
+
default_config :test_folder, "tests"
|
|
37
|
+
default_config :remove_builtin_powershellget, true
|
|
38
|
+
default_config :remove_builtin_pester, true
|
|
39
|
+
default_config :skip_pester_install, false
|
|
40
|
+
default_config :bootstrap, {
|
|
41
|
+
repository_url: "https://www.powershellgallery.com/api/v2",
|
|
42
|
+
modules: [],
|
|
43
|
+
}
|
|
44
|
+
default_config :register_repository, []
|
|
45
|
+
default_config :pester_install, {
|
|
46
|
+
SkipPublisherCheck: true,
|
|
47
|
+
Force: true,
|
|
48
|
+
ErrorAction: "Stop",
|
|
49
|
+
}
|
|
50
|
+
default_config :pester_configuration, {
|
|
51
|
+
run: {
|
|
52
|
+
path: ".",
|
|
53
|
+
PassThru: true,
|
|
54
|
+
},
|
|
55
|
+
TestResult: {
|
|
56
|
+
Enabled: true,
|
|
57
|
+
OutputPath: "PesterTestResults.xml",
|
|
58
|
+
TestSuiteName: "",
|
|
59
|
+
},
|
|
60
|
+
Output: {
|
|
61
|
+
Verbosity: "Detailed",
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
default_config :install_modules, []
|
|
65
|
+
default_config :downloads, { "./PesterTestResults.xml" => "./testresults/" }
|
|
66
|
+
default_config :copy_folders, []
|
|
67
|
+
default_config :sudo, false
|
|
68
|
+
default_config :shell, nil
|
|
38
69
|
|
|
39
70
|
# Creates a new Verifier object using the provided configuration data
|
|
40
71
|
# which will be merged with any default configuration.
|
|
@@ -64,21 +95,56 @@ module Kitchen
|
|
|
64
95
|
# end
|
|
65
96
|
def create_sandbox
|
|
66
97
|
super
|
|
67
|
-
|
|
98
|
+
prepare_supporting_psmodules
|
|
99
|
+
prepare_copy_folders
|
|
68
100
|
prepare_pester_tests
|
|
69
101
|
prepare_helpers
|
|
102
|
+
|
|
103
|
+
debug("\n\n")
|
|
104
|
+
debug("Sandbox content:\n")
|
|
105
|
+
list_files(sandbox_path).each do |f|
|
|
106
|
+
debug(" #{f}")
|
|
107
|
+
end
|
|
70
108
|
end
|
|
71
109
|
|
|
72
110
|
# Generates a command string which will install and configure the
|
|
73
111
|
# verifier software on an instance. If no work is required, then `nil`
|
|
74
112
|
# will be returned.
|
|
113
|
+
# PowerShellGet & Pester Bootstrap are done in prepare_command (after sandbox is transferred)
|
|
114
|
+
# so that we can use the PesterUtil.psm1
|
|
75
115
|
#
|
|
76
116
|
# @return [String] a command string
|
|
77
117
|
def install_command
|
|
78
|
-
|
|
79
|
-
|
|
118
|
+
# the sandbox has not yet been copied to the SUT.
|
|
119
|
+
install_command_string = <<-PS1
|
|
120
|
+
Write-Verbose 'Running Install Command...'
|
|
121
|
+
$modulesToRemove = @(
|
|
122
|
+
if ($#{config[:remove_builtin_powershellget]}) {
|
|
123
|
+
Get-module -ListAvailable -FullyQualifiedName @{ModuleName = 'PackageManagement'; RequiredVersion = '1.0.0.1'}
|
|
124
|
+
Get-module -ListAvailable -FullyQualifiedName @{ModuleName = 'PowerShellGet'; RequiredVersion = '1.0.0.1'}
|
|
125
|
+
}
|
|
80
126
|
|
|
81
|
-
|
|
127
|
+
if ($#{config[:remove_builtin_pester]}) {
|
|
128
|
+
Get-module -ListAvailable -FullyQualifiedName @{ModuleName = 'Pester'; RequiredVersion = '3.4.0'}
|
|
129
|
+
}
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
if ($modulesToRemove.ModuleBase.Count -eq 0) {
|
|
133
|
+
# for PS7 on linux
|
|
134
|
+
return
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
$modulesToRemove.ModuleBase | Foreach-Object {
|
|
138
|
+
$ModuleBaseLeaf = Split-Path -Path $_ -Leaf
|
|
139
|
+
if ($ModuleBaseLeaf -as [System.version]) {
|
|
140
|
+
Remove-Item -force -Recurse (Split-Path -Parent -Path $_) -ErrorAction SilentlyContinue
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
Remove-Item -force -Recurse $_ -ErrorAction SilentlyContinue
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
PS1
|
|
147
|
+
really_wrap_shell_code(Util.outdent!(install_command_string))
|
|
82
148
|
end
|
|
83
149
|
|
|
84
150
|
# Generates a command string which will perform any data initialization
|
|
@@ -97,7 +163,11 @@ module Kitchen
|
|
|
97
163
|
# required, then `nil` will be returned.
|
|
98
164
|
#
|
|
99
165
|
# @return [String] a command string
|
|
100
|
-
def prepare_command
|
|
166
|
+
def prepare_command
|
|
167
|
+
info("Preparing the SUT and Pester dependencies...")
|
|
168
|
+
resolve_downloads_paths!
|
|
169
|
+
really_wrap_shell_code(install_command_script)
|
|
170
|
+
end
|
|
101
171
|
|
|
102
172
|
# Generates a command string which will invoke the main verifier
|
|
103
173
|
# command on the prepared instance. If no work is required, then `nil`
|
|
@@ -105,9 +175,38 @@ module Kitchen
|
|
|
105
175
|
#
|
|
106
176
|
# @return [String] a command string
|
|
107
177
|
def run_command
|
|
108
|
-
|
|
178
|
+
really_wrap_shell_code(invoke_pester_scriptblock)
|
|
179
|
+
end
|
|
109
180
|
|
|
110
|
-
|
|
181
|
+
# Resolves the remote Downloads path from the verifier root path,
|
|
182
|
+
# unless they're absolute path (starts with / or C:\)
|
|
183
|
+
# This updates the config[:downloads], nothing (nil) is returned.
|
|
184
|
+
#
|
|
185
|
+
# @return [nil] updates config downloads
|
|
186
|
+
def resolve_downloads_paths!
|
|
187
|
+
info("Resolving Downloads path from config.")
|
|
188
|
+
config[:downloads] = config[:downloads]
|
|
189
|
+
.map do |source, destination|
|
|
190
|
+
source = source.to_s
|
|
191
|
+
info(" resolving remote source's absolute path.")
|
|
192
|
+
unless source.match?('^/|^[a-zA-Z]:[\\/]') # is Absolute?
|
|
193
|
+
info(" '#{source}' is a relative path, resolving to: #{File.join(config[:root_path], source)}")
|
|
194
|
+
source = File.join(config[:root_path], source.to_s).to_s
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
if destination.match?('\\$|/$') # is Folder (ends with / or \)
|
|
198
|
+
destination = File.join(destination, File.basename(source)).to_s
|
|
199
|
+
end
|
|
200
|
+
info(" Destination: #{destination}")
|
|
201
|
+
if !File.directory?(File.dirname(destination))
|
|
202
|
+
FileUtils.mkdir_p(File.dirname(destination))
|
|
203
|
+
else
|
|
204
|
+
info(" Directory #{File.dirname(destination)} seem to exist.")
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
[ source, destination ]
|
|
208
|
+
end
|
|
209
|
+
nil # make sure we do not return anything
|
|
111
210
|
end
|
|
112
211
|
|
|
113
212
|
# Download functionality was added to the base verifier behavior after
|
|
@@ -116,7 +215,9 @@ module Kitchen
|
|
|
116
215
|
def call(state)
|
|
117
216
|
super
|
|
118
217
|
ensure
|
|
119
|
-
|
|
218
|
+
info("Ensure download test files.")
|
|
219
|
+
download_test_files(state) unless config[:downloads].nil?
|
|
220
|
+
info("Download complete.")
|
|
120
221
|
end
|
|
121
222
|
else
|
|
122
223
|
def call(state)
|
|
@@ -124,179 +225,291 @@ module Kitchen
|
|
|
124
225
|
rescue
|
|
125
226
|
# If the verifier reports failure, we need to download the files ourselves.
|
|
126
227
|
# Test Kitchen's base verifier doesn't have the download in an `ensure` block.
|
|
127
|
-
|
|
128
|
-
|
|
228
|
+
info("Rescue to download test files.")
|
|
229
|
+
download_test_files(state) unless config[:downloads].nil?
|
|
129
230
|
# Rethrow original exception, we still want to register the failure.
|
|
130
231
|
raise
|
|
131
232
|
end
|
|
132
233
|
end
|
|
133
234
|
|
|
134
235
|
# private
|
|
135
|
-
def
|
|
136
|
-
<<-
|
|
137
|
-
Import-Module -Name Pester -Force
|
|
236
|
+
def invoke_pester_scriptblock
|
|
237
|
+
<<-PS1
|
|
238
|
+
$PesterModule = Import-Module -Name Pester -Force -ErrorAction Stop -PassThru
|
|
239
|
+
|
|
240
|
+
$TestPath = Join-Path "#{config[:root_path]}" -ChildPath "suites"
|
|
241
|
+
$OutputFilePath = Join-Path "#{config[:root_path]}" -ChildPath 'PesterTestResults.xml'
|
|
242
|
+
|
|
243
|
+
if ($PesterModule.Version.Major -le 4)
|
|
244
|
+
{
|
|
245
|
+
Write-Host -Object "Invoke Pester with v$($PesterModule.Version) Options"
|
|
246
|
+
$options = New-PesterOption -TestSuiteName "Pester - #{instance.to_str}"
|
|
247
|
+
$defaultPesterParameters = @{
|
|
248
|
+
Script = $TestPath
|
|
249
|
+
OutputFile = $OutputFilePath
|
|
250
|
+
OutputFormat = 'NUnitXml'
|
|
251
|
+
PassThru = $true
|
|
252
|
+
PesterOption = $options
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
$pesterCmd = Get-Command -Name 'Invoke-Pester'
|
|
256
|
+
$pesterConfig = #{ps_hash(config[:pester_configuration])}
|
|
257
|
+
$invokePesterParams = @{}
|
|
258
|
+
|
|
259
|
+
foreach ($paramName in $pesterCmd.Parameters.Keys)
|
|
260
|
+
{
|
|
261
|
+
$paramValue = $pesterConfig.($paramName)
|
|
262
|
+
|
|
263
|
+
if ($paramValue) {
|
|
264
|
+
Write-Host -Object "Using $paramName from Yaml config."
|
|
265
|
+
$invokePesterParams[$paramName] = $paramValue
|
|
266
|
+
}
|
|
267
|
+
elseif ($defaultPesterParameters.ContainsKey($paramName))
|
|
268
|
+
{
|
|
269
|
+
Write-Host -Object "Using $paramName from Defaults: $($defaultPesterParameters[$paramName])."
|
|
270
|
+
$invokePesterParams[$paramName] = $defaultPesterParameters[$paramName]
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
$result = Invoke-Pester @invokePesterParams
|
|
275
|
+
}
|
|
276
|
+
else
|
|
277
|
+
{
|
|
278
|
+
Write-Host -Object "Invoke Pester with v$($PesterModule.Version) Configuration."
|
|
279
|
+
$pesterConfigHash = #{ps_hash(config[:pester_configuration])}
|
|
280
|
+
|
|
281
|
+
if (-not $pesterConfigHash.ContainsKey('run')) {
|
|
282
|
+
$pesterConfigHash['run'] = @{}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (-not $pesterConfigHash.ContainsKey('TestResult')) {
|
|
286
|
+
$pesterConfigHash['TestResult'] = @{}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
if (-not $pesterConfigHash.run.path) {
|
|
290
|
+
$pesterConfigHash['run']['path'] = $TestPath
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
if (-not $pesterConfigHash.TestResult.TestSuiteName) {
|
|
294
|
+
$pesterConfigHash['TestResult']['TestSuiteName'] = 'Pester - #{instance.to_str}'
|
|
295
|
+
}
|
|
138
296
|
|
|
139
|
-
|
|
140
|
-
|
|
297
|
+
if (-not $pesterConfigHash.TestResult.OutputPath) {
|
|
298
|
+
$pesterConfigHash['TestResult']['OutputPath'] = $OutputFilePath
|
|
299
|
+
}
|
|
141
300
|
|
|
142
|
-
|
|
301
|
+
$PesterConfig = New-PesterConfiguration -Hashtable $pesterConfigHash
|
|
302
|
+
$result = Invoke-Pester -Configuration $PesterConfig
|
|
303
|
+
}
|
|
143
304
|
|
|
144
|
-
$
|
|
145
|
-
|
|
305
|
+
$resultXmlPath = (Join-Path -Path $TestPath -ChildPath 'result.xml')
|
|
306
|
+
if (Test-Path -Path $resultXmlPath) {
|
|
307
|
+
$result | Export-CliXml -Path
|
|
308
|
+
}
|
|
146
309
|
|
|
147
310
|
$LASTEXITCODE = $result.FailedCount
|
|
148
311
|
$host.SetShouldExit($LASTEXITCODE)
|
|
149
312
|
|
|
150
313
|
exit $LASTEXITCODE
|
|
151
|
-
|
|
314
|
+
PS1
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
def get_powershell_modules_from_nugetapi
|
|
318
|
+
# don't return anything is the modules subkey or bootstrap is null
|
|
319
|
+
return if config.dig(:bootstrap, :modules).nil?
|
|
320
|
+
|
|
321
|
+
bootstrap = config[:bootstrap]
|
|
322
|
+
# if the repository url is set, use that as parameter to Install-ModuleFromNuget. Default is the PSGallery url
|
|
323
|
+
gallery_url_param = bootstrap[:repository_url] ? "-GalleryUrl '#{bootstrap[:repository_url]}'" : ""
|
|
324
|
+
|
|
325
|
+
info("Bootstrapping environment without PowerShellGet Provider...")
|
|
326
|
+
Array(bootstrap[:modules]).map do |powershell_module|
|
|
327
|
+
if powershell_module.is_a? Hash
|
|
328
|
+
<<-PS1
|
|
329
|
+
${#{powershell_module[:Name]}} = #{ps_hash(powershell_module)}
|
|
330
|
+
|
|
331
|
+
Install-ModuleFromNuget -Module ${#{powershell_module[:Name]}} #{gallery_url_param}
|
|
332
|
+
PS1
|
|
333
|
+
else
|
|
334
|
+
<<-PS1
|
|
335
|
+
Install-ModuleFromNuget -Module @{Name = '#{powershell_module}'} #{gallery_url_param}
|
|
336
|
+
PS1
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
# Returns the string command to set a PS Repository
|
|
342
|
+
# for each PSRepo configured.
|
|
343
|
+
#
|
|
344
|
+
# @return [Array<String>] array of suite files
|
|
345
|
+
# @api private
|
|
346
|
+
def register_psrepository_scriptblock
|
|
347
|
+
return if config[:register_repository].nil?
|
|
348
|
+
|
|
349
|
+
info("Registering a new PowerShellGet Repository")
|
|
350
|
+
Array(config[:register_repository]).map do |psrepo|
|
|
351
|
+
# Using Set-PSRepo from ../../*/*/*/PesterUtil.psm1
|
|
352
|
+
debug("Command to set PSRepo #{psrepo[:Name]}.")
|
|
353
|
+
<<-PS1
|
|
354
|
+
Write-Host 'Registering psrepo #{psrepo[:Name]}...'
|
|
355
|
+
${#{psrepo[:Name]}} = #{ps_hash(psrepo)}
|
|
356
|
+
Set-PSRepo -Repository ${#{psrepo[:Name]}}
|
|
357
|
+
PS1
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
|
|
361
|
+
# Returns the string command set the PSGallery as trusted, and
|
|
362
|
+
# Install Pester from gallery based on the params from Pester_install_params config
|
|
363
|
+
#
|
|
364
|
+
# @return <String> command to install Pester Module
|
|
365
|
+
# @api private
|
|
366
|
+
def install_pester
|
|
367
|
+
return if config[:skip_pester_install]
|
|
368
|
+
|
|
369
|
+
pester_install_params = config[:pester_install] || {}
|
|
370
|
+
<<-PS1
|
|
371
|
+
if ((Get-PSRepository -Name PSGallery).InstallationPolicy -ne 'Trusted') {
|
|
372
|
+
Write-Host -Object "Trusting the PSGallery to install Pester without -Force"
|
|
373
|
+
Set-PSRepository -Name PSGallery -InstallationPolicy Trusted -ErrorAction SilentlyContinue
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
Write-Host "Installing Pester..."
|
|
377
|
+
$installPesterParams = #{ps_hash(pester_install_params)}
|
|
378
|
+
$installPesterParams['Name'] = 'Pester'
|
|
379
|
+
Install-module @installPesterParams
|
|
380
|
+
Write-Host 'Pester Installed.'
|
|
381
|
+
PS1
|
|
382
|
+
end
|
|
383
|
+
|
|
384
|
+
# returns a piece of PS scriptblock for each Module to install
|
|
385
|
+
# from gallery that has been sepcified in install_modules config.
|
|
386
|
+
#
|
|
387
|
+
# @return [Array<String>] array of PS commands.
|
|
388
|
+
# @api private
|
|
389
|
+
def install_modules_from_gallery
|
|
390
|
+
return if config[:install_modules].nil?
|
|
391
|
+
|
|
392
|
+
Array(config[:install_modules]).map do |powershell_module|
|
|
393
|
+
if powershell_module.is_a? Hash
|
|
394
|
+
# Sanitize variable name so that $powershell-yaml becomes $powershell_yaml
|
|
395
|
+
module_name = powershell_module[:Name].gsub(/[\W]/, "_")
|
|
396
|
+
# so we can splat that variable to install module
|
|
397
|
+
<<-PS1
|
|
398
|
+
$#{module_name} = #{ps_hash(powershell_module)}
|
|
399
|
+
Write-Host -NoNewline 'Installing #{module_name}'
|
|
400
|
+
Install-Module @#{module_name}
|
|
401
|
+
Write-host '... done.'
|
|
402
|
+
PS1
|
|
403
|
+
else
|
|
404
|
+
<<-PS1
|
|
405
|
+
Write-host -NoNewline 'Installing #{powershell_module} ...'
|
|
406
|
+
Install-Module -Name '#{powershell_module}'
|
|
407
|
+
Write-host '... done.'
|
|
408
|
+
PS1
|
|
409
|
+
end
|
|
410
|
+
end
|
|
152
411
|
end
|
|
153
412
|
|
|
154
413
|
def really_wrap_shell_code(code)
|
|
155
|
-
|
|
414
|
+
windows_os? ? really_wrap_windows_shell_code(code) : really_wrap_posix_shell_code(code)
|
|
156
415
|
end
|
|
157
416
|
|
|
158
|
-
|
|
159
|
-
|
|
417
|
+
# Get the defined shell or fall back to pwsh, unless we're on windows where we use powershell
|
|
418
|
+
# call via sudo if sudo is true.
|
|
419
|
+
# This allows to use pwsh-preview instead of pwsh, or a full path to a specific binary.
|
|
420
|
+
def shell_cmd
|
|
421
|
+
if !config[:shell].nil?
|
|
422
|
+
config[:sudo] ? "sudo #{config[:shell]}" : "#{config[:shell]}"
|
|
423
|
+
elsif windows_os?
|
|
424
|
+
"powershell"
|
|
425
|
+
else
|
|
426
|
+
config[:sudo] ? "sudo pwsh" : "pwsh"
|
|
427
|
+
end
|
|
428
|
+
end
|
|
429
|
+
|
|
430
|
+
def really_wrap_windows_shell_code(code)
|
|
431
|
+
my_command = <<-PWSH
|
|
432
|
+
echo "Running as '$(whoami)'..."
|
|
433
|
+
New-Item -ItemType Directory -Path '#{config[:root_path]}/modules' -Force -ErrorAction SilentlyContinue
|
|
434
|
+
Set-Location -Path "#{config[:root_path]}"
|
|
435
|
+
# Send the pwsh here string to the file kitchen_cmd.ps1
|
|
436
|
+
@'
|
|
160
437
|
try {
|
|
161
438
|
Set-ExecutionPolicy Unrestricted -force
|
|
162
439
|
}
|
|
163
440
|
catch {
|
|
164
441
|
$_ | Out-String | Write-Warning
|
|
165
442
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
#
|
|
171
|
-
|
|
443
|
+
#{Util.outdent!(use_local_powershell_modules(code))}
|
|
444
|
+
'@ | Set-Content -Path kitchen_cmd.ps1 -Encoding utf8 -Force -ErrorAction 'Stop'
|
|
445
|
+
# create the modules folder, making sure it's done as current user (not root)
|
|
446
|
+
#
|
|
447
|
+
# Invoke the created kitchen_cmd.ps1 file using pwsh
|
|
448
|
+
#{shell_cmd} ./kitchen_cmd.ps1
|
|
449
|
+
PWSH
|
|
450
|
+
wrap_shell_code(Util.outdent!(my_command))
|
|
172
451
|
end
|
|
173
452
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
453
|
+
# Writing the command to a ps1 file, adding the pwsh shebang
|
|
454
|
+
# invoke the file
|
|
455
|
+
def really_wrap_posix_shell_code(code)
|
|
456
|
+
my_command = <<-BASH
|
|
457
|
+
echo "Running as '$(whoami)'"
|
|
458
|
+
# create the modules folder, making sure it's done as current user (not root)
|
|
459
|
+
mkdir -p #{config[:root_path]}/modules
|
|
460
|
+
cd #{config[:root_path]}
|
|
461
|
+
# Send the bash heredoc 'EOF' to the file kitchen_cmd.ps1 using the tool cat
|
|
462
|
+
cat << 'EOF' > kitchen_cmd.ps1
|
|
463
|
+
#!/usr/bin/env pwsh
|
|
464
|
+
#{Util.outdent!(use_local_powershell_modules(code))}
|
|
465
|
+
EOF
|
|
466
|
+
chmod +x kitchen_cmd.ps1
|
|
467
|
+
# Invoke the created kitchen_cmd.ps1 file using pwsh
|
|
468
|
+
#{shell_cmd} ./kitchen_cmd.ps1
|
|
469
|
+
BASH
|
|
470
|
+
|
|
471
|
+
debug(Util.outdent!(my_command))
|
|
472
|
+
Util.outdent!(my_command)
|
|
473
|
+
end
|
|
188
474
|
|
|
189
|
-
|
|
475
|
+
def use_local_powershell_modules(script)
|
|
476
|
+
<<-PS1
|
|
477
|
+
Write-Host -Object ("{0} - PowerShell {1}" -f $PSVersionTable.OS,$PSVersionTable.PSVersion)
|
|
478
|
+
$global:ProgressPreference = 'SilentlyContinue'
|
|
479
|
+
$PSModPathToPrepend = Join-Path "#{config[:root_path]}" -ChildPath 'modules'
|
|
480
|
+
Write-Verbose "Adding '$PSModPathToPrepend' to `$Env:PSModulePath."
|
|
481
|
+
if (!$isLinux -and -not (Test-Path -Path $PSModPathToPrepend)) {
|
|
482
|
+
# if you create this folder now in Linux, it may run as root (via sudo).
|
|
483
|
+
$null = New-Item -Path $PSModPathToPrepend -Force -ItemType Directory
|
|
190
484
|
}
|
|
191
485
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
param($Name)
|
|
195
|
-
|
|
196
|
-
@(Get-Module -Name $Name -ListAvailable -ErrorAction SilentlyContinue).Count -gt 0
|
|
486
|
+
if ($Env:PSModulePath.Split([io.path]::PathSeparator) -notcontains $PSModPathToPrepend) {
|
|
487
|
+
$env:PSModulePath = @($PSModPathToPrepend, $env:PSModulePath) -Join [io.path]::PathSeparator
|
|
197
488
|
}
|
|
198
489
|
|
|
199
|
-
|
|
200
|
-
|
|
490
|
+
#{script}
|
|
491
|
+
PS1
|
|
492
|
+
end
|
|
201
493
|
|
|
202
|
-
|
|
494
|
+
def install_command_script
|
|
495
|
+
<<-PS1
|
|
496
|
+
$PSModPathToPrepend = "#{config[:root_path]}"
|
|
203
497
|
|
|
204
|
-
|
|
205
|
-
if (Test-Module -Name PowerShellGet) {
|
|
206
|
-
Import-Module PowerShellGet -Force
|
|
207
|
-
Import-Module PackageManagement -Force
|
|
498
|
+
Import-Module -ErrorAction Stop PesterUtil
|
|
208
499
|
|
|
209
|
-
|
|
500
|
+
#{get_powershell_modules_from_nugetapi.join("\n") unless config.dig(:bootstrap, :modules).nil?}
|
|
210
501
|
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
if (-not (Test-Module -Name PsGet)){
|
|
215
|
-
$webClient = New-Object -TypeName System.Net.WebClient
|
|
216
|
-
|
|
217
|
-
if ($env:HTTP_PROXY){
|
|
218
|
-
if ($env:NO_PROXY){
|
|
219
|
-
Write-Host "Creating WebProxy with 'HTTP_PROXY' and 'NO_PROXY' environment variables.
|
|
220
|
-
$webproxy = New-Object -TypeName System.Net.WebProxy -ArgumentList $env:HTTP_PROXY, $true, $env:NO_PROXY
|
|
221
|
-
}
|
|
222
|
-
else {
|
|
223
|
-
Write-Host "Creating WebProxy with 'HTTP_PROXY' environment variable.
|
|
224
|
-
$webproxy = New-Object -TypeName System.Net.WebProxy -ArgumentList $env:HTTP_PROXY
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
$webClient.Proxy = $webproxy
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
Invoke-Expression -Command $webClient.DownloadString('http://bit.ly/GetPsGet')
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
# If the module isn't already loaded, ensure we can import it.
|
|
235
|
-
if (-not (Get-Module -Name PsGet -ErrorAction SilentlyContinue)) {
|
|
236
|
-
Import-Module -Name PsGet -Force -ErrorAction Stop
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
Install-Module -Name Pester -Force
|
|
240
|
-
}
|
|
241
|
-
catch {
|
|
242
|
-
Write-Host "Installing from Github"
|
|
243
|
-
|
|
244
|
-
$downloadFolder = if (Test-Path "$env:TEMP/PesterDownload") {
|
|
245
|
-
"$env:TEMP/PesterDownload"
|
|
246
|
-
}
|
|
247
|
-
else {
|
|
248
|
-
New-Item -ItemType Directory -Path "$env:TEMP/PesterDownload"
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
$zipFile = Join-Path (Get-Item -Path $downloadFolder).FullName -ChildPath "pester.zip"
|
|
252
|
-
|
|
253
|
-
if (-not (Test-Path $zipfile)) {
|
|
254
|
-
$source = 'https://github.com/pester/Pester/archive/4.10.1.zip'
|
|
255
|
-
$webClient = New-Object -TypeName Net.WebClient
|
|
256
|
-
|
|
257
|
-
if ($env:HTTP_PROXY) {
|
|
258
|
-
if ($env:NO_PROXY) {
|
|
259
|
-
Write-Host "Creating WebProxy with 'HTTP_PROXY' and 'NO_PROXY' environment variables."
|
|
260
|
-
$webproxy = New-Object -TypeName System.Net.WebProxy -ArgumentList $env:HTTP_PROXY, $true, $env:NO_PROXY
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
Write-Host "Creating WebProxy with 'HTTP_PROXY' environment variable."
|
|
264
|
-
$webproxy = New-Object -TypeName System.Net.WebProxy -ArgumentList $env:HTTP_PROXY
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
$webClient.Proxy = $webproxy
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
[IO.File]::WriteAllBytes($zipfile, $webClient.DownloadData($source))
|
|
271
|
-
|
|
272
|
-
[GC]::Collect()
|
|
273
|
-
Write-Host "Downloaded Pester.zip"
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
Write-Host "Creating Shell.Application COM object"
|
|
277
|
-
$shellcom = New-Object -ComObject Shell.Application
|
|
278
|
-
|
|
279
|
-
Write-Host "Creating COM object for zip file."
|
|
280
|
-
$zipcomobject = $shellcom.Namespace($zipfile)
|
|
281
|
-
|
|
282
|
-
Write-Host "Creating COM object for module destination."
|
|
283
|
-
$destination = $shellcom.Namespace($VerifierModulePath)
|
|
284
|
-
|
|
285
|
-
Write-Host "Unpacking zip file."
|
|
286
|
-
$destination.CopyHere($zipcomobject.Items(), 0x610)
|
|
287
|
-
|
|
288
|
-
Rename-Item -Path (Join-Path $VerifierModulePath -ChildPath "Pester-4.10.1") -NewName 'Pester' -Force
|
|
289
|
-
}
|
|
290
|
-
}
|
|
291
|
-
}
|
|
502
|
+
#{register_psrepository_scriptblock.join("\n") unless config[:register_repository].nil?}
|
|
292
503
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
}
|
|
296
|
-
|
|
504
|
+
#{install_pester}
|
|
505
|
+
|
|
506
|
+
#{install_modules_from_gallery.join("\n") unless config[:install_modules].nil?}
|
|
507
|
+
PS1
|
|
297
508
|
end
|
|
298
509
|
|
|
299
510
|
def restart_winrm_service
|
|
511
|
+
return unless verifier.windows_os?
|
|
512
|
+
|
|
300
513
|
cmd = "schtasks /Create /TN restart_winrm /TR " \
|
|
301
514
|
'"powershell -Command Restart-Service winrm" ' \
|
|
302
515
|
"/SC ONCE /ST 00:00 "
|
|
@@ -308,11 +521,15 @@ module Kitchen
|
|
|
308
521
|
end
|
|
309
522
|
|
|
310
523
|
def download_test_files(state)
|
|
311
|
-
|
|
524
|
+
if config[:downloads].nil?
|
|
525
|
+
info("Skipped downloading test result file from #{instance.to_str}; 'downloads' hash is empty.")
|
|
526
|
+
return
|
|
527
|
+
end
|
|
312
528
|
|
|
529
|
+
info("Downloading test result files from #{instance.to_str}")
|
|
313
530
|
instance.transport.connection(state) do |conn|
|
|
314
|
-
config[:downloads].
|
|
315
|
-
debug("
|
|
531
|
+
config[:downloads].each do |remotes, local|
|
|
532
|
+
debug("downloading #{Array(remotes).join(", ")} to #{local}")
|
|
316
533
|
conn.download(remotes, local)
|
|
317
534
|
end
|
|
318
535
|
end
|
|
@@ -326,29 +543,25 @@ module Kitchen
|
|
|
326
543
|
#
|
|
327
544
|
# @return [Array<String>] array of suite files
|
|
328
545
|
# @api private
|
|
329
|
-
|
|
330
546
|
def suite_test_folder
|
|
331
547
|
@suite_test_folder ||= File.join(test_folder, config[:suite_name])
|
|
332
548
|
end
|
|
333
549
|
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
def
|
|
339
|
-
|
|
340
|
-
end
|
|
341
|
-
|
|
342
|
-
def local_suite_files
|
|
343
|
-
suite = suite_level_glob
|
|
344
|
-
suite_verifier = suite_verifier_level_glob
|
|
345
|
-
(suite << suite_verifier).flatten!.reject do |f|
|
|
346
|
-
File.directory?(f)
|
|
347
|
-
end
|
|
550
|
+
# Returns the current file's parent folder's full path.
|
|
551
|
+
#
|
|
552
|
+
# @return [string]
|
|
553
|
+
# @api private
|
|
554
|
+
def script_root
|
|
555
|
+
@script_root ||= File.dirname(__FILE__)
|
|
348
556
|
end
|
|
349
557
|
|
|
350
|
-
|
|
351
|
-
|
|
558
|
+
# Returns the absolute path of the Supporting PS module to
|
|
559
|
+
# be copied to the SUT via the Sandbox.
|
|
560
|
+
#
|
|
561
|
+
# @return [string]
|
|
562
|
+
# @api private
|
|
563
|
+
def support_psmodule_folder
|
|
564
|
+
@support_psmodule_folder ||= Pathname.new(File.join(script_root, "../../support/modules/PesterUtil")).cleanpath
|
|
352
565
|
end
|
|
353
566
|
|
|
354
567
|
# Returns an Array of common helper filenames currently residing on the
|
|
@@ -376,50 +589,128 @@ module Kitchen
|
|
|
376
589
|
end
|
|
377
590
|
end
|
|
378
591
|
|
|
379
|
-
#
|
|
592
|
+
# Creates a PowerShell hashtable from a ruby map.
|
|
593
|
+
# The only types supported for now are hash, array, string and Boolean.
|
|
380
594
|
#
|
|
381
595
|
# @api private
|
|
382
|
-
def
|
|
383
|
-
|
|
596
|
+
def ps_hash(obj, depth = 0)
|
|
597
|
+
if [true, false].include? obj
|
|
598
|
+
%{$#{obj}} # Return $true or $false when value is a bool
|
|
599
|
+
elsif obj.is_a?(Hash)
|
|
600
|
+
obj.map do |k, v|
|
|
601
|
+
# Format "Key = Value" enabling recursion
|
|
602
|
+
%{#{pad(depth + 2)}#{ps_hash(k)} = #{ps_hash(v, depth + 2)}}
|
|
603
|
+
end
|
|
604
|
+
.join("\n") # append \n to the key/value definitions
|
|
605
|
+
.insert(0, "@{\n") # prepend @{\n
|
|
606
|
+
.insert(-1, "\n#{pad(depth)}}\n") # append \n}\n
|
|
607
|
+
|
|
608
|
+
elsif obj.is_a?(Array)
|
|
609
|
+
array_string = obj.map { |v| ps_hash(v, depth + 4) }.join(",")
|
|
610
|
+
"#{pad(depth)}@(\n#{array_string}\n)"
|
|
611
|
+
else
|
|
612
|
+
# When the object is not a string nor a hash or array, it will be quoted as a string.
|
|
613
|
+
# In most cases, PS is smart enough to convert back to the type it needs.
|
|
614
|
+
"'" + obj.to_s + "'"
|
|
615
|
+
end
|
|
616
|
+
end
|
|
384
617
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
618
|
+
# returns the path of the modules subfolder
|
|
619
|
+
# in the sandbox, where PS Modules and folders will be copied to.
|
|
620
|
+
#
|
|
621
|
+
# @api private
|
|
622
|
+
def sandbox_module_path
|
|
623
|
+
File.join(sandbox_path, "modules")
|
|
624
|
+
end
|
|
625
|
+
|
|
626
|
+
# copy files into the 'modules' folder of the sandbox,
|
|
627
|
+
# so that copied folders can be discovered with the updated $Env:PSModulePath.
|
|
628
|
+
#
|
|
629
|
+
# @api private
|
|
630
|
+
def prepare_copy_folders
|
|
631
|
+
return if config[:copy_folders].nil?
|
|
632
|
+
|
|
633
|
+
info("Preparing to copy specified folders to #{sandbox_module_path}.")
|
|
634
|
+
kitchen_root_path = config[:kitchen_root]
|
|
635
|
+
config[:copy_folders].each do |folder|
|
|
636
|
+
debug("copying #{folder}")
|
|
637
|
+
folder_to_copy = File.join(kitchen_root_path, folder)
|
|
638
|
+
copy_if_src_exists(folder_to_copy, sandbox_module_path)
|
|
390
639
|
end
|
|
391
640
|
end
|
|
392
641
|
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
642
|
+
# returns an array of string
|
|
643
|
+
# Creates a flat list of files contained in a folder.
|
|
644
|
+
# This is useful when trying to debug what has been copied to
|
|
645
|
+
# the sandbox.
|
|
646
|
+
#
|
|
647
|
+
# @return [Array<String>] array of files in a folder
|
|
648
|
+
# @api private
|
|
649
|
+
def list_files(path)
|
|
650
|
+
base_directory_content = Dir.glob(File.join(path, "*"))
|
|
651
|
+
nested_directory_content = Dir.glob(File.join(path, "*/**/*"))
|
|
652
|
+
[base_directory_content, nested_directory_content].flatten
|
|
653
|
+
end
|
|
654
|
+
|
|
655
|
+
# Copies all test suite files into the suites directory in the sandbox.
|
|
656
|
+
#
|
|
657
|
+
# @api private
|
|
658
|
+
def prepare_pester_tests
|
|
659
|
+
info("Preparing to copy files from '#{suite_test_folder}' to the SUT.")
|
|
660
|
+
sandboxed_suites_path = File.join(sandbox_path, "suites")
|
|
661
|
+
copy_if_src_exists(suite_test_folder, sandboxed_suites_path)
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
def prepare_supporting_psmodules
|
|
665
|
+
info("Preparing to copy files from '#{support_psmodule_folder}' to the SUT.")
|
|
666
|
+
sandbox_module_path = File.join(sandbox_path, "modules")
|
|
667
|
+
copy_if_src_exists(support_psmodule_folder, sandbox_module_path)
|
|
400
668
|
end
|
|
401
669
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
670
|
+
# Copies a folder recursively preserving its layers,
|
|
671
|
+
# mostly used to copy to the sandbox.
|
|
672
|
+
#
|
|
673
|
+
# @api private
|
|
674
|
+
def copy_if_src_exists(src_to_validate, destination)
|
|
675
|
+
unless Dir.exist?(src_to_validate)
|
|
676
|
+
info("The path #{src_to_validate} was not found. Not copying to #{destination}.")
|
|
677
|
+
return
|
|
678
|
+
end
|
|
679
|
+
|
|
680
|
+
info("Moving #{src_to_validate} to #{destination}")
|
|
681
|
+
unless Dir.exist?(destination)
|
|
682
|
+
FileUtils.mkdir_p(destination)
|
|
683
|
+
debug("Folder '#{destination}' created.")
|
|
406
684
|
end
|
|
685
|
+
FileUtils.mkdir_p(File.join(destination, "__bugfix"))
|
|
686
|
+
FileUtils.cp_r(src_to_validate, destination, preserve: true)
|
|
407
687
|
end
|
|
408
688
|
|
|
689
|
+
# returns the absolute path of the folders containing the
|
|
690
|
+
# test suites, use default if not set.
|
|
691
|
+
#
|
|
692
|
+
# @api private
|
|
409
693
|
def test_folder
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
absolute_test_folder
|
|
694
|
+
config[:test_folder].nil? ? config[:test_base_path] : absolute_test_folder
|
|
413
695
|
end
|
|
414
696
|
|
|
697
|
+
# returns the absolute path of the relative folders containing the
|
|
698
|
+
# test suites, use default i not set.
|
|
699
|
+
#
|
|
700
|
+
# @api private
|
|
415
701
|
def absolute_test_folder
|
|
416
702
|
path = (Pathname.new config[:test_folder]).realpath
|
|
417
703
|
integration_path = File.join(path, "integration")
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
integration_path
|
|
704
|
+
Dir.exist?(integration_path) ? integration_path : path
|
|
421
705
|
end
|
|
422
706
|
|
|
707
|
+
# returns a string of space of the specified depth.
|
|
708
|
+
# This is used to pad messages or when building PS hashtables.
|
|
709
|
+
#
|
|
710
|
+
# @api private
|
|
711
|
+
def pad(depth = 0)
|
|
712
|
+
" " * depth
|
|
713
|
+
end
|
|
423
714
|
end
|
|
424
715
|
end
|
|
425
716
|
end
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
|
|
2
|
+
|
|
3
|
+
function Install-ModuleFromNuget {
|
|
4
|
+
[CmdletBinding()]
|
|
5
|
+
param (
|
|
6
|
+
[hashtable]
|
|
7
|
+
$Module,
|
|
8
|
+
|
|
9
|
+
[string]
|
|
10
|
+
$GalleryUrl = 'https://www.powershellgallery.com/api/v2'
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
$tempPath = [System.IO.Path]::GetTempPath()
|
|
14
|
+
$zipFileName = "{0}.{1}.{2}" -f $Module.Name, $Module.Version, 'zip'
|
|
15
|
+
$downloadedZip = Join-Path -Path $tempPath $zipFileName
|
|
16
|
+
$ModulePath = Join-Path -Path $PSHome -ChildPath 'Modules'
|
|
17
|
+
$ModuleFolder = Join-Path -Path $ModulePath -ChildPath $Module.Name
|
|
18
|
+
|
|
19
|
+
if ((Test-Path $ModuleFolder) -and ($PSVersionTable.PSVersion.Major -lt 5 -or $module.Force)) {
|
|
20
|
+
# Check if available version is correct
|
|
21
|
+
$ModuleManifest = Join-Path -Path $ModuleFolder -ChildPath "$($Module.Name).psd1"
|
|
22
|
+
if ((Test-Path -Path $ModuleManifest) -and -not $Module.Force) {
|
|
23
|
+
# Import-PowerShellDataFile only exists since 5.1
|
|
24
|
+
$ManifestInfo = Import-LocalizedData -BaseDirectory (Split-Path -Parent -Path $ModuleManifest) -FileName $Module.Name
|
|
25
|
+
$ModuleVersionNoPreRelease = $Module.Version -replace '-.*$'
|
|
26
|
+
# Compare the version in manifest with version required without Pre-release
|
|
27
|
+
if ($ManifestInfo.ModuleVersion -eq $ModuleVersionNoPreRelease) {
|
|
28
|
+
Write-Host "Module $($Module.Name) already installed, skipping."
|
|
29
|
+
return
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
Write-Host "Module $($Module.Name) found with version '$($ManifestInfo.ModuleVersion)', expecting '$ModuleVersionNoPreRelease'."
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
# if incorrect, remove it before install
|
|
37
|
+
Remove-Item -Recurse -Force -Path $ModuleFolder
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
elseif ($PSVersionTable.PSVersion.Major -gt 5) {
|
|
41
|
+
# skip if the version already exists or if force is enabled
|
|
42
|
+
$ModuleVersionNoPreRelease = $Module.Version -replace '-.*$'
|
|
43
|
+
$ModuleFolder = Join-Path -Path $ModuleFolder -ChildPath $ModuleVersionNoPreRelease
|
|
44
|
+
if (-not $Module.Force -and (Test-Path -Path $ModuleFolder)) {
|
|
45
|
+
Write-Verbose -Message "Module already installed."
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (-not (Test-Path $ModuleFolder)) {
|
|
51
|
+
$null = New-Item -Path $ModuleFolder -force -ItemType Directory
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
$urlSuffix = "/package/$($Module.Name)/$($Module.Version)".TrimEnd('/')
|
|
55
|
+
$nupkgUrl = $GalleryUrl.TrimEnd('/') + '/' + $urlSuffix.Trim('/')
|
|
56
|
+
$webclient = New-Object 'system.net.webclient'
|
|
57
|
+
|
|
58
|
+
if ($env:HTTP_PROXY){
|
|
59
|
+
if ($env:NO_PROXY){
|
|
60
|
+
Write-Host "Creating WebProxy with 'HTTP_PROXY' and 'NO_PROXY' environment variables."
|
|
61
|
+
$webproxy = New-Object -TypeName System.Net.WebProxy -ArgumentList $env:HTTP_PROXY, $true, $env:NO_PROXY
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
Write-Host "Creating WebProxy with 'HTTP_PROXY' environment variable."
|
|
65
|
+
$webproxy = New-Object -TypeName System.Net.WebProxy -ArgumentList $env:HTTP_PROXY
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
$webclient.Proxy = $webproxy
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
Write-Verbose -Message "Downloading Package from $nupkgUrl"
|
|
72
|
+
try {
|
|
73
|
+
if (Test-Path $downloadedZip) {
|
|
74
|
+
Remove-Item -Force -ErrorAction SilentlyContinue -Path $downloadedZip
|
|
75
|
+
}
|
|
76
|
+
$webclient.DownloadFile($nupkgUrl, $downloadedZip)
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
Write-Error "Error trying to download nupkg '$nupkgUrl' to '$downloadedZip'."
|
|
80
|
+
throw $_
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (-not (Test-Path -Path $downloadedZip)) {
|
|
84
|
+
throw "Error trying to download nupkg '$nupkgUrl' to '$downloadedZip'."
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
# Test to see if Expand-Archive is available first
|
|
88
|
+
if (Get-Command Expand-Archive) {
|
|
89
|
+
Expand-Archive -Path $downloadedZip -DestinationPath $ModuleFolder -Force
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
# Fall back to COM object for Shell.Application zip extraction
|
|
93
|
+
Write-Host "Creating COM object for zip file '$downloadedZip'."
|
|
94
|
+
$shellcom = New-Object -ComObject Shell.Application
|
|
95
|
+
$zipcomobject = $shellcom.Namespace($downloadedZip)
|
|
96
|
+
$destination = $shellcom.Namespace($ModuleFolder)
|
|
97
|
+
$destination.CopyHere($zipcomobject.Items(), 0x610)
|
|
98
|
+
Write-Host "Nupkg installed at $ModuleFolder"
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
[GC]::Collect()
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function Set-PSRepo {
|
|
105
|
+
param(
|
|
106
|
+
[Parameter(Mandatory)]
|
|
107
|
+
$Repository
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
if (-not (Get-Command Get-PSRepository) -and (Get-Command Get-PackageSource)) {
|
|
111
|
+
# Old versions of PSGet do not have a *-PSrepository but have *-PackageSource instead.
|
|
112
|
+
if (Get-PackageSource -Name $Repository.Name) {
|
|
113
|
+
Set-PackageSource @Repository
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
Register-PackageSource @Repository
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
elseif (Get-Command Get-PSRepository) {
|
|
120
|
+
if (Get-PSRepository -Name $Repository.Name -ErrorAction SilentlyContinue) {
|
|
121
|
+
# The repo exists, we should use Set-PSRepository and splat parameters
|
|
122
|
+
Set-PSRepository @Repository
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
# The repo does not exist, use Register-PSRepository and splat
|
|
126
|
+
Register-PSRepository @Repository
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
throw "Cannot Set PS Repository, command Set or Register for PSRepository or PackageSource not found."
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function ConvertFrom-PesterOutputObject {
|
|
135
|
+
param (
|
|
136
|
+
[parameter(ValueFromPipeline=$true)]
|
|
137
|
+
[object]
|
|
138
|
+
$InputObject
|
|
139
|
+
)
|
|
140
|
+
begin {
|
|
141
|
+
$PesterModule = Import-Module Pester -Passthru
|
|
142
|
+
}
|
|
143
|
+
process {
|
|
144
|
+
$DescribeGroup = $InputObject.testresult | Group-Object Describe
|
|
145
|
+
foreach ($DescribeBlock in $DescribeGroup) {
|
|
146
|
+
$PesterModule.Invoke({Write-Screen $args[0]}, "Describing $($DescribeBlock.Name)")
|
|
147
|
+
$ContextGroup = $DescribeBlock.group | Group-Object Context
|
|
148
|
+
foreach ($ContextBlock in $ContextGroup) {
|
|
149
|
+
$PesterModule.Invoke({Write-Screen $args[0]}, "`tContext $($subheader.name)")
|
|
150
|
+
foreach ($TestResult in $ContextBlock.group) {
|
|
151
|
+
$PesterModule.Invoke({Write-PesterResult $args[0]}, $TestResult)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
$PesterModule.Invoke({Write-PesterReport $args[0]}, $InputObject)
|
|
157
|
+
}
|
|
158
|
+
}
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kitchen-pester
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Steven Murawski
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-07-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -81,7 +81,7 @@ dependencies:
|
|
|
81
81
|
version: '1.10'
|
|
82
82
|
- - "<"
|
|
83
83
|
- !ruby/object:Gem::Version
|
|
84
|
-
version: '
|
|
84
|
+
version: '4'
|
|
85
85
|
type: :runtime
|
|
86
86
|
prerelease: false
|
|
87
87
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -91,7 +91,7 @@ dependencies:
|
|
|
91
91
|
version: '1.10'
|
|
92
92
|
- - "<"
|
|
93
93
|
- !ruby/object:Gem::Version
|
|
94
|
-
version: '
|
|
94
|
+
version: '4'
|
|
95
95
|
description: Skip all that Busser stuff and jump right into Pester.
|
|
96
96
|
email:
|
|
97
97
|
- steven.murawski@gmail.com
|
|
@@ -105,12 +105,12 @@ files:
|
|
|
105
105
|
- kitchen-pester.gemspec
|
|
106
106
|
- lib/kitchen/verifier/pester.rb
|
|
107
107
|
- lib/kitchen/verifier/pester_version.rb
|
|
108
|
-
- lib/support/
|
|
108
|
+
- lib/support/modules/PesterUtil/PesterUtil.psm1
|
|
109
109
|
homepage: https://github.com/test-kitchen/kitchen-pester
|
|
110
110
|
licenses:
|
|
111
111
|
- Apache-2.0
|
|
112
112
|
metadata: {}
|
|
113
|
-
post_install_message:
|
|
113
|
+
post_install_message:
|
|
114
114
|
rdoc_options: []
|
|
115
115
|
require_paths:
|
|
116
116
|
- lib
|
|
@@ -126,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
126
126
|
version: '0'
|
|
127
127
|
requirements: []
|
|
128
128
|
rubygems_version: 3.0.6
|
|
129
|
-
signing_key:
|
|
129
|
+
signing_key:
|
|
130
130
|
specification_version: 4
|
|
131
131
|
summary: Test-Kitchen verifier for Pester.
|
|
132
132
|
test_files: []
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
function ConvertFrom-PesterOutputObject {
|
|
2
|
-
param (
|
|
3
|
-
[parameter(ValueFromPipeline=$true)]
|
|
4
|
-
[object]
|
|
5
|
-
$InputObject
|
|
6
|
-
)
|
|
7
|
-
begin {
|
|
8
|
-
$PesterModule = Import-Module Pester -Passthru
|
|
9
|
-
}
|
|
10
|
-
process {
|
|
11
|
-
$DescribeGroup = $InputObject.testresult | Group-Object Describe
|
|
12
|
-
foreach ($DescribeBlock in $DescribeGroup) {
|
|
13
|
-
$PesterModule.Invoke({Write-Screen $args[0]}, "Describing $($DescribeBlock.Name)")
|
|
14
|
-
$ContextGroup = $DescribeBlock.group | Group-Object Context
|
|
15
|
-
foreach ($ContextBlock in $ContextGroup) {
|
|
16
|
-
$PesterModule.Invoke({Write-Screen $args[0]}, "`tContext $($subheader.name)")
|
|
17
|
-
foreach ($TestResult in $ContextBlock.group) {
|
|
18
|
-
$PesterModule.Invoke({Write-PesterResult $args[0]}, $TestResult)
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
$PesterModule.Invoke({Write-PesterReport $args[0]}, $InputObject)
|
|
23
|
-
}
|
|
24
|
-
}
|