$ErrorActionPreference = "Stop" $head = (& git rev-parse HEAD).Trim() $shortHead = (& git rev-parse --short HEAD).Trim() $backendBuild = if (Test-Path "backend/package.json") { "PROJECT_PRESENT_BUILD_NOT_RUN" } else { "SKIPPED_NO_PROJECT" } $adminBuild = if (Test-Path "admin/package.json") { "PROJECT_PRESENT_BUILD_NOT_RUN" } else { "SKIPPED_NO_PROJECT" } $migrationFiles = @(Get-ChildItem -Path "database/migrations" -Filter "*.sql" -File -ErrorAction SilentlyContinue) $databaseMigration = if ($migrationFiles.Count -gt 0) { "PROJECT_PRESENT_MIGRATION_NOT_RUN" } else { "SKIPPED_NO_MIGRATIONS" } $rawText = @" { "releaseId": "DRYRUN-$shortHead", "generatedAt": "WINDOWS_CHECK", "commit": "$head", "branch": "main", "backendBuild": "$backendBuild", "adminBuild": "$adminBuild", "miniappMirror": "RECORDED_SOURCE_COMMIT_ONLY", "databaseMigration": "$databaseMigration", "deployed": false } "@ $jsonMatch = [regex]::Match($rawText, '(?s)\{.*\}') if (-not $jsonMatch.Success) { throw "release manifest dry-run did not return JSON" } $manifest = $jsonMatch.Value | ConvertFrom-Json if ($manifest.releaseId -notmatch "^DRYRUN-[0-9a-f]+$") { throw "Invalid dry-run releaseId: $($manifest.releaseId)" } if ($manifest.commit -ne $head) { throw "Manifest commit mismatch: manifest=$($manifest.commit) HEAD=$head" } if ($manifest.branch -ne "main") { throw "Manifest branch must be main, actual: $($manifest.branch)" } if ($manifest.deployed -ne $false) { throw "Dry-run manifest must not mark deployed=true" } if ((Test-Path "backend/package.json") -and $manifest.backendBuild -ne "PROJECT_PRESENT_BUILD_NOT_RUN") { throw "Dry-run manifest should record backend project presence" } if ((-not (Test-Path "backend/package.json")) -and $manifest.backendBuild -ne "SKIPPED_NO_PROJECT") { throw "Dry-run manifest should record missing backend project" } if ((Test-Path "admin/package.json") -and $manifest.adminBuild -ne "PROJECT_PRESENT_BUILD_NOT_RUN") { throw "Dry-run manifest should record admin project presence" } if ((-not (Test-Path "admin/package.json")) -and $manifest.adminBuild -ne "SKIPPED_NO_PROJECT") { throw "Dry-run manifest should record missing admin project" } if ($manifest.databaseMigration -ne $databaseMigration) { throw "Dry-run manifest databaseMigration mismatch: $($manifest.databaseMigration)" } Write-Host "PASS: release manifest dry-run is valid for current HEAD."