Modules/businessdev.ALbuild.Apps/Public/Test-BcCodeCoverageThreshold.ps1
|
function Test-BcCodeCoverageThreshold { <# .SYNOPSIS Gates a build on code-coverage thresholds -- overall and (optionally) per object. .DESCRIPTION Evaluates ALbuild coverage data (raw *.dat + workspace, or an existing coverage-summary.json) against a minimum overall line-coverage percentage and an optional per-object floor. Returns a verdict object ({ passed, lineCoverage, minLineCoverage, belowMinimum[], offenders[] }) and, with -ThrowOnFailure, throws so a pipeline step fails. Honest by construction: it uses the source-based denominator, so a suite that merely executes every covered line does not pass a real threshold. .PARAMETER MinLineCoverage Minimum overall line-coverage percent (0-100) required to pass. .PARAMETER MinObjectLineCoverage Optional per-object minimum; any workspace object below it is reported as an offender (and fails the gate). .PARAMETER ThrowOnFailure Throw a terminating error when the gate fails (for use as a pipeline gate). .OUTPUTS PSCustomObject verdict. #> [CmdletBinding(DefaultParameterSetName = 'Raw')] [OutputType([PSCustomObject])] param( [Parameter(Mandatory, ParameterSetName = 'Raw')] [ValidateNotNullOrEmpty()] [string] $CoveragePath, [Parameter(ParameterSetName = 'Raw')] [string] $WorkspaceRoot, [Parameter(ParameterSetName = 'Raw')] [ValidateSet('Auto', 'Source', 'CoveredOnly')] [string] $DenominatorMode = 'Auto', [Parameter(Mandatory, ParameterSetName = 'Summary')] [ValidateNotNullOrEmpty()] [string] $SummaryPath, [Parameter(Mandatory)] [ValidateRange(0, 100)] [double] $MinLineCoverage, [ValidateRange(0, 100)] [double] $MinObjectLineCoverage = 0, [switch] $ThrowOnFailure ) $data = if ($PSCmdlet.ParameterSetName -eq 'Summary') { Resolve-BcCoverageData -SummaryPath $SummaryPath } else { $params = @{ CoveragePath = $CoveragePath; DenominatorMode = $DenominatorMode } if ($WorkspaceRoot) { $params['WorkspaceRoot'] = $WorkspaceRoot } Resolve-BcCoverageData @params } $overall = [double]$data.Summary.lineCoverage $overallPass = $overall -ge $MinLineCoverage $offenders = @() if ($MinObjectLineCoverage -gt 0) { $offenders = @($data.Objects | Where-Object { [double]$_.lineCoverage -lt $MinObjectLineCoverage } | ForEach-Object { [PSCustomObject]@{ objectType = $_.objectType objectId = $_.objectId objectName = $_.objectName filePath = $_.filePath lineCoverage = $_.lineCoverage } }) } $passed = $overallPass -and ($offenders.Count -eq 0) $verdict = [PSCustomObject]@{ passed = $passed lineCoverage = $overall minLineCoverage = $MinLineCoverage minObjectLineCoverage = $MinObjectLineCoverage overallPassed = $overallPass offenders = @($offenders) coveredLines = $data.Summary.coveredLines totalExecutableLines = $data.Summary.totalExecutableLines denominatorMode = $data.Summary.denominatorMode } if ($passed) { Write-ALbuildLog -Level Success ("Coverage gate PASSED: {0}% >= {1}% ({2}/{3} lines)." -f $overall, $MinLineCoverage, $data.Summary.coveredLines, $data.Summary.totalExecutableLines) } else { $msg = if (-not $overallPass) { "Coverage {0}% is below the required {1}%." -f $overall, $MinLineCoverage } else { "{0} object(s) are below the per-object minimum of {1}%." -f $offenders.Count, $MinObjectLineCoverage } Write-ALbuildLog -Level Warning "Coverage gate FAILED: $msg" if ($ThrowOnFailure) { throw "Coverage gate failed: $msg" } } return $verdict } |