diff --git a/src/PSModuleUtils.psd1 b/src/PSModuleUtils.psd1 index 87e4826..d383b2a 100644 --- a/src/PSModuleUtils.psd1 +++ b/src/PSModuleUtils.psd1 @@ -1,6 +1,6 @@ @{ RootModule = 'PSModuleUtils.psm1' - ModuleVersion = '3.1.0' + ModuleVersion = '3.2.0' GUID = '3c63c38f-c32c-4837-a6fa-0b456f4099ce' Author = '' CompanyName = '' diff --git a/src/Public/Invoke-PSModuleAnalyzer.ps1 b/src/Public/Invoke-PSModuleAnalyzer.ps1 index 952d484..60dca31 100644 --- a/src/Public/Invoke-PSModuleAnalyzer.ps1 +++ b/src/Public/Invoke-PSModuleAnalyzer.ps1 @@ -24,6 +24,11 @@ command needs to process the diagnostics, such as converting them to SARIF. Analyzes only what SourceDirectory itself matches instead of descending into subdirectories. Use with a wildcard to keep a subtree with different rules, such as a tests folder, out of the run. +.PARAMETER ErrorOnFinding +Throws when the analyzer reports anything, rather than setting the process exit code. Required to +gate a script that analyzes more than one path: PSScriptAnalyzer's exit code is last-writer-wins and +does not stop the caller, so a clean pass after a failing one leaves the run reporting success. + .OUTPUTS Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord @@ -33,6 +38,9 @@ Invoke-PSModuleAnalyzer -SourceDirectory $PWD/src -Fix .EXAMPLE Invoke-PSModuleAnalyzer -SourceDirectory $PWD/scripts/*.ps1 -NoRecurse +.EXAMPLE +Invoke-PSModuleAnalyzer -SourceDirectory $PWD/tests -ErrorOnFinding + .NOTES N/A #> @@ -44,7 +52,8 @@ function Invoke-PSModuleAnalyzer { [String]$Settings = (Get-PSModuleAnalyzerSettingsPath -CallerScriptRoot $PSScriptRoot), [Switch]$Fix, [Switch]$NoExit, - [Switch]$NoRecurse + [Switch]$NoRecurse, + [Switch]$ErrorOnFinding ) $scriptAnalyzerArgs = @{ @@ -52,7 +61,7 @@ function Invoke-PSModuleAnalyzer { Settings = $Settings Recurse = (-not $NoRecurse) Severity = 'Error', 'Warning', 'Information' - EnableExit = (-not $Fix -and -not $NoExit) + EnableExit = (-not $Fix -and -not $NoExit -and -not $ErrorOnFinding) ReportSummary = $true ErrorAction = 'Stop' } @@ -61,8 +70,21 @@ function Invoke-PSModuleAnalyzer { $scriptAnalyzerArgs.Fix = $true } - # After PSScriptAnalyzer fixes recursive PSUseCorrectCasing command metadata resolution, uncomment this call - # and remove the private workaround and its tests. - # Invoke-ScriptAnalyzer @scriptAnalyzerArgs - Invoke-PSModuleAnalyzerCasingWorkaround @scriptAnalyzerArgs + # After PSScriptAnalyzer fixes recursive PSUseCorrectCasing command metadata resolution, uncomment + # these calls and remove the private workaround and its tests. + if ($ErrorOnFinding) { + # $diagnostics = @(Invoke-ScriptAnalyzer @scriptAnalyzerArgs) + $diagnostics = @(Invoke-PSModuleAnalyzerCasingWorkaround @scriptAnalyzerArgs) + + if ($diagnostics) { + # Written to the host as well as thrown: the throw discards the records, and a count on its + # own does not say what to fix. + Write-Host -Object ($diagnostics | Format-Table -AutoSize | Out-String -Width 200) + throw "$($diagnostics.Count) rule violation(s) found in '$SourceDirectory'." + } + } + else { + # Invoke-ScriptAnalyzer @scriptAnalyzerArgs + Invoke-PSModuleAnalyzerCasingWorkaround @scriptAnalyzerArgs + } } diff --git a/tests/Invoke-PSModuleAnalyzer.Tests.ps1 b/tests/Invoke-PSModuleAnalyzer.Tests.ps1 index 71317e0..6492fe7 100644 --- a/tests/Invoke-PSModuleAnalyzer.Tests.ps1 +++ b/tests/Invoke-PSModuleAnalyzer.Tests.ps1 @@ -112,6 +112,32 @@ Describe 'Unit Tests' -Tag 'Unit' { $topOnlyFindings.ScriptName | Should -Not -Contain 'Alias.ps1' } + It 'should not set the analyzer exit code when ErrorOnFinding is set' { + Mock Invoke-PSModuleAnalyzerCasingWorkaround {} + + Invoke-PSModuleAnalyzer -SourceDirectory $TestDrive -ErrorOnFinding + + Should -Invoke Invoke-PSModuleAnalyzerCasingWorkaround -Exactly -Times 1 -ParameterFilter { + $EnableExit -eq $false + } + } + + It 'should throw naming the count and the path when ErrorOnFinding finds something' { + $fixtureDir = Join-Path -Path $TestDrive -ChildPath 'ErrorOnFindingFixture' + New-Item -ItemType Directory -Path $fixtureDir -Force | Out-Null + 'function Get-Aliased { gci }' | Set-Content -Path "$fixtureDir/Aliased.ps1" -Encoding utf8 + + { Invoke-PSModuleAnalyzer -SourceDirectory $fixtureDir -ErrorOnFinding } | + Should -Throw '*rule violation(s) found in*ErrorOnFindingFixture*' + } + + It 'should stay silent when ErrorOnFinding has nothing to report' { + $fixtureDir = Join-Path -Path $TestDrive -ChildPath 'ErrorOnFindingCleanFixture' + New-Item -ItemType Directory -Path $fixtureDir -Force | Out-Null + + { Invoke-PSModuleAnalyzer -SourceDirectory $fixtureDir -ErrorOnFinding } | Should -Not -Throw + } + It 'should preserve nested parentheses containing function definitions in fix mode' { $fixtureDir = Join-Path -Path $TestDrive -ChildPath 'IndentationFixture' New-Item -ItemType Directory -Path $fixtureDir -Force | Out-Null