Skip to content

Commit c89cae0

Browse files
Add missed-path coverage reporting upstream
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent b11b310 commit c89cae0

4 files changed

Lines changed: 91 additions & 0 deletions

File tree

.github/actions/Get-PesterCodeCoverage/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ This GitHub Action is a part of the [PSModule framework](https://github.com/PSMo
1111
- Combines multiple code coverage reports from parallel test runs
1212
- Generates markdown/HTML tables showing missed & executed commands
1313
- Displays analyzed files and coverage statistics
14+
- Generates a generic missed-path report (markdown + json)
1415
- Configurable step summary sections
1516
- Threshold enforcement for minimum code coverage
1617

@@ -40,6 +41,10 @@ This GitHub Action is a part of the [PSModule framework](https://github.com/PSMo
4041
4142
## Outputs
4243
44+
| Name | Description |
45+
| ---- | ----------- |
46+
| `MissedPathReportPath` | Folder path containing `CodeCoverage-MissedPaths.md` and `CodeCoverage-MissedPaths.json` |
47+
4348
### GitHub Step Summary
4449

4550
The action generates a detailed summary visible in the GitHub Actions UI:
@@ -53,6 +58,7 @@ The action generates a detailed summary visible in the GitHub Actions UI:
5358
- **Missed Commands**: HTML table with code snippets
5459
- **Executed Commands**: HTML table with code snippets
5560
- **Analyzed Files**: List of covered files
61+
- **Missed Paths**: Aggregated missed-command counts grouped by file path
5662

5763
Example summary:
5864

.github/actions/Get-PesterCodeCoverage/action.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,11 @@ inputs:
3535
description: The target for code coverage.
3636
required: false
3737

38+
outputs:
39+
MissedPathReportPath:
40+
description: Path to the generated missed-path report folder.
41+
value: ${{ steps.Get-PesterCodeCoverage.outputs.MissedPathReportPath }}
42+
3843
runs:
3944
using: composite
4045
steps:

.github/actions/Get-PesterCodeCoverage/src/main.ps1

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,66 @@ $success = $coveragePercent -ge $coveragePercentTarget
158158
$statusIcon = $success ? '' : ''
159159
$stats | Format-Table -AutoSize | Out-String
160160

161+
$missedPaths = $codeCoverage.CommandsMissed |
162+
Where-Object { -not [string]::IsNullOrWhiteSpace($_.File) } |
163+
Group-Object -Property File |
164+
Sort-Object -Property @(
165+
@{ Expression = 'Count'; Descending = $true },
166+
@{ Expression = 'Name'; Descending = $false }
167+
) |
168+
ForEach-Object {
169+
$lines = $_.Group |
170+
Where-Object { $_.Line -is [ValueType] } |
171+
ForEach-Object { [int]$_.Line } |
172+
Sort-Object -Unique
173+
[pscustomobject]@{
174+
Path = $_.Name
175+
MissedCommands = [int]$_.Count
176+
MissedLines = if ($lines.Count -eq 0) { '' } else { ($lines -join ', ') }
177+
}
178+
}
179+
180+
$missedPathReportPath = 'CodeCoverage-MissedPaths'
181+
$null = New-Item -Path $missedPathReportPath -ItemType Directory -Force
182+
183+
$missedPathReport = [ordered]@{
184+
GeneratedAtUtc = [DateTime]::UtcNow.ToString('o')
185+
CoveragePercent = [double]$coveragePercent
186+
CoverageTarget = [double]$coveragePercentTarget
187+
MissedPaths = @($missedPaths)
188+
}
189+
190+
$missedPathReportJsonPath = Join-Path -Path $missedPathReportPath -ChildPath 'CodeCoverage-MissedPaths.json'
191+
$missedPathReportMarkdownPath = Join-Path -Path $missedPathReportPath -ChildPath 'CodeCoverage-MissedPaths.md'
192+
$missedPathReport | ConvertTo-Json -Depth 10 | Set-Content -Path $missedPathReportJsonPath -Encoding utf8NoBOM
193+
194+
$missedPathMarkdown = [System.Collections.Generic.List[string]]::new()
195+
$null = $missedPathMarkdown.Add('# Code Coverage Missed Paths')
196+
$null = $missedPathMarkdown.Add('')
197+
$null = $missedPathMarkdown.Add("| Coverage | Target | Missed Paths | Missed Commands |")
198+
$null = $missedPathMarkdown.Add("| --- | --- | --- | --- |")
199+
$null = $missedPathMarkdown.Add("| $([Math]::Round($coveragePercent, 2))% | $([Math]::Round($coveragePercentTarget, 2))% | $($missedPaths.Count) | $($codeCoverage.CommandsMissedCount) |")
200+
$null = $missedPathMarkdown.Add('')
201+
$null = $missedPathMarkdown.Add('## Paths')
202+
$null = $missedPathMarkdown.Add('| Path | Missed Commands | Missed Lines |')
203+
$null = $missedPathMarkdown.Add('| --- | ---: | --- |')
204+
if ($missedPaths.Count -eq 0) {
205+
$null = $missedPathMarkdown.Add('| _None_ | 0 | |')
206+
} else {
207+
foreach ($pathEntry in $missedPaths) {
208+
$safePath = ([string]$pathEntry.Path).Replace('|', '\|')
209+
$safeLines = ([string]$pathEntry.MissedLines).Replace('|', '\|')
210+
$null = $missedPathMarkdown.Add("| $safePath | $($pathEntry.MissedCommands) | $safeLines |")
211+
}
212+
}
213+
214+
$missedPathMarkdown | Set-Content -Path $missedPathReportMarkdownPath -Encoding utf8NoBOM
215+
Write-Output 'Missed path report generated:'
216+
$missedPaths | Select-Object -First 20 | Format-Table -Property Path, MissedCommands, MissedLines -AutoSize | Out-String
217+
if ($env:GITHUB_OUTPUT) {
218+
"MissedPathReportPath=$missedPathReportPath" >> $env:GITHUB_OUTPUT
219+
}
220+
161221
# Build HTML table for 'missed' commands
162222
$tableheader = @'
163223
<table>
@@ -300,6 +360,18 @@ LogGroup 'Step Summary - Set step summary' {
300360
}
301361
}
302362
}
363+
364+
Details "Missed paths [$($missedPaths.Count)]" {
365+
if ($missedPaths.Count -eq 0) {
366+
Paragraph {
367+
Write-Output 'No missed paths were detected.'
368+
}
369+
} else {
370+
Table {
371+
$missedPaths | Select-Object -First 100
372+
}
373+
}
374+
}
303375
}
304376
}
305377

.github/workflows/Get-CodeCoverage.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,11 @@ jobs:
3434
Prerelease: ${{ fromJson(inputs.Settings).Prerelease }}
3535
Verbose: ${{ fromJson(inputs.Settings).Verbose }}
3636
Version: ${{ fromJson(inputs.Settings).Version }}
37+
38+
- name: Upload CodeCoverage-MissedPaths artifact
39+
if: always()
40+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
41+
with:
42+
name: CodeCoverage-MissedPaths
43+
path: CodeCoverage-MissedPaths
44+
if-no-files-found: warn

0 commit comments

Comments
 (0)