utilities/pipelines/staticValidation/Set-PesterGitHubOutput.ps1 (202 lines of code) (raw):
<#
.SYNOPSIS
Parse a Pester output containing checks & results and generate formatted markdown file out of it.
.DESCRIPTION
Parse a Pester output containing checks & results and generate formatted markdown file out of it.
.PARAMETER PesterTestResults
Mandatory. The Pester tests results to parse. Can be fetched by running Pester with the `-PassThru` parameter. For example:
@{
Containers = '[+] C:/ResourceModules/utilities/pipelines/staticValidation/module.tests.ps1'
Result = 'Passed'
FailedCount = 0
FailedBlocksCount = 0
FailedContainersCount = 0
PassedCount = 36
SkippedCount = 1
NotRunCount = 0
TotalCount = 37
Duration = '00:00:41.8816077'
Executed = true
ExecutedAt = '2023-04-01T12:27:19.5807422+02:00'
Version = '5.4.0'
PSVersion = '7.3.3'
PSBoundParameters = 'System.Management.Automation.PSBoundParametersDictionary'
Plugins = null
PluginConfiguration = null
PluginData = null
Configuration = 'PesterConfiguration'
DiscoveryDuration = '00:00:16.1489218'
UserDuration = '00:00:22.4714890'
FrameworkDuration = '00:00:03.2611969'
Failed = ''
FailedBlocks = ''
FailedContainers = ''
Passed = '[+] [key-vault/vault/secret] Module should contain a [main.json/main.bicep] file. [+] ...'
NotRun = ''
Tests = '[+] [key-vault/vault/secret] Module should contain a [main.json/main.bicep] file. [+] ...'
CodeCoverage = null
}
.PARAMETER OutputFilePath
Optional. The path to the formatted .md file to be created.
.PARAMETER GitHubRepository
Optional. The repository containing the test file. If provided it will be used to generate a URL to the exact line of the test.
For example: 'Azure/ResourceModules'
.PARAMETER BranchName
Optional. The branch the pipeline was triggered from. If provided it will be used to generate a URL to the exact line of the test.
For example: 'users/carml/testBranch'
.EXAMPLE
Set-PesterGitHubOutput -PesterTestResults @{...}
Generate a markdown file [output.md] in the current folder, out of the Pester test results input, listing all passed and failed tests.
.EXAMPLE
Set-PesterGitHubOutput -PesterTestResults @{...} -OutputFilePath 'C:/Pester-output.md' -GitHubRepository 'Azure/ResourceModules' -BranchName 'users/carml/testBranch'
Generate a markdown file [C:/Pester-output.md], out of the Pester test results input, including links to the exact test line numbers in the originating GitHub repository [Azure/ResourceModules] in branch [users/carml/testBranch].
#>
function Set-PesterGitHubOutput {
[CmdletBinding(SupportsShouldProcess)]
param (
[Parameter(Mandatory = $true)]
[PSCustomObject] $PesterTestResults,
[Parameter(Mandatory = $false)]
[string] $OutputFilePath = './output.md',
[Parameter(Mandatory = $false)]
[string] $GitHubRepository,
[Parameter(Mandatory = $false)]
[string] $BranchName
)
$passedTests = $PesterTestResults.Passed
$failedTests = $PesterTestResults.Failed
$skippedTests = $PesterTestResults.Skipped
Write-Verbose ('Formatting [{0}] passed tests' -f $passedTests.Count)
Write-Verbose ('Formatting [{0}] failed tests' -f $failedTests.Count)
Write-Verbose ('Formatting [{0}] skipped tests' -f $skippedTests.Count)
######################
# Set output content #
######################
# Header
$fileContent = [System.Collections.ArrayList]@(
'# Pester validation summary ',
''
)
## Header table
$fileContent += [System.Collections.ArrayList]@(
'| Total No. of Processed Tests| Passed Tests :white_check_mark: | Failed Tests :x: | Skipped Tests :paperclip: |',
'| :-- | :-- | :-- | :-- |'
('| {0} | {1} | {2} | {3} |' -f $PesterTestResults.TotalCount, $passedTests.count , $failedTests.count, $skippedTests.count),
''
)
######################
## Failed Tests ##
######################
Write-Verbose 'Adding failed tests'
$fileContent += [System.Collections.ArrayList]@(
'',
'<details>',
'<summary>List of failed Tests</summary>',
''
)
if ($failedTests.Count -gt 0) {
Write-Verbose 'Adding failed tests'
$fileContent += [System.Collections.ArrayList]@(
'| Name | Error | Source |',
'| :-- | :-- | :-- |'
)
foreach ($failedTest in ($failedTests | Sort-Object -Property { $PSItem.ExpandedName })) {
$intermediateNameElements = $failedTest.Path
$intermediateNameElements[-1] = '**{0}**' -f $failedTest.ExpandedName
$testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim()
$errorTestLine = $failedTest.ErrorRecord.TargetObject.Line
$errorTestFile = (Split-Path $failedTest.ErrorRecord.TargetObject.File -Leaf).Trim()
$errorMessage = $failedTest.ErrorRecord.TargetObject.Message.Trim() -replace '\n', '<br>' # Replace new lines with <br> to enable line breaks in markdown
$testReference = '{0}:{1}' -f $errorTestFile, $errorTestLine
if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) {
# Creating URL to test file to enable users to 'click' on it
$testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/utilities/pipelines/staticValidation/module.tests.ps1#L$errorTestLine)"
}
$fileContent += '| {0} | {1} | <code>{2}</code> |' -f $testName, $errorMessage, $testReference
}
} else {
$fileContent += ('No tests failed.')
}
$fileContent += [System.Collections.ArrayList]@(
'',
'</details>',
''
)
######################
## Passed Tests ##
######################
Write-Verbose 'Adding passed tests'
$fileContent += [System.Collections.ArrayList]@(
'',
'<details>',
'<summary>List of passed Tests</summary>',
''
)
if (($passedTests.Count -gt 0)) {
$fileContent += [System.Collections.ArrayList]@(
'| Name | Source |',
'| :-- | :-- |'
)
foreach ($passedTest in ($passedTests | Sort-Object -Property { $PSItem.ExpandedName }) ) {
$intermediateNameElements = $passedTest.Path
$intermediateNameElements[-1] = '**{0}**' -f $passedTest.ExpandedName
$testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim()
$testLine = $passedTest.ScriptBlock.StartPosition.StartLine
$testFile = (Split-Path $passedTest.ScriptBlock.File -Leaf).Trim()
$testReference = '{0}:{1}' -f $testFile, $testLine
if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) {
# Creating URL to test file to enable users to 'click' on it
$testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/utilities/pipelines/staticValidation/module.tests.ps1#L$testLine)"
}
$fileContent += '| {0} | <code>{1}</code> |' -f $testName, $testReference
}
} else {
$fileContent += ('No tests passed.')
}
$fileContent += [System.Collections.ArrayList]@(
'',
'</details>',
''
)
#######################
## Skipped Tests ##
#######################
Write-Verbose 'Adding skipped tests'
$fileContent += [System.Collections.ArrayList]@(
'',
'<details>',
'<summary>List of skipped Tests</summary>',
''
)
if ($skippedTests.Count -gt 0) {
$fileContent += [System.Collections.ArrayList]@(
'| Name | Reason | Source |',
'| :-- | :-- | :-- |'
)
foreach ($skippedTest in ($skippedTests | Sort-Object -Property { $PSItem.ExpandedName }) ) {
$intermediateNameElements = $skippedTest.Path
$intermediateNameElements[-1] = '**{0}**' -f $skippedTest.ExpandedName
$testName = (($intermediateNameElements -join ' / ' | Out-String) -replace '\|', '\|').Trim()
$reason = ('Test {0}' -f $skippedTest.ErrorRecord.Exception.Message -replace '\|', '\|').Trim()
$testLine = $passedTest.ScriptBlock.StartPosition.StartLine
$testFile = (Split-Path $passedTest.ScriptBlock.File -Leaf).Trim()
$testReference = '{0}:{1}' -f $testFile, $testLine
if (-not [String]::IsNullOrEmpty($GitHubRepository) -and -not [String]::IsNullOrEmpty($BranchName)) {
# Creating URL to test file to enable users to 'click' on it
$testReference = "[$testReference](https://github.com/$GitHubRepository/blob/$BranchName/utilities/pipelines/staticValidation/module.tests.ps1#L$testLine)"
}
$fileContent += '| {0} | {1} | <code>{2}</code> |' -f $testName, $reason, $testReference
}
} else {
$fileContent += ('No tests were skipped.')
}
$fileContent += [System.Collections.ArrayList]@(
'',
'</details>',
''
)
if ($PSCmdlet.ShouldProcess("Test results file in path [$OutputFilePath]", 'Create')) {
$null = New-Item -Path $OutputFilePath -Force -Value ($fileContent | Out-String)
}
Write-Verbose "Create results file [$outputFilePath]"
}