hypertwist/scripts/render-hypertwist-web-package-validation-summary.mjs
2026-06-30 23:04:58 +00:00

154 lines
4.7 KiB
JavaScript

#!/usr/bin/env node
import fs from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const repoRoot = path.resolve(__dirname, '..')
const sourcePath = path.join(
repoRoot,
'docs/generated/higher_dimensional_training_maps/phase6c_dedicated_family_package_validation_report.json',
)
const outputPath = path.join(
repoRoot,
'website/src/shared/generated/windows-package-validation-summary.json',
)
const FAMILY_LABELS = {
magic120cell: 'Magic120Cell dedicated-family training map',
magiccube5d: 'MagicCube5D dedicated-family training map',
}
function parseJson(content, label) {
try {
return JSON.parse(content)
} catch (error) {
throw new Error(`${label} is not valid JSON: ${error instanceof Error ? error.message : String(error)}`)
}
}
function assertString(value, label) {
if (typeof value !== 'string' || value.trim().length === 0) {
throw new Error(`${label} must be a non-empty string.`)
}
return value
}
function assertBoolean(value, label) {
if (typeof value !== 'boolean') {
throw new Error(`${label} must be a boolean.`)
}
return value
}
function normalizePrePackageEditorBuild(value) {
if (value == null) {
return null
}
if (typeof value !== 'object') {
throw new Error('prePackageEditorBuild must be an object when present.')
}
const lane = assertString(value.lane, 'prePackageEditorBuild.lane')
const performed = assertBoolean(value.performed, 'prePackageEditorBuild.performed')
if (value.result !== 'passed' && value.result !== 'not-run') {
throw new Error('prePackageEditorBuild.result must be "passed" or "not-run".')
}
return {
lane,
performed,
result: value.result,
}
}
function normalizeSmokeResult(value, label) {
if (value === 'passed' || value === 'failed') {
return value
}
throw new Error(`${label} must be "passed" or "failed".`)
}
function buildFallbackLabel(mapUrl) {
const mapName = mapUrl.split('/').pop() || mapUrl
return `${mapName} packaged smoke map`
}
function buildSummary(report) {
const generatedAtUtc = assertString(report.generatedAtUtc, 'generatedAtUtc')
const configuration = assertString(report.configuration, 'configuration')
const skipBuild = assertBoolean(report.skipBuild, 'skipBuild')
const prePackageEditorBuild = normalizePrePackageEditorBuild(report.prePackageEditorBuild)
const result = normalizeSmokeResult(report.result, 'result')
const validatedEntries = Array.isArray(report.authoringManifest?.validatedEntries)
? report.authoringManifest.validatedEntries
: []
const mapKindByUrl = new Map(
validatedEntries
.filter((entry) => typeof entry?.mapAssetPath === 'string' && typeof entry?.mapKind === 'string')
.map((entry) => [entry.mapAssetPath, entry.mapKind]),
)
const smokeReports = Array.isArray(report.smokeReports) ? report.smokeReports : []
const smokeMaps = smokeReports.map((smokeReport, index) => {
const mapUrl = assertString(smokeReport.mapUrl, `smokeReports[${index}].mapUrl`)
const mapKind = mapKindByUrl.get(mapUrl)
const label =
(mapKind && FAMILY_LABELS[mapKind]) ||
buildFallbackLabel(mapUrl)
return {
map_url: mapUrl,
label,
result: normalizeSmokeResult(smokeReport.result, `smokeReports[${index}].result`),
}
})
return {
lane: 'Windows Unreal packaged validation',
result,
generated_at: generatedAtUtc,
configuration,
skip_build: skipBuild,
pre_package_editor_build: prePackageEditorBuild,
smoke_map_count: smokeMaps.length,
smoke_maps: smokeMaps,
}
}
async function main() {
const checkOnly = process.argv.includes('--check')
const sourceContent = await fs.readFile(sourcePath, 'utf8')
const summary = buildSummary(parseJson(sourceContent, sourcePath))
const serialized = `${JSON.stringify(summary, null, 2)}\n`
if (checkOnly) {
let existing = null
try {
existing = await fs.readFile(outputPath, 'utf8')
} catch (error) {
if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') {
console.error(`Generated summary missing: ${outputPath}`)
process.exit(1)
}
throw error
}
if (existing !== serialized) {
console.error('Generated web package-validation summary is stale.')
console.error(`Refresh with: node ${path.relative(repoRoot, __filename)}`)
process.exit(1)
}
console.log(`Validated packaged-validation summary freshness: ${path.relative(repoRoot, outputPath)}`)
return
}
await fs.mkdir(path.dirname(outputPath), { recursive: true })
await fs.writeFile(outputPath, serialized, 'utf8')
console.log(`Wrote ${path.relative(repoRoot, outputPath)}`)
}
await main()