|
| 1 | +Function Export-NUnitXml { |
| 2 | +<# |
| 3 | +.SYNOPSIS |
| 4 | + Takes results from PSScriptAnalyzer and exports them as a Pester test results file (NUnitXml format). |
| 5 | +
|
| 6 | +.DESCRIPTION |
| 7 | + Takes results from PSScriptAnalyzer and exports them as a Pester test results file (NUnit XML schema). |
| 8 | + Because the generated file in NUnit-compatible, it can be consumed and published by most continuous integration tools. |
| 9 | +#> |
| 10 | + [CmdletBinding()] |
| 11 | + Param ( |
| 12 | + [Parameter(Mandatory, Position=0)] |
| 13 | + [AllowNull()] |
| 14 | + [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]$ScriptAnalyzerResult, |
| 15 | + |
| 16 | + [Parameter(Mandatory, Position=1)] |
| 17 | + [string]$Path |
| 18 | + ) |
| 19 | + |
| 20 | + $TotalNumber = If ($ScriptAnalyzerResult) { $ScriptAnalyzerResult.Count -as [string] } Else { '1' } |
| 21 | + $FailedNumber = If ($ScriptAnalyzerResult) { $ScriptAnalyzerResult.Count -as [string] } Else { '0' } |
| 22 | + $Now = Get-Date |
| 23 | + $FormattedDate = Get-Date $Now -Format 'yyyy-MM-dd' |
| 24 | + $FormattedTime = Get-Date $Now -Format 'T' |
| 25 | + $User = $env:USERNAME |
| 26 | + $MachineName = $env:COMPUTERNAME |
| 27 | + $Cwd = $pwd.Path |
| 28 | + $UserDomain = $env:USERDOMAIN |
| 29 | + $OS = Get-CimInstance -ClassName Win32_OperatingSystem |
| 30 | + $Platform = $OS.Caption |
| 31 | + $OSVersion = $OS.Version |
| 32 | + $ClrVersion = $PSVersionTable.CLRVersion.ToString() |
| 33 | + $CurrentCulture = (Get-Culture).Name |
| 34 | + $UICulture = (Get-UICulture).Name |
| 35 | + |
| 36 | + Switch ($ScriptAnalyzerResult) { |
| 37 | + $Null { $TestResult = 'Success'; $TestSuccess = 'True'; Break} |
| 38 | + Default { $TestResult = 'Failure'; $TestSuccess = 'False'} |
| 39 | + } |
| 40 | + |
| 41 | + $Header = @" |
| 42 | +<?xml version="1.0" encoding="utf-8" standalone="no"?> |
| 43 | +<test-results xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="nunit_schema_2.5.xsd" name="PSScriptAnalyzer" total="$TotalNumber" errors="0" failures="$FailedNumber" not-run="0" inconclusive="0" ignored="0" skipped="0" invalid="0" date="$FormattedDate" time="$FormattedTime"> |
| 44 | + <environment user="$User" machine-name="$MachineName" cwd="$Cwd" user-domain="$UserDomain" platform="$Platform" nunit-version="2.5.8.0" os-version="$OSVersion" clr-version="$ClrVersion" /> |
| 45 | + <culture-info current-culture="$CurrentCulture" current-uiculture="$UICulture" /> |
| 46 | + <test-suite type="Powershell" name="PSScriptAnalyzer" executed="True" result="$TestResult" success="$TestSuccess" time="0.0" asserts="0"> |
| 47 | + <results> |
| 48 | + <test-suite type="TestFixture" name="PSScriptAnalyzer" executed="True" result="$TestResult" success="$TestSuccess" time="0.0" asserts="0" description="PSScriptAnalyzer"> |
| 49 | + <results>`n |
| 50 | +"@ |
| 51 | + |
| 52 | + $Footer = @" |
| 53 | + </results> |
| 54 | + </test-suite> |
| 55 | + </results> |
| 56 | + </test-suite> |
| 57 | +</test-results> |
| 58 | +"@ |
| 59 | + |
| 60 | + If ( -not($ScriptAnalyzerResult) ) { |
| 61 | + |
| 62 | + $TestDescription = 'All PowerShell files pass the specified PSScriptAnalyzer rules' |
| 63 | + $TestName = "PSScriptAnalyzer.{0}" -f $TestDescription |
| 64 | + |
| 65 | + $Body = @" |
| 66 | + <test-case description="$TestDescription" name="$TestName" time="0.0" asserts="0" success="True" result="Success" executed="True" />`n |
| 67 | +"@ |
| 68 | + } |
| 69 | + Else { # $ScriptAnalyzerResult is not null |
| 70 | + $Body = [string]::Empty |
| 71 | + Foreach ( $Result in $ScriptAnalyzerResult ) { |
| 72 | + |
| 73 | + $TestDescription = "Rule name : $($Result.RuleName)" |
| 74 | + $TestName = "PSScriptAnalyzer.{0} - {1} - Line {2}" -f $TestDescription, $($Result.ScriptName), $($Result.Line.ToString()) |
| 75 | + |
| 76 | + # Need to Escape these otherwise we can end up with an invalid XML if the Stacktrace has non XML friendly chars like &, etc |
| 77 | + $Line = [System.Security.SecurityElement]::Escape($Result.Line) |
| 78 | + $ScriptPath = [System.Security.SecurityElement]::Escape($Result.ScriptPath) |
| 79 | + $Text = [System.Security.SecurityElement]::Escape($Result.Extent.Text) |
| 80 | + $Severity = [System.Security.SecurityElement]::Escape($Result.Severity) |
| 81 | + |
| 82 | + $TestCase = @" |
| 83 | + <test-case description="$TestDescription" name="$TestName" time="0.0" asserts="0" success="False" result="Failure" executed="True"> |
| 84 | + <failure> |
| 85 | + <message>$($Result.Message)</message> |
| 86 | + <stack-trace>at line: $($Line) in $($ScriptPath) |
| 87 | + $($Line): $($Text) |
| 88 | + Rule severity : $($Severity) |
| 89 | + </stack-trace> |
| 90 | + </failure> |
| 91 | + </test-case>`n |
| 92 | +"@ |
| 93 | + |
| 94 | + $Body += $TestCase |
| 95 | + } |
| 96 | + } |
| 97 | + $OutputXml = $Header + $Body + $Footer |
| 98 | + |
| 99 | + # Checking our output is a well formed XML document |
| 100 | + Try { |
| 101 | + $XmlCheck = [xml]$OutputXml |
| 102 | + } |
| 103 | + Catch { |
| 104 | + Throw "There was an problem when attempting to cast the output to XML : $($_.Exception.Message)" |
| 105 | + } |
| 106 | + $OutputXml | Out-File -FilePath $Path -Encoding utf8 -Force |
| 107 | +} |
0 commit comments