From 3f550c0746cca4c45009d305f9afddb9cfd33cfa Mon Sep 17 00:00:00 2001 From: Bernie White Date: Fri, 7 Jun 2019 21:11:19 +1000 Subject: [PATCH] Fix for path space and exporting of recommend keyword #168 #171 (#172) * Fix handling of spaces in rule paths #168 * Export Recommend and Hint #171 * Improve tests for exports --- CHANGELOG.md | 3 ++ src/PSRule/Host/HostHelper.cs | 2 +- src/PSRule/PSRule.psd1 | 7 +-- src/PSRule/PSRule.psm1 | 13 ++--- tests/PSRule.Tests/PSRule.Common.Tests.ps1 | 49 ++++++++++++++++--- tests/PSRule.Tests/PSRule.PSGallery.Tests.ps1 | 33 +++++++++++-- 6 files changed, 88 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 611552fa11..f9f9160ee8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ ## Unreleased +- Fix discovery of rules within paths that contain spaces fails. [#168](https://github.com/BernieWhite/PSRule/issues/168) +- Fix exporting of `Recommend` keyword and `Hint` alias. [#171](https://github.com/BernieWhite/PSRule/issues/171) + ## v0.6.0-B190627 (pre-release) - **Important change**: Changed `Hint` keyword to `Recommend` to align with rule documentation. [#165](https://github.com/BernieWhite/PSRule/issues/165) diff --git a/src/PSRule/Host/HostHelper.cs b/src/PSRule/Host/HostHelper.cs index eb779cd5e8..a64287f8d7 100644 --- a/src/PSRule/Host/HostHelper.cs +++ b/src/PSRule/Host/HostHelper.cs @@ -115,7 +115,7 @@ private static IEnumerable GetLanguageBlock(RuleSource[] sources //PipelineContext.CurrentThread.UseSource(source: source); // Invoke script - ps.AddScript(source.Path, true); + ps.AddScript(string.Concat("& '", source.Path, "'"), true); var invokeResults = ps.Invoke(); if (ps.HadErrors) diff --git a/src/PSRule/PSRule.psd1 b/src/PSRule/PSRule.psd1 index 3616807c15..2c8cee3c29 100644 --- a/src/PSRule/PSRule.psd1 +++ b/src/PSRule/PSRule.psd1 @@ -85,7 +85,7 @@ FunctionsToExport = @( 'Match' 'TypeOf' 'Within' - 'Hint' + 'Recommend' ) # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. @@ -99,7 +99,9 @@ VariablesToExport = @( ) # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. -AliasesToExport = @() +AliasesToExport = @( + 'Hint' +) # DSC resources to export from this module # DscResourcesToExport = @() @@ -112,7 +114,6 @@ AliasesToExport = @() # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. PrivateData = @{ - PSData = @{ # Tags applied to this module. These help with module discovery in online galleries. diff --git a/src/PSRule/PSRule.psm1 b/src/PSRule/PSRule.psm1 index 3ff6d65e5f..b0c86e817a 100644 --- a/src/PSRule/PSRule.psm1 +++ b/src/PSRule/PSRule.psm1 @@ -528,7 +528,7 @@ function Get-PSRuleHelp { if ($Online -and $result.Length -eq 1) { $launchUri = $result.GetOnlineHelpUri(); - + if ($Null -ne $launchUri) { Write-Verbose -Message "[Get-PSRuleHelp] -- Launching online version: $($launchUri.OriginalString)"; LaunchOnlineHelp -Uri $launchUri -Verbose:$VerbosePreference; @@ -604,7 +604,7 @@ function New-PSRuleOption { [Parameter(Mandatory = $False)] [Alias('ExecutionInconclusiveWarning')] [System.Boolean]$InconclusiveWarning = $True, - + # Sets the Execution.NotProcessedWarning option [Parameter(Mandatory = $False)] [Alias('ExecutionNotProcessedWarning')] @@ -758,7 +758,7 @@ function Set-PSRuleOption { [Parameter(Mandatory = $False)] [Alias('ExecutionInconclusiveWarning')] [System.Boolean]$InconclusiveWarning = $True, - + # Sets the Execution.NotProcessedWarning option [Parameter(Mandatory = $False)] [Alias('ExecutionNotProcessedWarning')] @@ -1218,7 +1218,7 @@ function SetOptions { [Parameter(Mandatory = $False)] [Alias('ExecutionInconclusiveWarning')] [System.Boolean]$InconclusiveWarning = $True, - + # Sets the Execution.NotProcessedWarning option [Parameter(Mandatory = $False)] [Alias('ExecutionNotProcessedWarning')] @@ -1377,6 +1377,7 @@ function LaunchOnlineHelp { } function InitEditorServices { + [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalAliases', '', Justification = 'Alias is used for editor discovery only.', Scope = 'Function')] [CmdletBinding()] param () @@ -1393,8 +1394,8 @@ function InitEditorServices { 'Recommend' ); - New-Alias -Name 'Hint' -Value 'Recommend' -Force; - + # Define aliases + $Null = New-Alias -Name Hint -Value Recommend -Scope Global -Force; Export-ModuleMember -Alias @( 'Hint' ); diff --git a/tests/PSRule.Tests/PSRule.Common.Tests.ps1 b/tests/PSRule.Tests/PSRule.Common.Tests.ps1 index eb68b6d3f6..21c3d55fbb 100644 --- a/tests/PSRule.Tests/PSRule.Common.Tests.ps1 +++ b/tests/PSRule.Tests/PSRule.Common.Tests.ps1 @@ -842,8 +842,41 @@ Describe 'Get-PSRule' -Tag 'Get-PSRule','Common' { } Context 'Using -Module' { + $testModuleSourcePath = Join-Path $here -ChildPath 'TestModule'; + It 'Returns module rules' { - $Null = Import-Module (Join-Path $here -ChildPath 'TestModule'); + $Null = Import-Module $testModuleSourcePath -Force; + $result = @(Get-PSRule -Module 'TestModule' -Culture 'en-US'); + $result | Should -Not -BeNullOrEmpty; + $result.Length | Should -Be 2; + $result[0].RuleName | Should -Be 'M1.Rule1'; + $result[0].Description | Should -Be 'Synopsis en-US.'; + $result[0].Info.Annotations.culture | Should -Be 'en-US'; + } + + if ($Null -ne (Get-Module -Name TestModule -ErrorAction SilentlyContinue)) { + $Null = Remove-Module -Name TestModule; + } + + It 'Handles path spaces' { + # Copy file + $testParentPath = Join-Path -Path $outputPath -ChildPath 'Program Files\'; + $testRuleDestinationPath = Join-Path -Path $testParentPath -ChildPath 'FromFile.Rule.ps1'; + if (!(Test-Path -Path $testParentPath)) { + $Null = New-Item -Path $testParentPath -ItemType Directory -Force; + } + $Null = Copy-Item -Path $ruleFilePath -Destination $testRuleDestinationPath -Force; + + $result = @(Get-PSRule -Path $testRuleDestinationPath); + $result | Should -Not -BeNullOrEmpty; + $result.Length | Should -BeGreaterThan 10; + + # Copy module to test path + $testModuleDestinationPath = Join-Path -Path $testParentPath -ChildPath 'TestModule'; + $Null = Copy-Item -Path $testModuleSourcePath -Destination $testModuleDestinationPath -Recurse -Force; + + # Test modules with spaces in paths + $Null = Import-Module $testModuleDestinationPath -Force; $result = @(Get-PSRule -Module 'TestModule' -Culture 'en-US'); $result | Should -Not -BeNullOrEmpty; $result.Length | Should -Be 2; @@ -852,8 +885,12 @@ Describe 'Get-PSRule' -Tag 'Get-PSRule','Common' { $result[0].Info.Annotations.culture | Should -Be 'en-US'; } + if ($Null -ne (Get-Module -Name TestModule -ErrorAction SilentlyContinue)) { + $Null = Remove-Module -Name TestModule; + } + It 'Returns module and path rules' { - $Null = Import-Module (Join-Path $here -ChildPath 'TestModule'); + $Null = Import-Module $testModuleSourcePath -Force; $result = @(Get-PSRule -Path (Join-Path $here -ChildPath 'TestModule') -Module 'TestModule'); $result | Should -Not -BeNullOrEmpty; $result.Length | Should -Be 4; @@ -866,7 +903,7 @@ Describe 'Get-PSRule' -Tag 'Get-PSRule','Common' { } # en-US default - $Null = Import-Module (Join-Path $here -ChildPath 'TestModule'); + $Null = Import-Module $testModuleSourcePath -Force; $result = @(Get-PSRule -Module 'TestModule'); $result | Should -Not -BeNullOrEmpty; $result.Length | Should -Be 2; @@ -875,7 +912,7 @@ Describe 'Get-PSRule' -Tag 'Get-PSRule','Common' { $result[0].Info.Annotations.culture | Should -Be 'en-US'; # en-AU - $Null = Import-Module (Join-Path $here -ChildPath 'TestModule'); + $Null = Import-Module $testModuleSourcePath -Force; $result = @(Get-PSRule -Module 'TestModule' -Culture 'en-AU'); $result | Should -Not -BeNullOrEmpty; $result.Length | Should -Be 2; @@ -888,7 +925,7 @@ Describe 'Get-PSRule' -Tag 'Get-PSRule','Common' { } # en-AU default - $Null = Import-Module (Join-Path $here -ChildPath 'TestModule'); + $Null = Import-Module $testModuleSourcePath -Force; $result = @(Get-PSRule -Module 'TestModule'); $result | Should -Not -BeNullOrEmpty; $result.Length | Should -Be 2; @@ -926,7 +963,7 @@ Describe 'Get-PSRule' -Tag 'Get-PSRule','Common' { Describe 'Get-PSRuleHelp' -Tag 'Get-PSRuleHelp', 'Common' { $ruleFilePath = (Join-Path -Path $here -ChildPath 'FromFile.Rule.ps1'); - $Null = Import-Module (Join-Path $here -ChildPath 'TestModule'); + $Null = Import-Module (Join-Path $here -ChildPath 'TestModule') -Force; Context 'With defaults' { It 'Docs from imported module' { diff --git a/tests/PSRule.Tests/PSRule.PSGallery.Tests.ps1 b/tests/PSRule.Tests/PSRule.PSGallery.Tests.ps1 index 607f038109..e2a7703522 100644 --- a/tests/PSRule.Tests/PSRule.PSGallery.Tests.ps1 +++ b/tests/PSRule.Tests/PSRule.PSGallery.Tests.ps1 @@ -15,15 +15,20 @@ Set-StrictMode -Version latest; $rootPath = $PWD; Describe 'PSRule' -Tag 'PowerShellGallery' { + $modulePath = (Join-Path -Path $rootPath -ChildPath out/modules/PSRule); + Context 'Module' { It 'Can be imported' { - Import-Module (Join-Path -Path $rootPath -ChildPath out/modules/PSRule) -Force; + Import-Module $modulePath -Force; } } Context 'Manifest' { $manifestPath = (Join-Path -Path $rootPath -ChildPath out/modules/PSRule/PSRule.psd1); $result = Test-ModuleManifest -Path $manifestPath; + $Global:psEditor = $True; + $Null = Import-Module $modulePath -Force; + $commands = Get-Command -Module PSRule -All; It 'Has required fields' { $result.Name | Should -Be 'PSRule'; @@ -33,12 +38,34 @@ Describe 'PSRule' -Tag 'PowerShellGallery' { } It 'Exports functions' { - 'Invoke-PSRule', 'Get-PSRule', 'New-PSRuleOption', 'Rule' | Should -BeIn $result.ExportedFunctions.Keys; + $filteredCommands = @($commands | Where-Object -FilterScript { $_ -is [System.Management.Automation.FunctionInfo] }); + $filteredCommands | Should -Not -BeNullOrEmpty; + $expected = @( + 'Invoke-PSRule' + 'Get-PSRule' + 'Get-PSRuleHelp' + 'Test-PSRuleTarget' + 'New-PSRuleOption' + 'Set-PSRuleOption' + 'Rule' + ) + $expected | Should -BeIn $filteredCommands.Name; + $expected | Should -BeIn $result.ExportedFunctions.Keys; + } + + It 'Exports aliases' { + $filteredCommands = @($commands | Where-Object -FilterScript { $_ -is [System.Management.Automation.AliasInfo] }); + $filteredCommands | Should -Not -BeNullOrEmpty; + $expected = @( + 'Hint' + ) + $expected | Should -BeIn $filteredCommands.Name; + $expected | Should -BeIn $result.ExportedAliases.Keys; } } Context 'Static analysis' { - $result = Invoke-ScriptAnalyzer -Path (Join-Path -Path $rootPath -ChildPath out/modules/PSRule); + $result = Invoke-ScriptAnalyzer -Path $modulePath; $warningCount = ($result | Where-Object { $_.Severity -eq 'Warning' } | Measure-Object).Count; $errorCount = ($result | Where-Object { $_.Severity -eq 'Error' } | Measure-Object).Count;