mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-10-08 09:29:01 +00:00
121 lines
5.1 KiB
JavaScript
121 lines
5.1 KiB
JavaScript
import { readFileSync } from 'node:fs';
|
|
import path from 'node:path';
|
|
import process from 'node:process';
|
|
import { fileURLToPath } from 'node:url';
|
|
|
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
const webNextRoot = path.resolve(scriptDir, '..');
|
|
const repoRoot = path.resolve(webNextRoot, '..');
|
|
|
|
export const REQUIRED_WEB_NEXT_INGRESS_PREFIXES = [
|
|
'/_next/',
|
|
'/overview',
|
|
'/entities',
|
|
'/alert',
|
|
'/topology',
|
|
'/setting'
|
|
];
|
|
|
|
export const RELEASE_CHECKLIST_ITEMS = [
|
|
{
|
|
key: 'ci-blocking-gates',
|
|
label: 'Frontend CI keeps build, budget, compose, checklist, tests, and smoke blocking',
|
|
verify: files =>
|
|
files.packageJson.scripts?.['verify:full'] ===
|
|
'npm run build && npm run release:budget && npm run release:compose && npm run release:checklist && npm run verify' &&
|
|
files.workflow.includes('npm run verify:full') &&
|
|
files.workflow.includes('npm run parity:smoke:baseline')
|
|
},
|
|
{
|
|
key: 'standalone-release-image',
|
|
label: 'web-next release image is standalone, non-root, healthchecked, and version labeled',
|
|
verify: files =>
|
|
files.nextConfig.includes("output: 'standalone'") &&
|
|
files.dockerfile.includes('FROM node:22-alpine') &&
|
|
files.dockerfile.includes('USER nextjs') &&
|
|
files.dockerfile.includes('HEALTHCHECK') &&
|
|
files.dockerfile.includes('org.opencontainers.image.version="${HERTZBEAT_RELEASE_VERSION}"')
|
|
},
|
|
{
|
|
key: 'compose-version-convergence',
|
|
label: 'Compose release stack shares one overrideable server/web-next release version',
|
|
verify: files =>
|
|
files.compose.includes('${HERTZBEAT_RELEASE_VERSION:-1.8.0}') &&
|
|
files.compose.includes('${HERTZBEAT_SERVER_IMAGE:-apache/hertzbeat}') &&
|
|
files.compose.includes('${HERTZBEAT_WEB_NEXT_IMAGE:-apache/hertzbeat-web-next}')
|
|
},
|
|
{
|
|
key: 'promotion-rollback-config',
|
|
label: 'Promotion and rollback tags are validated through docker compose config',
|
|
verify: files =>
|
|
files.packageJson.scripts?.['release:compose'] === 'node ./scripts/release-compose.mjs' &&
|
|
files.releaseCompose.includes('verifyReleaseComposeConfig') &&
|
|
files.releaseCompose.includes('HERTZBEAT_ROLLBACK_VERSION')
|
|
},
|
|
{
|
|
key: 'bundle-budget',
|
|
label: 'Production Next build has a JavaScript bundle budget gate',
|
|
verify: files =>
|
|
files.packageJson.scripts?.['release:budget'] === 'node ./scripts/release-budget.mjs' &&
|
|
files.releaseBudget.includes('DEFAULT_RELEASE_BUDGET_BYTES') &&
|
|
files.releaseBudget.includes('evaluateReleaseBudget')
|
|
},
|
|
{
|
|
key: 'release-ingress-route-ownership',
|
|
label: 'Gateway routes operator route families to web-next and APIs/fallback to Spring',
|
|
verify: files =>
|
|
REQUIRED_WEB_NEXT_INGRESS_PREFIXES.every(prefix => files.gateway.includes(`location ^~ ${prefix}`)) &&
|
|
files.gateway.includes('proxy_pass http://web-next:4200;') &&
|
|
files.gateway.includes('location ^~ /api/') &&
|
|
files.gateway.includes('location /') &&
|
|
files.gateway.includes('proxy_pass http://hertzbeat:1157;')
|
|
},
|
|
{
|
|
key: 'three-signal-alpha-cutoff-evidence',
|
|
label: 'Three-signal alpha cutoff evidence report runs in frontend verification',
|
|
verify: files =>
|
|
files.packageJson.scripts?.['three-signal:cutoff'] === 'node ./scripts/three-signal-alpha-cutoff-report.mjs' &&
|
|
files.packageJson.scripts?.verify?.includes('npm run three-signal:cutoff') &&
|
|
files.threeSignalAlphaCutoff.includes('verifyThreeSignalAlphaCutoff')
|
|
}
|
|
];
|
|
|
|
export function readReleaseChecklistFiles(rootDir = repoRoot) {
|
|
const readRepoFile = relativePath => readFileSync(path.join(rootDir, relativePath), 'utf8');
|
|
const packageText = readRepoFile('web-next/package.json');
|
|
|
|
return {
|
|
packageJson: JSON.parse(packageText),
|
|
workflow: readRepoFile('.github/workflows/frontend-build-test.yml'),
|
|
dockerfile: readRepoFile('web-next/Dockerfile'),
|
|
nextConfig: readRepoFile('web-next/next.config.mjs'),
|
|
compose: readRepoFile('script/docker-compose/hertzbeat-postgresql-victoria-metrics-next-observability/docker-compose.yaml'),
|
|
gateway: readRepoFile('script/docker-compose/hertzbeat-postgresql-victoria-metrics-next-observability/nginx/default.conf'),
|
|
releaseBudget: readRepoFile('web-next/scripts/release-budget.mjs'),
|
|
releaseCompose: readRepoFile('web-next/scripts/release-compose.mjs'),
|
|
threeSignalAlphaCutoff: readRepoFile('web-next/scripts/three-signal-alpha-cutoff-report.mjs')
|
|
};
|
|
}
|
|
|
|
export function evaluateReleaseChecklist(files = readReleaseChecklistFiles()) {
|
|
return RELEASE_CHECKLIST_ITEMS.map(item => ({
|
|
key: item.key,
|
|
label: item.label,
|
|
passed: Boolean(item.verify(files))
|
|
}));
|
|
}
|
|
|
|
export function verifyReleaseChecklist(files = readReleaseChecklistFiles()) {
|
|
const results = evaluateReleaseChecklist(files);
|
|
const failures = results.filter(result => !result.passed);
|
|
if (failures.length > 0) {
|
|
throw new Error(`Release checklist failed: ${failures.map(result => result.key).join(', ')}`);
|
|
}
|
|
return results;
|
|
}
|
|
|
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
const results = verifyReleaseChecklist();
|
|
console.log(`release checklist ok: ${results.map(result => result.key).join(', ')}`);
|
|
}
|