Skip to content

Commit 367384a

Browse files
bergmeisterJamesWTruher
authored andcommitted
Finalise new -ReportSummary switch (#895)
* added -ReportSummary switch to emit an additional single line count of error, warning, and info results * changing ReportSummary to write-host * Add markdown file fix and test library mock for new -ReportSummary switch * tweak reportSummary and add test * convert tabs to spaces for consistency * poke build * update to pester v4 syntax * use built in warning/error methods to get colouring to work in a user setting agnostic way * try using helper class because writeerrorline did not work in CI * make one helper private and add licence header
1 parent 304d300 commit 367384a

File tree

5 files changed

+145
-4
lines changed

5 files changed

+145
-4
lines changed

Engine/Commands/InvokeScriptAnalyzerCommand.cs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,19 @@ public SwitchParameter AttachAndDebug
227227
set { attachAndDebug = value; }
228228
}
229229
private bool attachAndDebug = false;
230+
230231
#endif
232+
/// <summary>
233+
/// Write a summary of rule violations to the host, which might be undesirable in some cases, therefore this switch is optional.
234+
/// </summary>
235+
[Parameter(Mandatory = false)]
236+
public SwitchParameter ReportSummary
237+
{
238+
get { return reportSummary; }
239+
set { reportSummary = value; }
240+
}
241+
private SwitchParameter reportSummary;
242+
231243
#endregion Parameters
232244

233245
#region Overrides
@@ -409,9 +421,49 @@ private void WriteToOutput(IEnumerable<DiagnosticRecord> diagnosticRecords)
409421
{
410422
foreach (ILogger logger in ScriptAnalyzer.Instance.Loggers)
411423
{
424+
var errorCount = 0;
425+
var warningCount = 0;
426+
var infoCount = 0;
427+
412428
foreach (DiagnosticRecord diagnostic in diagnosticRecords)
413429
{
414430
logger.LogObject(diagnostic, this);
431+
switch (diagnostic.Severity)
432+
{
433+
case DiagnosticSeverity.Information:
434+
infoCount++;
435+
break;
436+
case DiagnosticSeverity.Warning:
437+
warningCount++;
438+
break;
439+
case DiagnosticSeverity.Error:
440+
errorCount++;
441+
break;
442+
default:
443+
throw new ArgumentOutOfRangeException(nameof(diagnostic.Severity), $"Severity '{diagnostic.Severity}' is unknown");
444+
}
445+
}
446+
447+
if (ReportSummary.IsPresent)
448+
{
449+
var numberOfRuleViolations = infoCount + warningCount + errorCount;
450+
if (numberOfRuleViolations == 0)
451+
{
452+
Host.UI.WriteLine("0 rule violations found.");
453+
}
454+
else
455+
{
456+
var pluralS = numberOfRuleViolations > 1 ? "s" : string.Empty;
457+
var message = $"{numberOfRuleViolations} rule violation{pluralS} found. Severity distribution: {DiagnosticSeverity.Error} = {errorCount}, {DiagnosticSeverity.Warning} = {warningCount}, {DiagnosticSeverity.Information} = {infoCount}";
458+
if (warningCount + errorCount == 0)
459+
{
460+
ConsoleHostHelper.DisplayMessageUsingSystemProperties(Host, "WarningForegroundColor", "WarningBackgroundColor", message);
461+
}
462+
else
463+
{
464+
ConsoleHostHelper.DisplayMessageUsingSystemProperties(Host, "ErrorForegroundColor", "ErrorBackgroundColor", message);
465+
}
466+
}
415467
}
416468
}
417469

Engine/Generic/ConsoleHostHelper.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
using System;
5+
using System.Management.Automation.Host;
6+
7+
namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic
8+
{
9+
internal static class ConsoleHostHelper
10+
{
11+
internal static void DisplayMessageUsingSystemProperties(PSHost psHost, string foregroundColorPropertyName, string backgroundPropertyName, string message)
12+
{
13+
var gotForegroundColor = TryGetPrivateDataConsoleColor(psHost, foregroundColorPropertyName, out ConsoleColor foregroundColor);
14+
var gotBackgroundColor = TryGetPrivateDataConsoleColor(psHost, backgroundPropertyName, out ConsoleColor backgroundColor);
15+
if (gotForegroundColor && gotBackgroundColor)
16+
{
17+
psHost.UI.WriteLine(foregroundColor: foregroundColor, backgroundColor: backgroundColor, value: message);
18+
}
19+
else
20+
{
21+
psHost.UI.WriteLine(message);
22+
}
23+
}
24+
25+
private static bool TryGetPrivateDataConsoleColor(PSHost psHost, string propertyName, out ConsoleColor consoleColor)
26+
{
27+
consoleColor = default(ConsoleColor);
28+
var property = psHost.PrivateData.Properties[propertyName];
29+
if (property == null)
30+
{
31+
return false;
32+
}
33+
34+
try
35+
{
36+
consoleColor = (ConsoleColor)Enum.Parse(typeof(ConsoleColor), property.Value.ToString(), true);
37+
}
38+
catch (InvalidCastException)
39+
{
40+
return false;
41+
}
42+
43+
return true;
44+
}
45+
}
46+
}

Tests/Engine/InvokeScriptAnalyzer.tests.ps1

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -516,4 +516,16 @@ Describe "Test -EnableExit Switch" {
516516
powershell -Command 'Import-Module PSScriptAnalyzer; Invoke-ScriptAnalyzer -ScriptDefinition gci -EnableExit'
517517
$LASTEXITCODE | Should -Be 1
518518
}
519+
520+
Describe "-ReportSummary switch" {
521+
$reportSummaryFor1Warning = '*1 rule violation found. Severity distribution: Error = 0, Warning = 1, Information = 0*'
522+
It "prints the correct report summary using the -NoReportSummary switch" {
523+
$result = powershell -command 'Invoke-Scriptanalyzer -ScriptDefinition gci -ReportSummary'
524+
"$result" | Should -BeLike $reportSummaryFor1Warning
525+
}
526+
It "does not print the report summary when not using -NoReportSummary switch" {
527+
$result = powershell -command 'Invoke-Scriptanalyzer -ScriptDefinition gci'
528+
"$result" | Should -Not -BeLike $reportSummaryFor1Warning
529+
}
530+
}
519531
}

Tests/Engine/LibraryUsage.tests.ps1

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,13 @@ function Invoke-ScriptAnalyzer {
5252

5353
[Parameter(Mandatory = $false)]
5454
[switch] $Fix,
55+
56+
[Parameter(Mandatory = $false)]
57+
[switch] $EnableExit,
5558

5659
[Parameter(Mandatory = $false)]
57-
[switch] $EnableExit
58-
)
60+
[switch] $ReportSummary
61+
)
5962

6063
if ($null -eq $CustomRulePath)
6164
{
@@ -98,6 +101,19 @@ function Invoke-ScriptAnalyzer {
98101
}
99102

100103
$results
104+
105+
if ($ReportSummary.IsPresent)
106+
{
107+
if ($null -ne $results)
108+
{
109+
# This is not the exact message that it would print but close enough
110+
Write-Host "$($results.Count) rule violations found. Severity distribution: Error = 1, Warning = 3, Information = 5" -ForegroundColor Red
111+
}
112+
else
113+
{
114+
Write-Host '0 rule violations found.' -ForegroundColor Green
115+
}
116+
}
101117

102118
if ($EnableExit.IsPresent -and $null -ne $results)
103119
{

docs/markdown/Invoke-ScriptAnalyzer.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ Evaluates a script or module based on selected best practice rules
1212
### UNNAMED_PARAMETER_SET_1
1313
```
1414
Invoke-ScriptAnalyzer [-Path] <String> [-CustomRulePath <String>] [-RecurseCustomRulePath]
15-
[-ExcludeRule <String[]>] [-IncludeRule <String[]>] [-Severity <String[]>] [-Recurse] [-SuppressedOnly] [-Fix] [-EnableExit]
15+
[-ExcludeRule <String[]>] [-IncludeRule <String[]>] [-Severity <String[]>] [-Recurse] [-SuppressedOnly] [-Fix] [-EnableExit] [-ReportSummary]
1616
[-Settings <String>]
1717
```
1818

1919
### UNNAMED_PARAMETER_SET_2
2020
```
2121
Invoke-ScriptAnalyzer [-ScriptDefinition] <String> [-CustomRulePath <String>] [-RecurseCustomRulePath]
22-
[-ExcludeRule <String[]>] [-IncludeRule <String[]>] [-Severity <String[]>] [-Recurse] [-SuppressedOnly] [-EnableExit]
22+
[-ExcludeRule <String[]>] [-IncludeRule <String[]>] [-Severity <String[]>] [-Recurse] [-SuppressedOnly] [-EnableExit] [-ReportSummary]
2323
[-Settings <String>]
2424
```
2525

@@ -432,6 +432,21 @@ Accept pipeline input: False
432432
Accept wildcard characters: False
433433
```
434434
435+
### -ReportSummary
436+
Writes a report summary of the found warnings to the host.
437+
438+
```yaml
439+
Type: SwitchParameter
440+
Parameter Sets: (All)
441+
Aliases:
442+
443+
Required: False
444+
Position: Named
445+
Default value: False
446+
Accept pipeline input: False
447+
Accept wildcard characters: False
448+
```
449+
435450
### -Settings
436451
File path that contains user profile or hash table for ScriptAnalyzer
437452

0 commit comments

Comments
 (0)