From 936f37a1b60ef4d7854752f825f033c5eb4fb5fe Mon Sep 17 00:00:00 2001 From: Michael Van Leeuwen Date: Sun, 6 Nov 2022 12:36:39 -0800 Subject: [PATCH 1/5] Add Windows to the UseSingularNouns allow list --- Rules/UseSingularNouns.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Rules/UseSingularNouns.cs b/Rules/UseSingularNouns.cs index de9264d35..fbbdac1b0 100644 --- a/Rules/UseSingularNouns.cs +++ b/Rules/UseSingularNouns.cs @@ -37,7 +37,8 @@ public class CmdletSingularNoun : IScriptRule private readonly string[] nounAllowList = { - "Data" + "Data", + "Windows" }; /// From 5489f4c928f5b0e08593d4eb81d73312a79b32bf Mon Sep 17 00:00:00 2001 From: Michael Van Leeuwen Date: Sun, 6 Nov 2022 12:37:09 -0800 Subject: [PATCH 2/5] Add test case for Windows verb --- .../Rules/UseSingularNounsReservedVerbs.tests.ps1 | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 b/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 index 534e6df4d..db9475f6a 100644 --- a/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 +++ b/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 @@ -44,6 +44,20 @@ Write-Output "Adding some data" -OutVariable violations $violations.Count | Should -Be 0 } + + It "ignores function name ending with Windows" { + $nounViolationScript = @' +Function Test-Windows +{ +Write-Output "Testing Microsoft Windows" +} +'@ + Invoke-ScriptAnalyzer -ScriptDefinition $nounViolationScript ` + -IncludeRule "PSUseSingularNouns" ` + -OutVariable violations + $violations.Count | Should -Be 0 + } + } Context "When there are no violations" { From ae9f6f9164a56487afb0e75bd798fa3665e2e803 Mon Sep 17 00:00:00 2001 From: Michael Van Leeuwen Date: Mon, 7 Nov 2022 19:44:26 -0800 Subject: [PATCH 3/5] Refactor UseSingularNouns to configurable rule and add tests --- Rules/UseSingularNouns.cs | 27 ++++++++++--------- .../UseSingularNounsReservedVerbs.tests.ps1 | 20 ++++++++++++-- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/Rules/UseSingularNouns.cs b/Rules/UseSingularNouns.cs index fbbdac1b0..11a8b8b2b 100644 --- a/Rules/UseSingularNouns.cs +++ b/Rules/UseSingularNouns.cs @@ -32,14 +32,15 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules #if !CORECLR [Export(typeof(IScriptRule))] #endif - public class CmdletSingularNoun : IScriptRule + public class CmdletSingularNoun : ConfigurableRule { + [ConfigurableRuleProperty(defaultValue: new string[] { "Data", "Windows" })] + public string[] NounAllowList { get; set; } - private readonly string[] nounAllowList = + public CmdletSingularNoun() { - "Data", - "Windows" - }; + Enable = true; + } /// /// Checks that all defined cmdlet use singular noun @@ -47,7 +48,7 @@ public class CmdletSingularNoun : IScriptRule /// /// /// - public IEnumerable AnalyzeScript(Ast ast, string fileName) + public override IEnumerable AnalyzeScript(Ast ast, string fileName) { if (ast == null) throw new ArgumentNullException(Strings.NullCommandInfoError); @@ -71,7 +72,7 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) if (pluralizer.CanOnlyBePlural(noun)) { - if (nounAllowList.Contains(noun, StringComparer.OrdinalIgnoreCase)) + if (NounAllowList.Contains(noun, StringComparer.OrdinalIgnoreCase)) { continue; } @@ -99,7 +100,7 @@ public IEnumerable AnalyzeScript(Ast ast, string fileName) /// GetName: Retrieves the name of this rule. /// /// The name of this rule - public string GetName() + public override string GetName() { return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.UseSingularNounsName); } @@ -108,7 +109,7 @@ public string GetName() /// GetName: Retrieves the common name of this rule. /// /// The common name of this rule - public string GetCommonName() + public override string GetCommonName() { return string.Format(CultureInfo.CurrentCulture, Strings.UseSingularNounsCommonName); } @@ -117,7 +118,7 @@ public string GetCommonName() /// GetDescription: Retrieves the description of this rule. /// /// The description of this rule - public string GetDescription() + public override string GetDescription() { return string.Format(CultureInfo.CurrentCulture, Strings.UseSingularNounsDescription); } @@ -125,7 +126,7 @@ public string GetDescription() /// /// GetSourceType: Retrieves the type of the rule: builtin, managed or module. /// - public SourceType GetSourceType() + public override SourceType GetSourceType() { return SourceType.Builtin; } @@ -134,7 +135,7 @@ public SourceType GetSourceType() /// GetSeverity: Retrieves the severity of the rule: error, warning of information. /// /// - public RuleSeverity GetSeverity() + public override RuleSeverity GetSeverity() { return RuleSeverity.Warning; } @@ -142,7 +143,7 @@ public RuleSeverity GetSeverity() /// /// GetSourceName: Retrieves the module/assembly name the rule is from. /// - public string GetSourceName() + public override string GetSourceName() { return string.Format(CultureInfo.CurrentCulture, Strings.SourceName); } diff --git a/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 b/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 index db9475f6a..9cc49030e 100644 --- a/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 +++ b/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 @@ -32,7 +32,7 @@ Describe "UseSingularNouns" { Context "When function names have nouns from allowlist" { - It "ignores function name ending with Data" { + It "ignores function name ending with Data by default" { $nounViolationScript = @' Function Add-SomeData { @@ -45,7 +45,7 @@ Write-Output "Adding some data" $violations.Count | Should -Be 0 } - It "ignores function name ending with Windows" { + It "ignores function name ending with Windows by default" { $nounViolationScript = @' Function Test-Windows { @@ -58,6 +58,22 @@ Write-Output "Testing Microsoft Windows" $violations.Count | Should -Be 0 } + It "ignores function names defined in settings" { + $nounViolationScript = @' +Function Get-Bananas +{ +Write-Output "Bananas" +} +'@ + Invoke-ScriptAnalyzer -ScriptDefinition $nounViolationScript ` + -IncludeRule "PSUseSingularNouns" ` + -OutVariable violations + Invoke-ScriptAnalyzer -ScriptDefinition $nounViolationScript -Settings @{ + IncludeRules = @("PSUseSingularNouns") + Rules = @{ PSUseSingularNouns = @{ NounAllowList = "Bananas" } } + } | Should -BeNullOrEmpty + } + } Context "When there are no violations" { From 386624542ffa85c8d11424e96b97ce482166c730 Mon Sep 17 00:00:00 2001 From: Michael Van Leeuwen Date: Mon, 7 Nov 2022 19:44:56 -0800 Subject: [PATCH 4/5] Update UseSingularNouns docs with configuration information --- docs/Rules/README.md | 2 +- docs/Rules/UseSingularNouns.md | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/Rules/README.md b/docs/Rules/README.md index aaac74f66..2915369b7 100644 --- a/docs/Rules/README.md +++ b/docs/Rules/README.md @@ -74,7 +74,7 @@ The PSScriptAnalyzer contains the following rule definitions. | [UseProcessBlockForPipelineCommand](./UseProcessBlockForPipelineCommand.md) | Warning | Yes | | | [UsePSCredentialType](./UsePSCredentialType.md) | Warning | Yes | | | [UseShouldProcessForStateChangingFunctions](./UseShouldProcessForStateChangingFunctions.md) | Warning | Yes | | -| [UseSingularNouns](./UseSingularNouns.md) | Warning | Yes | | +| [UseSingularNouns](./UseSingularNouns.md) | Warning | Yes | Yes | | [UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Warning | Yes | | | [UseToExportFieldsInManifest](./UseToExportFieldsInManifest.md) | Warning | Yes | | | [UseUsingScopeModifierInNewRunspaces](./UseUsingScopeModifierInNewRunspaces.md) | Warning | Yes | | diff --git a/docs/Rules/UseSingularNouns.md b/docs/Rules/UseSingularNouns.md index 9dc24a017..3c8681244 100644 --- a/docs/Rules/UseSingularNouns.md +++ b/docs/Rules/UseSingularNouns.md @@ -13,6 +13,27 @@ title: UseSingularNouns PowerShell team best practices state cmdlets should use singular nouns and not plurals. +## Configuration + +```powershell +Rules = @{ + UseSingularNouns = @{ + NounAllowList = 'Data', 'Windows', 'Foos' + Enable = $true + } +} +``` + +### Parameters + +#### `UseSingularNouns: string[]` (Default value is `{'Data', 'Windows'}`) + +Commands to be excluded from this rule. `Data` and `Windows` are common false positives and are excluded by default + +#### Enable: `bool` (Default value is `$true`) + +Enable or disable the rule during ScriptAnalyzer invocation. + ## How Change plurals to singular. From 474e1306faf4f1c5fbd46f6640d41131cb4eacc1 Mon Sep 17 00:00:00 2001 From: Michael Van Leeuwen Date: Mon, 7 Nov 2022 19:48:25 -0800 Subject: [PATCH 5/5] Remove extra test code --- Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 | 3 --- 1 file changed, 3 deletions(-) diff --git a/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 b/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 index 9cc49030e..472b7eaf7 100644 --- a/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 +++ b/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 @@ -65,9 +65,6 @@ Function Get-Bananas Write-Output "Bananas" } '@ - Invoke-ScriptAnalyzer -ScriptDefinition $nounViolationScript ` - -IncludeRule "PSUseSingularNouns" ` - -OutVariable violations Invoke-ScriptAnalyzer -ScriptDefinition $nounViolationScript -Settings @{ IncludeRules = @("PSUseSingularNouns") Rules = @{ PSUseSingularNouns = @{ NounAllowList = "Bananas" } }