From 97a7432df31ac223f5ae4237ba24b60140d0bdc1 Mon Sep 17 00:00:00 2001 From: Wickedness Date: Tue, 7 Jul 2026 15:21:28 +0900 Subject: [PATCH] Improve release QA deployment checks --- scripts/deploy-nas.ps1 | 12 +++ scripts/qa-representative-battles.mjs | 107 +++++++++++++++++--------- 2 files changed, 82 insertions(+), 37 deletions(-) diff --git a/scripts/deploy-nas.ps1 b/scripts/deploy-nas.ps1 index efc5e61..4d20577 100644 --- a/scripts/deploy-nas.ps1 +++ b/scripts/deploy-nas.ps1 @@ -53,7 +53,19 @@ if ($BackupRetention -lt 0) { } $timestamp = Get-Date -Format "yyyyMMddHHmmss" +$fullCommit = (git rev-parse HEAD).Trim() $commit = (git rev-parse --short=8 HEAD).Trim() +$qaVersion = if ($env:PUBLIC_QA_VERSION) { $env:PUBLIC_QA_VERSION } else { "deploy-$timestamp" } +$releaseManifestPath = Join-Path $dist "release-manifest.json" +@{ + app = "heros_web" + commit = $fullCommit + shortCommit = $commit + qaVersion = $qaVersion + generatedAt = (Get-Date).ToUniversalTime().ToString("o") +} | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $releaseManifestPath -Encoding UTF8 +Write-Host "Wrote $releaseManifestPath for $commit ($qaVersion)" + $userHost = "$SshUser@$SshHost" $remoteTemp = "$RemoteRoot/.$($SiteName)_deploy_$timestamp" $remotePrevious = "$RemoteRoot/.$($SiteName)_previous_$timestamp" diff --git a/scripts/qa-representative-battles.mjs b/scripts/qa-representative-battles.mjs index a704b2b..9ca313b 100644 --- a/scripts/qa-representative-battles.mjs +++ b/scripts/qa-representative-battles.mjs @@ -1198,43 +1198,7 @@ try { failureReason: objective.failureReason ?? '' })) ); - console.table( - results.map((result) => ({ - no: result.no, - outcome: result.outcome, - turn: result.finalTurn, - alliesAlive: result.alliesAlive, - enemiesAlive: result.enemiesAlive, - itemsUsed: result.itemsUsed, - campUsed: result.campSuppliesUsed - ? `${result.campSuppliesUsed.bean}/${result.campSuppliesUsed.salve}/${result.campSuppliesUsed.wine}` - : '', - stock: result.campaign ? `${result.campaign.supplies.bean}/${result.campaign.supplies.salve}/${result.campaign.supplies.wine}` : '', - level: result.campaign ? `${result.campaign.levelMin}-${result.campaign.levelMax} (${result.campaign.levelAvg})` : '', - lowHp: result.campaign?.lowHp ?? '', - supports: result.supports, - objectives: `${result.objectivesAchieved}/${result.objectiveCount}`, - missed: result.objectiveDetails?.filter((objective) => !objective.achieved).map((objective) => objective.id).join(',') ?? '' - })) - ); - - if (cumulativeMode && results.length > 0) { - const latest = results.at(-1).campaign; - console.dir( - { - mode: 'cumulative', - battleCount: latest?.battleCount, - gold: latest?.gold, - supplies: latest?.supplies, - rosterCount: latest?.rosterCount, - levelRange: latest ? `${latest.levelMin}-${latest.levelMax}` : undefined, - levelAvg: latest?.levelAvg, - lowHp: latest?.lowHp, - topLevels: latest?.topLevels - }, - { depth: null } - ); - } + printQaSummary(results, failed, missedObjectives); await writeQaReport(qaReportPath, results, failed); @@ -2995,6 +2959,75 @@ function parseCliOptions(args) { return options; } +function printQaSummary(results, failed, missedObjectives) { + const totals = results.reduce( + (summary, result) => { + summary.turns += result.finalTurn ?? 0; + summary.objectives += result.objectiveCount ?? 0; + summary.objectivesAchieved += result.objectivesAchieved ?? 0; + summary.itemsUsed += result.itemsUsed ?? 0; + summary.supports += result.supports ?? 0; + + if (result.campSuppliesUsed) { + summary.camp.bean += result.campSuppliesUsed.bean ?? 0; + summary.camp.salve += result.campSuppliesUsed.salve ?? 0; + summary.camp.wine += result.campSuppliesUsed.wine ?? 0; + } + + return summary; + }, + { + turns: 0, + objectives: 0, + objectivesAchieved: 0, + itemsUsed: 0, + supports: 0, + camp: { bean: 0, salve: 0, wine: 0 } + } + ); + const turnValues = results.map((result) => result.finalTurn ?? 0).filter((turn) => turn > 0); + const longestBattle = results.reduce((current, result) => { + if (!current || (result.finalTurn ?? 0) > (current.finalTurn ?? 0)) { + return result; + } + return current; + }, undefined); + const latestCampaign = results.at(-1)?.campaign; + + console.log( + `QA summary: battles=${results.length} victories=${results.filter((result) => result.outcome === 'victory').length} failures=${failed.length} objectives=${totals.objectivesAchieved}/${totals.objectives} missed=${missedObjectives.length}` + ); + + if (turnValues.length > 0) { + const averageTurns = (totals.turns / turnValues.length).toFixed(1); + console.log( + `QA pace: avgTurn=${averageTurns} minTurn=${Math.min(...turnValues)} maxTurn=${Math.max(...turnValues)} longest=${longestBattle?.no}:${longestBattle?.id}` + ); + } + + console.log( + `QA resources: items=${totals.itemsUsed} supports=${totals.supports} campUsed=${totals.camp.bean}/${totals.camp.salve}/${totals.camp.wine}` + ); + + if (latestCampaign) { + const topLevels = Array.isArray(latestCampaign.topLevels) ? latestCampaign.topLevels.join(',') : 'none'; + console.log( + `QA campaign: battles=${latestCampaign.battleCount} gold=${latestCampaign.gold} roster=${latestCampaign.rosterCount} level=${latestCampaign.levelMin}-${latestCampaign.levelMax} avg=${latestCampaign.levelAvg} lowHp=${latestCampaign.lowHp}` + ); + console.log( + `QA stock: bean=${latestCampaign.supplies.bean} salve=${latestCampaign.supplies.salve} wine=${latestCampaign.supplies.wine} topLevels=${topLevels}` + ); + } + + if (failed.length > 0) { + console.log(`QA failures: ${failed.map((result) => `${result.no}:${result.id}:${result.outcome}`).join(' | ')}`); + } + + if (missedObjectives.length > 0) { + console.log(`QA missed objectives: ${missedObjectives.map((objective) => `${objective.no}:${objective.objectiveId}`).join(' | ')}`); + } +} + async function writeQaReport(reportPath, results, failed) { if (!reportPath) { return;