From ff0c22e2699a01fba6708ea688a4c5e9cb38001d Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Fri, 22 Nov 2019 14:59:58 -0800 Subject: [PATCH] Fixed: Whiskey fails to fail a build when certain PowerShell terminating errors are thrown. --- Test/Invoke-WhiskeyBuild.Tests.ps1 | 107 ++++++++++++++++++++++ Test/WhiskeyTest.psm1 | 4 +- Test/WhiskeyTestTasks.psm1 | 43 ++++++++- Whiskey/Functions/Invoke-WhiskeyBuild.ps1 | 9 ++ Whiskey/Whiskey.psd1 | 1 + build.ps1 | 2 + 6 files changed, 162 insertions(+), 4 deletions(-) diff --git a/Test/Invoke-WhiskeyBuild.Tests.ps1 b/Test/Invoke-WhiskeyBuild.Tests.ps1 index c739213b..d49e177b 100644 --- a/Test/Invoke-WhiskeyBuild.Tests.ps1 +++ b/Test/Invoke-WhiskeyBuild.Tests.ps1 @@ -17,6 +17,8 @@ $publishPipelineName = 'Publish' function Init { + $Global:Error.Clear() + [Whiskey.Context]$script:context = $null $script:runByDeveloper = $false $script:runByBuildServer = $false @@ -140,6 +142,20 @@ function GivenWhiskeyYml $Content | Set-Content -Path (Join-Path $testRoot -ChildPath 'whiskey.yml') } + +function ThenBuildFailed +{ + param( + $WithErrorMessage + ) + + $threwException | Should -BeTrue + if( $WithErrorMessage ) + { + $Global:Error | Select-Object -First 1 | Should -Match $WithErrorMessage + } +} + function ThenBuildOutputRemoved { It ('should remove .output directory') { @@ -359,6 +375,35 @@ function WhenRunningBuild } } +function WhenRunningBuildFromBuildPs1 +{ + [CmdletBinding()] + param( + ) + + $script:threwException = $false + $buildPs1Path = Join-Path $testRoot -ChildPath 'build.ps1' + @" +Set-Location -Path "$($testRoot)" +Import-Module -Name "$(Join-Path -Path $PSScriptRoot -ChildPath '..\Whiskey' -Resolve)" +Import-Module -Name "$(Join-Path -Path $PSScriptRoot -ChildPath 'WhiskeyTestTasks.psm1' -Resolve)" +`$context = New-WhiskeyContext -Environment Verification -ConfigurationPath '.\whiskey.yml' +Invoke-WhiskeyBuild -Context `$context +New-Item -Path 'passed' +"@ | Set-Content -Path $buildPs1Path + + # PowerShell's error handling is very different between starting a build from a build.ps1 script vs. a Pester test + # calling Invoke-WhiskeyBuild. + Start-Job -ScriptBlock { + & $using:buildPs1Path + } | Receive-Job -Wait -AutoRemoveJob + + if( -not (Test-Path -Path (Join-Path -Path $testRoot -ChildPath 'passed') ) ) + { + $script:threwException = $true + } +} + Describe 'Invoke-WhiskeyBuild.when build passes' { Context 'By Developer' { Init @@ -543,3 +588,65 @@ Build: $infos | Where-Object { $_ -match 'InformationPreference\ enabled!' } | Should -BeNullOrEmpty } } + +Describe 'Invoke-WhiskeyBuild.when task violates a strict mode rule' { + It 'should fail the build' { + Init + GivenWhiskeyYml @' +Build: +- Version: + Version: 0.0.0 +- SetStrictModeViolationTask +'@ + WhenRunningBuildFromBuildPs1 -ErrorAction SilentlyContinue + ThenBuildFailed -WithErrorMessage 'Build\ failed\.' + $Global:Error[1] | Should -Match 'has\ not\ been\ set' + } +} + +Describe 'Invoke-WhiskeyBuild.when task invokes a command that doesn''t exist' { + It 'should fail the build' { + Init + GivenWhiskeyYml @' +Build: +- Version: + Version: 0.0.0 +- CommandNotFoundTask +'@ + WhenRunningBuildFromBuildPs1 -ErrorAction SilentlyContinue + ThenBuildFailed -WithErrorMessage 'Build\ failed.' + $Global:Error[1] | Should -Match 'is\ not\ recognized' + } +} + +Describe 'Invoke-WhiskeyBuild.when task fails' { + It 'should fail the build' { + Init + GivenWhiskeyYml @' +Build: +- Version: + Version: 0.0.0 +- FailingTask: + Message: fdsafjkfsdafjdsf +'@ + WhenRunningBuildFromBuildPs1 -ErrorAction SilentlyContinue + ThenBuildFailed -WithErrorMessage '\bfdsafjkfsdafjdsf\b' + $Global:Error | Should -Not -Match 'Build\ failed\.' + } +} + +Describe 'Invoke-WhiskeyBuild.when cmdlet fails because ErrorAction is Stop' { + It 'should fail the build' { + Init + GivenWhiskeyYml @' +Build: +- Version: + Version: 0.0.0 +- CmdletErrorActionStopTask: + Path: ruirwemdsfirewmk +'@ + WhenRunningBuildFromBuildPs1 -ErrorAction SilentlyContinue + ThenBuildFailed -WithErrorMessage '\bruirwemdsfirewmk\b' + $Global:Error | Should -Not -Match 'Build\ failed\.' + } +} diff --git a/Test/WhiskeyTest.psm1 b/Test/WhiskeyTest.psm1 index ceae513f..5d56a3f1 100644 --- a/Test/WhiskeyTest.psm1 +++ b/Test/WhiskeyTest.psm1 @@ -1,4 +1,6 @@ +$PSModulesDirectoryName = 'PSModules' + $exportPlatformVars = $false if( -not (Get-Variable -Name 'IsLinux' -ErrorAction Ignore) ) { @@ -670,8 +672,6 @@ if( $IsWindows ) $FailureCommandScriptBlock = { cmd /c exit 1 } } -$PSModulesDirectoryName = 'PSModules' - $variablesToExport = & { 'WhiskeyTestDownloadCachePath' 'SuccessCommandScriptBlock' diff --git a/Test/WhiskeyTestTasks.psm1 b/Test/WhiskeyTestTasks.psm1 index 3b301680..e6ebc3a0 100644 --- a/Test/WhiskeyTestTasks.psm1 +++ b/Test/WhiskeyTestTasks.psm1 @@ -50,6 +50,7 @@ function Clear-LastTaskBoundParameter { $script:lastTaskBoundParameters = $null } + function DuplicateAliasTask1 { [Whiskey.Task('DuplicateAliasTask1',Aliases=('DuplicateAliasTask'),WarnWhenUsingAlias)] @@ -91,10 +92,11 @@ function FailingTask [Whiskey.Task('FailingTask')] param( [Whiskey.Context]$TaskContext, - [hashtable]$TaskParameter + [hashtable]$TaskParameter, + $Message = 'Failed!' ) - Stop-WhiskeyTask -TaskContext $TaskContext -Message 'Failed!' + Stop-WhiskeyTask -TaskContext $TaskContext -Message $Message } function Get-LastTaskBoundParameter @@ -399,3 +401,40 @@ function WrapsNoOpTask Invoke-WhiskeyTask -TaskContext $TaskContext -Parameter $TaskParameter -Name 'NoOpTask' } + +function SetStrictModeViolationTask +{ + [Whiskey.Task('SetStrictModeViolationTask')] + [CmdletBinding()] + param( + ) + + Set-StrictMode -Version 'Latest' + $ErrorActionPreference = 'Stop' + + Write-Verbose ($fdsocvxkljewqrjfdslk) +} + +function CommandNotFoundTask +{ + [Whiskey.Task('CommandNotFoundTask')] + [CmdletBinding()] + param( + ) + + Set-StrictMode -Version 'Latest' + $ErrorActionPreference = 'Stop' + + Invoke-SomeCommandfdfdsjkfsdaourewfsdrewmkl +} + +function CmdletErrorActionStopTask +{ + [Whiskey.Task('CmdletErrorActionStopTask')] + [CmdletBinding()] + param( + $Path = '4lkdfmlfu9jdsfkj09' + ) + + Resolve-Path $Path -ErrorAction Stop +} \ No newline at end of file diff --git a/Whiskey/Functions/Invoke-WhiskeyBuild.ps1 b/Whiskey/Functions/Invoke-WhiskeyBuild.ps1 index ae766ca5..41443176 100644 --- a/Whiskey/Functions/Invoke-WhiskeyBuild.ps1 +++ b/Whiskey/Functions/Invoke-WhiskeyBuild.ps1 @@ -151,4 +151,13 @@ function Invoke-WhiskeyBuild $env:PSModulePath = $originalPSModulesPath } + + # There are some errors (strict mode validation failures, command not found errors, etc.) that stop a build, but + # even though ErrorActionPreference is Stop, it doesn't stop the current process, which is what causes a build to + # fail the build. If we get here, and the build didn't succeed, we've encountered one of those errors. Throw a + # guaranteed terminating error. + if( -not $succeeded ) + { + Write-Error -Message ('Build failed. See previous error output for more information.') -ErrorAction Stop + } } diff --git a/Whiskey/Whiskey.psd1 b/Whiskey/Whiskey.psd1 index 23dc7ada..1f6a895e 100644 --- a/Whiskey/Whiskey.psd1 +++ b/Whiskey/Whiskey.psd1 @@ -162,6 +162,7 @@ * The `GetPowerShellModule` task now supports installing prerelease versions of modules. Set the `AllowPrerelease` property to `true`. * The `GetPowerShellModule` task can now install a module into a custom directory instead of the PSModules directory. Pass the path to the `Path` parameter. * The `GetPowerShellModule` task can now import the module being installed. Set the `Import` property to `true`. +* Fixed: Whiskey fails to fail a build when certain PowerShell terminating errors are thrown (i.e. strict mode violations, command not found error, etc.). '@ } # End of PSData hashtable diff --git a/build.ps1 b/build.ps1 index a8ad88cd..e790065d 100644 --- a/build.ps1 +++ b/build.ps1 @@ -199,6 +199,8 @@ foreach( $assembly in (Get-ChildItem -Path $whiskeyOutBinPath -Filter '*.dll') ) Copy-Item -Path $assembly.FullName -Destination $whiskeyBinPath } +$ErrorActionPreference = 'Continue' + & (Join-Path -Path $PSScriptRoot -ChildPath 'Whiskey\Import-Whiskey.ps1' -Resolve) $configPath = Join-Path -Path $PSScriptRoot -ChildPath 'whiskey.yml' -Resolve