Publish release manifest with NAS deployments

This commit is contained in:
2026-07-05 20:03:06 +09:00
parent 1710c96456
commit 1cdfcd57b3
2 changed files with 48 additions and 0 deletions

View File

@@ -1,9 +1,12 @@
import { spawnSync } from 'node:child_process';
import { mkdirSync, writeFileSync } from 'node:fs';
import { join } from 'node:path';
const qaVersion = process.env.PUBLIC_QA_VERSION ?? makeQaVersion();
runPnpmScript('verify:local-release');
runPnpmScript('qa:early');
writeReleaseManifest(qaVersion);
runPnpmScript('deploy:nas:dist');
runPnpmScript('verify:public-deploy', { PUBLIC_QA_VERSION: qaVersion });
@@ -14,6 +17,30 @@ function makeQaVersion() {
return `ship-${stamp}`;
}
function writeReleaseManifest(qaVersion) {
const manifest = {
app: 'heros_web',
qaVersion,
commit: gitValue(['rev-parse', 'HEAD'], 'unknown'),
shortCommit: gitValue(['rev-parse', '--short', 'HEAD'], 'unknown'),
branch: gitValue(['branch', '--show-current'], 'unknown'),
generatedAt: new Date().toISOString(),
verification: ['verify:local-release', 'qa:early', 'verify:public-deploy']
};
mkdirSync('dist', { recursive: true });
writeFileSync(join('dist', 'release-manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
console.log(`Wrote dist/release-manifest.json for ${manifest.shortCommit} (${qaVersion})`);
}
function gitValue(args, fallback) {
const result = spawnSync('git', args, { cwd: process.cwd(), encoding: 'utf8' });
if (result.status !== 0) {
return fallback;
}
return result.stdout.trim() || fallback;
}
function runPnpmScript(scriptName, extraEnv = {}) {
const label = `pnpm run ${scriptName}`;
console.log(`\n$ ${label}`);

View File

@@ -4,6 +4,7 @@ import { chromium } from 'playwright';
const targetUrl = withQaParams(process.env.PUBLIC_QA_URL ?? 'https://comtropy.synology.me/heros_web/');
const screenshotPath = process.env.PUBLIC_QA_SCREENSHOT ?? 'dist/public-deploy-qa.png';
const expectedQaVersion = process.env.PUBLIC_QA_VERSION;
const expectedTitle = '\uC0BC\uAD6D\uC9C0: \uC138 \uD615\uC81C\uC758 \uB9F9\uC138';
const relevantLogPattern = /asset|audio|cannot|failed|map|missing|portrait|sprite|story|texture|unit/i;
@@ -99,6 +100,17 @@ try {
assert(state.canvas.pixelProbe.nonTransparentRatio > 0.5, `Expected non-empty canvas pixels: ${JSON.stringify(state)}`);
assert(state.canvas.pixelProbe.distinctColorBuckets >= 12, `Expected visually varied canvas pixels: ${JSON.stringify(state)}`);
const releaseManifest = await readReleaseManifest(targetUrl);
assert(releaseManifest.app === 'heros_web', `Expected deployed release manifest app id: ${JSON.stringify(releaseManifest)}`);
assert(typeof releaseManifest.commit === 'string' && releaseManifest.commit.length >= 7, `Expected deployed release manifest commit: ${JSON.stringify(releaseManifest)}`);
assert(typeof releaseManifest.generatedAt === 'string' && releaseManifest.generatedAt.length > 0, `Expected deployed release manifest timestamp: ${JSON.stringify(releaseManifest)}`);
if (expectedQaVersion) {
assert(
releaseManifest.qaVersion === expectedQaVersion,
`Expected deployed release manifest qaVersion ${expectedQaVersion}: ${JSON.stringify(releaseManifest)}`
);
}
const relevantLogs = consoleMessages.filter(
(message) => message.type === 'error' || (isWarning(message.type) && relevantLogPattern.test(message.text))
);
@@ -108,6 +120,7 @@ try {
assert(blockingRequestFailures.length === 0, `Unexpected public deploy request failures: ${JSON.stringify(blockingRequestFailures, null, 2)}`);
console.log(`Verified public deploy at ${targetUrl}`);
console.log(`Verified release manifest ${releaseManifest.shortCommit ?? releaseManifest.commit} (${releaseManifest.qaVersion ?? 'no qaVersion'})`);
console.log(`Captured ${screenshotPath}`);
} finally {
await browser.close();
@@ -124,6 +137,14 @@ function isWarning(type) {
return type === 'warning' || type === 'warn';
}
async function readReleaseManifest(pageUrl) {
const manifestUrl = new URL('release-manifest.json', pageUrl);
manifestUrl.searchParams.set('v', expectedQaVersion ?? String(Date.now()));
const response = await fetch(manifestUrl, { signal: AbortSignal.timeout(90000) });
assert(response.ok, `Expected deployed release manifest at ${manifestUrl.href}: ${response.status} ${response.statusText}`);
return response.json();
}
function assert(condition, message) {
if (!condition) {
throw new Error(message);