Thing/scripts/run-parity-smoke.ps1
2026-07-10 10:35:26 +01:00

197 lines
6.4 KiB
PowerShell

param(
[string] $ProviderId = "eve.cultui.inspector",
[string] $OutputDirectory = "artifacts\parity-smoke",
[string] $IosSshTarget = "eve",
[string] $LinuxSshTarget = "nightwing"
)
$ErrorActionPreference = "Stop"
$projectRoot = Split-Path -Parent $PSScriptRoot
$stamp = Get-Date -Format "yyyyMMdd-HHmmss"
$runRoot = Join-Path $projectRoot (Join-Path $OutputDirectory $stamp)
New-Item -ItemType Directory -Force $runRoot | Out-Null
$conformanceRoot = if ($env:EVE_CONFORMANCE_ROOT) { $env:EVE_CONFORMANCE_ROOT } else { "E:\Projects\EveConformance" }
$manifest = Get-Content (Join-Path $conformanceRoot "tools\parity\parity-manifest.json") | ConvertFrom-Json
$env:EVE_KERNEL_ROOT = $projectRoot
$responsiveCases = @($manifest.responsiveCases)
$androidDeviceCases = @($manifest.androidDeviceCases)
$results = [ordered]@{
schema = "gamecult.eve.parity_smoke.v1"
generatedAt = (Get-Date).ToUniversalTime().ToString("o")
providerId = $ProviderId
outputDirectory = $runRoot
targets = @()
}
function Add-TargetResult {
param(
[string] $Id,
[string] $Status,
[string] $Screenshot = "",
[string] $ErrorMessage = ""
)
$results.targets += [ordered]@{
id = $Id
status = $Status
screenshot = $Screenshot
error = $ErrorMessage
}
}
function Invoke-Capture {
param(
[string] $Id,
[scriptblock] $Capture
)
try {
$screenshot = & $Capture
if ($LASTEXITCODE -ne 0) {
throw "capture command exited with code $LASTEXITCODE"
}
Add-TargetResult -Id $Id -Status "pass" -Screenshot ($screenshot | Select-Object -Last 1)
} catch {
Add-TargetResult -Id $Id -Status "fail" -ErrorMessage $_.Exception.Message
}
}
function Resolve-ContactSheetPython {
$candidates = @()
if ($env:EVE_PARITY_PYTHON) {
$candidates += $env:EVE_PARITY_PYTHON
}
$candidates += @("python", "python3")
foreach ($candidate in $candidates) {
try {
& $candidate -c "import PIL" *> $null
if ($LASTEXITCODE -eq 0) {
return $candidate
}
} catch {
}
}
return $null
}
Push-Location $projectRoot
try {
powershell -ExecutionPolicy Bypass -File .\scripts\run-parity-harness.ps1 -OutputDirectory (Join-Path $runRoot "semantic") | Out-Host
if ($LASTEXITCODE -ne 0) {
throw "Semantic parity harness failed with exit code $LASTEXITCODE"
}
$flutterSurface = Join-Path $runRoot "flutter-current-surface.json"
node (Join-Path $conformanceRoot "tools\parity\export-fixture.mjs") $ProviderId $flutterSurface | Out-Host
if ($LASTEXITCODE -ne 0) { throw "Flutter fixture export failed with exit code $LASTEXITCODE" }
foreach ($case in $responsiveCases) {
Invoke-Capture "web-$($case.id)" {
powershell -ExecutionPolicy Bypass -File .\scripts\capture-web-reference.ps1 `
-ProviderId $ProviderId `
-OutputPath (Join-Path $runRoot "web-$ProviderId-$($case.id).png") `
-Width $case.width `
-Height $case.height
}
}
Invoke-Capture "ios" {
$iosFixture = Join-Path $runRoot "ios-current-surface.json"
node (Join-Path $conformanceRoot "tools\parity\export-fixture.mjs") $ProviderId $iosFixture | Out-Host
powershell -ExecutionPolicy Bypass -File .\scripts\capture-eve-screenshot.ps1 `
-Target $IosSshTarget `
-OutputDirectory $runRoot `
-FixturePath $iosFixture
}
$androidFlutterBuilt = $false
foreach ($case in $responsiveCases) {
Invoke-Capture "android-flutter-$($case.id)" {
$args = @(
"-ExecutionPolicy", "Bypass",
"-File", "E:\Projects\EveFlutter\scripts\capture-android-flutter-parity.ps1",
"-FixtureId", $ProviderId,
"-SurfacePath", $flutterSurface,
"-OutputPath", (Join-Path $runRoot "android-flutter-periwinkle-$($case.id).png"),
"-Width", $case.width,
"-Height", $case.height,
"-Orientation", $case.orientation
)
if ($androidFlutterBuilt) {
$args += "-SkipBuild"
} else {
$args += "-ForceInstall"
}
powershell @args
$androidFlutterBuilt = $true
}
}
foreach ($case in $androidDeviceCases) {
Invoke-Capture "android-flutter-$($case.id)" {
powershell -ExecutionPolicy Bypass -File E:\Projects\EveFlutter\scripts\capture-android-flutter-parity.ps1 `
-FixtureId $ProviderId `
-SurfacePath $flutterSurface `
-OutputPath (Join-Path $runRoot "android-flutter-periwinkle-$($case.id).png") `
-Orientation $case.orientation `
-SkipBuild
}
}
foreach ($case in $responsiveCases) {
Invoke-Capture "windows-$($case.id)" {
powershell -ExecutionPolicy Bypass -File E:\Projects\EveFlutter\scripts\capture-flutter-parity.ps1 `
-Target windows `
-FixtureId $ProviderId `
-SurfacePath $flutterSurface `
-ViewportId $case.id `
-OutputPath (Join-Path $runRoot "windows-flutter-$ProviderId-$($case.id).png")
}
}
foreach ($case in $responsiveCases) {
Invoke-Capture "linux-$($case.id)" {
powershell -ExecutionPolicy Bypass -File E:\Projects\EveFlutter\scripts\capture-linux-flutter-parity.ps1 `
-SshTarget $LinuxSshTarget `
-FixtureId $ProviderId `
-SurfacePath $flutterSurface `
-ViewportId $case.id `
-OutputPath (Join-Path $runRoot "linux-flutter-$ProviderId-$($case.id).png")
}
}
$jsonPath = Join-Path $runRoot "parity-smoke.json"
$mdPath = Join-Path $runRoot "parity-smoke.md"
$results | ConvertTo-Json -Depth 8 | Set-Content -LiteralPath $jsonPath -Encoding UTF8
$lines = @(
"# Eve Parity Smoke",
"",
"Generated: $($results.generatedAt)",
"Provider: $ProviderId",
"",
"| Target | Status | Screenshot | Error |",
"| --- | --- | --- | --- |"
)
foreach ($target in $results.targets) {
$lines += "| $($target.id) | $($target.status) | $($target.screenshot) | $($target.error) |"
}
$lines -join "`n" | Set-Content -LiteralPath $mdPath -Encoding UTF8
$contactSheetPython = Resolve-ContactSheetPython
if ($contactSheetPython) {
& $contactSheetPython .\tools\parity\render-contact-sheet.py $jsonPath | Out-Host
} else {
Write-Host "Parity contact sheet skipped: set EVE_PARITY_PYTHON to a Python with Pillow."
}
Write-Host "Parity smoke report: $mdPath"
$failed = @($results.targets | Where-Object { $_.status -ne "pass" })
if ($failed.Count -gt 0) {
throw "$($failed.Count) parity smoke target(s) failed: $($failed.id -join ', ')"
}
} finally {
Pop-Location
}