mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
[release/v7.4] Add GitHub Actions annotations for Pester test failures (#26800)
This commit is contained in:
@@ -24,6 +24,7 @@ $testIgnoredCount = 0
|
||||
$testSkippedCount = 0
|
||||
$testInvalidCount = 0
|
||||
|
||||
# Process test results and generate annotations for failures
|
||||
Get-ChildItem -Path "${TestResultsFolder}/*.xml" -Recurse | ForEach-Object {
|
||||
$results = [xml] (get-content $_.FullName)
|
||||
|
||||
@@ -35,6 +36,61 @@ Get-ChildItem -Path "${TestResultsFolder}/*.xml" -Recurse | ForEach-Object {
|
||||
$testIgnoredCount += [int]$results.'test-results'.ignored
|
||||
$testSkippedCount += [int]$results.'test-results'.skipped
|
||||
$testInvalidCount += [int]$results.'test-results'.invalid
|
||||
|
||||
# Generate GitHub Actions annotations for test failures
|
||||
# Select failed test cases
|
||||
if ("System.Xml.XmlDocumentXPathExtensions" -as [Type]) {
|
||||
$failures = [System.Xml.XmlDocumentXPathExtensions]::SelectNodes($results.'test-results', './/test-case[@result = "Failure"]')
|
||||
}
|
||||
else {
|
||||
$failures = $results.SelectNodes('.//test-case[@result = "Failure"]')
|
||||
}
|
||||
|
||||
foreach ($testfail in $failures) {
|
||||
$description = $testfail.description
|
||||
$testName = $testfail.name
|
||||
$message = $testfail.failure.message
|
||||
$stack_trace = $testfail.failure.'stack-trace'
|
||||
|
||||
# Parse stack trace to get file and line info
|
||||
$fileInfo = Get-PesterFailureFileInfo -StackTraceString $stack_trace
|
||||
|
||||
if ($fileInfo.File) {
|
||||
# Convert absolute path to relative path for GitHub Actions
|
||||
$filePath = $fileInfo.File
|
||||
|
||||
# GitHub Actions expects paths relative to the workspace root
|
||||
if ($env:GITHUB_WORKSPACE) {
|
||||
$workspacePath = $env:GITHUB_WORKSPACE
|
||||
if ($filePath.StartsWith($workspacePath)) {
|
||||
$filePath = $filePath.Substring($workspacePath.Length).TrimStart('/', '\')
|
||||
# Normalize to forward slashes for consistency
|
||||
$filePath = $filePath -replace '\\', '/'
|
||||
}
|
||||
}
|
||||
|
||||
# Create annotation title
|
||||
$annotationTitle = "Test Failure: $description / $testName"
|
||||
|
||||
# Build the annotation message
|
||||
$annotationMessage = $message -replace "`n", "%0A" -replace "`r"
|
||||
|
||||
# Build and output the workflow command
|
||||
$workflowCommand = "::error file=$filePath"
|
||||
if ($fileInfo.Line) {
|
||||
$workflowCommand += ",line=$($fileInfo.Line)"
|
||||
}
|
||||
$workflowCommand += ",title=$annotationTitle::$annotationMessage"
|
||||
|
||||
Write-Host $workflowCommand
|
||||
|
||||
# Output a link to the test run
|
||||
if ($env:GITHUB_SERVER_URL -and $env:GITHUB_REPOSITORY -and $env:GITHUB_RUN_ID) {
|
||||
$logUrl = "$($env:GITHUB_SERVER_URL)/$($env:GITHUB_REPOSITORY)/actions/runs/$($env:GITHUB_RUN_ID)"
|
||||
Write-Host "Test logs: $logUrl"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@"
|
||||
|
||||
+63
@@ -1846,6 +1846,69 @@ $stack_trace
|
||||
|
||||
}
|
||||
|
||||
function Get-PesterFailureFileInfo
|
||||
{
|
||||
[CmdletBinding()]
|
||||
param (
|
||||
[Parameter(Mandatory)]
|
||||
[string]$StackTraceString
|
||||
)
|
||||
|
||||
# Parse stack trace to extract file path and line number
|
||||
# Common patterns:
|
||||
# "at line: 123 in C:\path\to\file.ps1" (Pester 4)
|
||||
# "at C:\path\to\file.ps1:123"
|
||||
# "at <ScriptBlock>, C:\path\to\file.ps1: line 123"
|
||||
# "at 1 | Should -Be 2, /path/to/file.ps1:123" (Pester 5)
|
||||
# "at 1 | Should -Be 2, C:\path\to\file.ps1:123" (Pester 5 Windows)
|
||||
|
||||
$result = @{
|
||||
File = $null
|
||||
Line = $null
|
||||
}
|
||||
|
||||
if ([string]::IsNullOrWhiteSpace($StackTraceString)) {
|
||||
return $result
|
||||
}
|
||||
|
||||
# Try pattern: "at line: 123 in <path>" (Pester 4)
|
||||
if ($StackTraceString -match 'at line:\s*(\d+)\s+in\s+(.+?)(?:\r|\n|$)') {
|
||||
$result.Line = $matches[1]
|
||||
$result.File = $matches[2].Trim()
|
||||
return $result
|
||||
}
|
||||
|
||||
# Try pattern: ", <path>:123" (Pester 5 format)
|
||||
# This handles both Unix paths (/path/file.ps1:123) and Windows paths (C:\path\file.ps1:123)
|
||||
if ($StackTraceString -match ',\s*((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1):(\d+)') {
|
||||
$result.File = $matches[1].Trim()
|
||||
$result.Line = $matches[2]
|
||||
return $result
|
||||
}
|
||||
|
||||
# Try pattern: "at <path>:123" (without comma)
|
||||
# Handle both absolute Unix and Windows paths
|
||||
if ($StackTraceString -match 'at\s+((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):(\d+)(?:\r|\n|$)') {
|
||||
$result.File = $matches[1].Trim()
|
||||
$result.Line = $matches[2]
|
||||
return $result
|
||||
}
|
||||
|
||||
# Try pattern: "<path>: line 123"
|
||||
if ($StackTraceString -match '((?:[A-Za-z]:)?[\/\\][^,]+?\.ps[m]?1):\s*line\s+(\d+)(?:\r|\n|$)') {
|
||||
$result.File = $matches[1].Trim()
|
||||
$result.Line = $matches[2]
|
||||
return $result
|
||||
}
|
||||
|
||||
# Try to extract just the file path if no line number found
|
||||
if ($StackTraceString -match '(?:at\s+|in\s+)?((?:[A-Za-z]:)?[\/\\].+?\.ps[m]?1)') {
|
||||
$result.File = $matches[1].Trim()
|
||||
}
|
||||
|
||||
return $result
|
||||
}
|
||||
|
||||
function Test-XUnitTestResults
|
||||
{
|
||||
param(
|
||||
|
||||
Reference in New Issue
Block a user