Repository navigation
Add GitHub Actions annotations for Pester test failures #26789
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
739b0cc
d71c239
6a2d1af
6605c89
9b85763
790ef44
3138c65
b490e52
0366a8b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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 '\\', '/' | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+65
to
+71
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ($filePath.StartsWith($workspacePath)) { | |
| $filePath = $filePath.Substring($workspacePath.Length).TrimStart('/', '\') | |
| # Normalize to forward slashes for consistency | |
| $filePath = $filePath -replace '\\', '/' | |
| } | |
| } | |
| try { | |
| $workspaceFullPath = [System.IO.Path]::GetFullPath($workspacePath) | |
| } | |
| catch { | |
| $workspaceFullPath = $workspacePath | |
| } | |
| try { | |
| $fileFullPath = [System.IO.Path]::GetFullPath($filePath) | |
| } | |
| catch { | |
| $fileFullPath = $filePath | |
| } | |
| # Normalize separators for comparison | |
| $normalizedWorkspace = $workspaceFullPath.TrimEnd([System.IO.Path]::DirectorySeparatorChar, [System.IO.Path]::AltDirectorySeparatorChar) | |
| $normalizedFile = $fileFullPath.Replace([System.IO.Path]::AltDirectorySeparatorChar, [System.IO.Path]::DirectorySeparatorChar) | |
| $comparison = if ($IsWindows) { | |
| [System.StringComparison]::OrdinalIgnoreCase | |
| } | |
| else { | |
| [System.StringComparison]::Ordinal | |
| } | |
| $workspacePrefix = $normalizedWorkspace + [System.IO.Path]::DirectorySeparatorChar | |
| if ($normalizedFile.StartsWith($workspacePrefix, $comparison) -or $normalizedFile.Equals($normalizedWorkspace, $comparison)) { | |
| $relativePath = if ($normalizedFile.Equals($normalizedWorkspace, $comparison)) { | |
| '' | |
| } | |
| else { | |
| $normalizedFile.Substring($normalizedWorkspace.Length + 1) | |
| } | |
| if ($relativePath) { | |
| $filePath = $relativePath | |
| } | |
| } | |
| } | |
| # Normalize to forward slashes for consistency (required by GitHub annotations) | |
| $filePath = $filePath -replace '\\', '/' |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$annotationMessage = $message -replace "n", "%0A" -replace "r" is missing the replacement value for the second -replace, which will cause a PowerShell parse error at runtime. Provide an explicit replacement (e.g., strip \r or encode it) so the action can run.
| $annotationMessage = $message -replace "`n", "%0A" -replace "`r" | |
| $annotationMessage = $message -replace "`n", "%0A" -replace "`r", "%0D" |
Copilot
AI
Feb 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GitHub Actions workflow command needs escaping for %, \r, \n, and for property values also : and ,. As written, $filePath, $annotationTitle, or $annotationMessage containing these characters can produce a malformed ::error ...::... command (or truncate fields). Add proper workflow-command escaping before concatenating file=, title=, and the message payload.
Uh oh!
There was an error while loading. Please reload this page.