289 lines
8.7 KiB
PowerShell
289 lines
8.7 KiB
PowerShell
[CmdletBinding()]
|
|
param(
|
|
[string]$BuildPreset = "windows-msvc-default",
|
|
[string]$Configuration = "Debug",
|
|
[string[]]$BuildTargets = @("PanoPainter", "pano_cli"),
|
|
[string]$TestPreset = "desktop-fast",
|
|
[string]$TestRegex = "",
|
|
[switch]$Configure,
|
|
[switch]$SkipBuild,
|
|
[switch]$SkipTests,
|
|
[string]$CMakeCommand = "",
|
|
[string]$CTestCommand = "",
|
|
[string]$LogDir = "out/logs/quiet-validation",
|
|
[string]$IgnoreFilterFile = "",
|
|
[string[]]$IgnorePattern = @(),
|
|
[int]$FailureTailLines = 0
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
function Resolve-CMakeCommand {
|
|
param([string]$Requested)
|
|
|
|
if ($Requested.Length -gt 0) {
|
|
return $Requested
|
|
}
|
|
|
|
$vsCmake = "C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin\cmake.exe"
|
|
if (Test-Path -LiteralPath $vsCmake) {
|
|
return $vsCmake
|
|
}
|
|
|
|
return "cmake"
|
|
}
|
|
|
|
function Resolve-CTestCommand {
|
|
param(
|
|
[string]$Requested,
|
|
[string]$ResolvedCMake
|
|
)
|
|
|
|
if ($Requested.Length -gt 0) {
|
|
return $Requested
|
|
}
|
|
|
|
if ($ResolvedCMake.EndsWith("cmake.exe", [System.StringComparison]::OrdinalIgnoreCase)) {
|
|
$candidate = Join-Path -Path (Split-Path -Parent $ResolvedCMake) -ChildPath "ctest.exe"
|
|
if (Test-Path -LiteralPath $candidate) {
|
|
return $candidate
|
|
}
|
|
}
|
|
|
|
return "ctest"
|
|
}
|
|
|
|
function Read-IgnorePatterns {
|
|
param(
|
|
[string]$FilterFile,
|
|
[string[]]$InlinePatterns
|
|
)
|
|
|
|
$patterns = @()
|
|
if ($FilterFile.Length -eq 0) {
|
|
$defaultFile = Join-Path -Path $PSScriptRoot -ChildPath "quiet-validation-ignore.txt"
|
|
if (Test-Path -LiteralPath $defaultFile) {
|
|
$FilterFile = $defaultFile
|
|
}
|
|
}
|
|
|
|
if ($FilterFile.Length -gt 0 -and (Test-Path -LiteralPath $FilterFile)) {
|
|
$patterns += Get-Content -LiteralPath $FilterFile |
|
|
Where-Object { $_.Trim().Length -gt 0 -and -not $_.TrimStart().StartsWith("#") }
|
|
}
|
|
|
|
$patterns += $InlinePatterns
|
|
return @($patterns | Where-Object { $_ -and $_.Length -gt 0 })
|
|
}
|
|
|
|
function Expand-ArgumentList {
|
|
param([string[]]$Values)
|
|
|
|
$expanded = @()
|
|
foreach ($value in $Values) {
|
|
if ($null -eq $value) {
|
|
continue
|
|
}
|
|
$expanded += $value -split "[,\s]+" | Where-Object { $_.Length -gt 0 }
|
|
}
|
|
return @($expanded)
|
|
}
|
|
|
|
function Test-IgnoredLine {
|
|
param(
|
|
[string]$Line,
|
|
[string[]]$Patterns
|
|
)
|
|
|
|
foreach ($pattern in $Patterns) {
|
|
if ($Line -match $pattern) {
|
|
return $true
|
|
}
|
|
}
|
|
return $false
|
|
}
|
|
|
|
function Measure-Log {
|
|
param(
|
|
[string]$Path,
|
|
[string[]]$IgnorePatterns
|
|
)
|
|
|
|
$errorPattern = "(?i)(:\s*(fatal\s+)?error\s+[A-Z0-9]+:|^LINK\s*:\s*fatal error|^CMake Error|Errors while running CTest|Unable to find executable|\*\*\*Failed)"
|
|
$warningPattern = "(?i)(:\s*warning\s+[A-Z0-9]+:|^LINK\s*:\s*warning\s+[A-Z0-9]+:|warning:)"
|
|
$ctestSummaryPattern = "(\d+)% tests passed, (\d+) tests failed out of (\d+)"
|
|
|
|
$lineCount = 0
|
|
$rawErrors = 0
|
|
$rawWarnings = 0
|
|
$visibleErrors = 0
|
|
$visibleWarnings = 0
|
|
$ignoredErrors = 0
|
|
$ignoredWarnings = 0
|
|
$testsFailed = $null
|
|
$testsTotal = $null
|
|
|
|
if (Test-Path -LiteralPath $Path) {
|
|
foreach ($line in Get-Content -LiteralPath $Path) {
|
|
++$lineCount
|
|
$ignored = Test-IgnoredLine -Line $line -Patterns $IgnorePatterns
|
|
if ($line -match $ctestSummaryPattern) {
|
|
$testsFailed = [int]$Matches[2]
|
|
$testsTotal = [int]$Matches[3]
|
|
}
|
|
if ($line -match $errorPattern) {
|
|
++$rawErrors
|
|
if ($ignored) { ++$ignoredErrors } else { ++$visibleErrors }
|
|
}
|
|
if ($line -match $warningPattern) {
|
|
++$rawWarnings
|
|
if ($ignored) { ++$ignoredWarnings } else { ++$visibleWarnings }
|
|
}
|
|
}
|
|
}
|
|
|
|
return [ordered]@{
|
|
lineCount = $lineCount
|
|
errors = $visibleErrors
|
|
warnings = $visibleWarnings
|
|
rawErrors = $rawErrors
|
|
rawWarnings = $rawWarnings
|
|
ignoredErrors = $ignoredErrors
|
|
ignoredWarnings = $ignoredWarnings
|
|
testsFailed = $testsFailed
|
|
testsTotal = $testsTotal
|
|
}
|
|
}
|
|
|
|
function Invoke-QuietStep {
|
|
param(
|
|
[string]$Name,
|
|
[string]$Command,
|
|
[string[]]$Arguments,
|
|
[string]$LogPath,
|
|
[string[]]$IgnorePatterns,
|
|
[int]$FailureTailLines
|
|
)
|
|
|
|
$started = Get-Date
|
|
$exitCode = 0
|
|
try {
|
|
& $Command @Arguments *> $LogPath
|
|
$exitCode = $LASTEXITCODE
|
|
if ($null -eq $exitCode) {
|
|
$exitCode = 0
|
|
}
|
|
}
|
|
catch {
|
|
$_ | Out-File -LiteralPath $LogPath -Append -Encoding utf8
|
|
$exitCode = 1
|
|
}
|
|
|
|
$elapsed = [int]((Get-Date) - $started).TotalMilliseconds
|
|
$summary = Measure-Log -Path $LogPath -IgnorePatterns $IgnorePatterns
|
|
$result = [ordered]@{
|
|
name = $Name
|
|
exitCode = $exitCode
|
|
elapsedMs = $elapsed
|
|
log = $LogPath
|
|
summary = $summary
|
|
}
|
|
|
|
if ($exitCode -ne 0 -and $FailureTailLines -gt 0 -and (Test-Path -LiteralPath $LogPath)) {
|
|
$result.failureTail = @(Get-Content -LiteralPath $LogPath -Tail $FailureTailLines)
|
|
}
|
|
|
|
return $result
|
|
}
|
|
|
|
$resolvedCMake = Resolve-CMakeCommand -Requested $CMakeCommand
|
|
$resolvedCTest = Resolve-CTestCommand -Requested $CTestCommand -ResolvedCMake $resolvedCMake
|
|
$BuildTargets = @(Expand-ArgumentList -Values $BuildTargets)
|
|
$IgnorePattern = @(Expand-ArgumentList -Values $IgnorePattern)
|
|
$ignorePatterns = Read-IgnorePatterns -FilterFile $IgnoreFilterFile -InlinePatterns $IgnorePattern
|
|
|
|
New-Item -ItemType Directory -Force -Path $LogDir | Out-Null
|
|
$runId = Get-Date -Format "yyyyMMdd-HHmmss"
|
|
$started = Get-Date
|
|
$results = @()
|
|
$overallExitCode = 0
|
|
|
|
if ($Configure) {
|
|
$log = Join-Path -Path $LogDir -ChildPath "$runId-configure-$BuildPreset.log"
|
|
$result = Invoke-QuietStep `
|
|
-Name "configure:$BuildPreset" `
|
|
-Command $resolvedCMake `
|
|
-Arguments @("--preset", $BuildPreset) `
|
|
-LogPath $log `
|
|
-IgnorePatterns $ignorePatterns `
|
|
-FailureTailLines $FailureTailLines
|
|
$results += $result
|
|
if ($result.exitCode -ne 0 -and $overallExitCode -eq 0) {
|
|
$overallExitCode = $result.exitCode
|
|
}
|
|
}
|
|
|
|
if (-not $SkipBuild) {
|
|
$targets = @($BuildTargets | Where-Object { $_ -and $_.Length -gt 0 })
|
|
if ($targets.Count -gt 0) {
|
|
$safeTargets = ($targets -join "_") -replace "[^A-Za-z0-9_.-]", "_"
|
|
$log = Join-Path -Path $LogDir -ChildPath "$runId-build-$BuildPreset-$Configuration-$safeTargets.log"
|
|
$buildArgs = @("--build", "--preset", $BuildPreset, "--config", $Configuration, "--target") + $targets
|
|
$result = Invoke-QuietStep `
|
|
-Name ("build:{0}:{1}" -f $BuildPreset, $Configuration) `
|
|
-Command $resolvedCMake `
|
|
-Arguments $buildArgs `
|
|
-LogPath $log `
|
|
-IgnorePatterns $ignorePatterns `
|
|
-FailureTailLines $FailureTailLines
|
|
$result.targets = $targets
|
|
$results += $result
|
|
if ($result.exitCode -ne 0 -and $overallExitCode -eq 0) {
|
|
$overallExitCode = $result.exitCode
|
|
}
|
|
}
|
|
}
|
|
|
|
if (-not $SkipTests) {
|
|
$safeRegex = if ($TestRegex.Length -gt 0) { ($TestRegex -replace "[^A-Za-z0-9_.-]", "_") } else { "all" }
|
|
$log = Join-Path -Path $LogDir -ChildPath "$runId-test-$TestPreset-$Configuration-$safeRegex.log"
|
|
$testArgs = @("--preset", $TestPreset, "--build-config", $Configuration, "--output-on-failure")
|
|
if ($TestRegex.Length -gt 0) {
|
|
$testArgs += @("-R", $TestRegex)
|
|
}
|
|
$result = Invoke-QuietStep `
|
|
-Name ("test:{0}:{1}" -f $TestPreset, $Configuration) `
|
|
-Command $resolvedCTest `
|
|
-Arguments $testArgs `
|
|
-LogPath $log `
|
|
-IgnorePatterns $ignorePatterns `
|
|
-FailureTailLines $FailureTailLines
|
|
if ($TestRegex.Length -gt 0) {
|
|
$result.testRegex = $TestRegex
|
|
}
|
|
$results += $result
|
|
if ($result.exitCode -ne 0 -and $overallExitCode -eq 0) {
|
|
$overallExitCode = $result.exitCode
|
|
}
|
|
}
|
|
|
|
$elapsed = [int]((Get-Date) - $started).TotalMilliseconds
|
|
$summaryPath = Join-Path -Path $LogDir -ChildPath "$runId-summary.json"
|
|
$payload = [ordered]@{
|
|
command = "quiet-validate"
|
|
exitCode = $overallExitCode
|
|
elapsedMs = $elapsed
|
|
buildPreset = $BuildPreset
|
|
configuration = $Configuration
|
|
testPreset = $TestPreset
|
|
logDir = $LogDir
|
|
summary = $summaryPath
|
|
ignoreFilterFile = $IgnoreFilterFile
|
|
ignorePatternCount = $ignorePatterns.Count
|
|
results = $results
|
|
}
|
|
|
|
$payload | ConvertTo-Json -Depth 8 | Out-File -LiteralPath $summaryPath -Encoding utf8
|
|
$payload | ConvertTo-Json -Compress -Depth 8
|
|
exit $overallExitCode
|