Files
harbor-net/scripts/runtime-impact.mjs
T
dokril 1ae23d848b
Build and Deploy Gateway / build-and-push (push) Successful in 1m22s
Build and Deploy Gateway / deploy (push) Successful in 16s
Migrate Harbor state and traffic history to SQLite
2026-09-10 19:21:21 +03:00

113 lines
3.8 KiB
JavaScript

#!/usr/bin/env node
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const CODE_EXTENSION = String.raw`\.[cm]?[jt]sx?$`;
const noRuntimeImpact = [
/^\.codex\//,
/^\.tmp-tests\//,
/^docs\//,
/^test\//,
/^workpack\//,
/^(?:AGENTS|PRODUCT|README)\.md$/,
/^context\.md$/,
/^\.env\.example$/,
/^\.gitignore$/,
/^Dockerfile\.client$/,
/^docker-compose\.client(?:\.local)?\.yml$/,
/^entrypoint\.client\.sh$/,
/^install\.sh$/,
/^scripts\/(?:check-import-boundaries\.mjs|clean-test-dist\.mjs|harbor-network-monitor\.sh|harbor-version\.mjs|install-macos-client\.sh)$/,
/^tools\/test-singbox-(?:client-rc|gateway-native-traffic|native-traffic)\.sh$/,
];
const foundation = [
/^\.node-version$/,
/^scripts\/check-sqlite-runtime\.mjs$/,
/^\.dockerignore$/,
/^\.gitea\/workflows\//,
/^Dockerfile(?:\.runtime-base)?$/,
/^docker-compose\.gateway\.yml$/,
/^entrypoint\.sh$/,
/^package(?:-lock)?\.json$/,
/^scripts\/(?:build-on-107-deploy-111|build-runtime-base|deploy-gateway)\.sh$/,
/^scripts\/runtime-impact\.mjs$/,
/^tsconfig(?:\.[^.]+)?\.json$/,
];
const controlAndDataplane = [
/^src\/server\/services\/(?:sqlite|trafficHistoryStore|trafficHistoryService|trafficHistoryWorker)\.ts$/,
/^src\/shared\/trafficHistory\.ts$/,
/^buf\.gen\.yaml$/,
/^proto\//,
new RegExp(`^src/server/main${CODE_EXTENSION}`),
new RegExp(`^src/server/(?:config|gatewayNativeRuntime|gatewayRouting|singbox|singboxRuntime|version)${CODE_EXTENSION}`),
/^src\/server\/generated\//,
new RegExp(`^src/server/adapters/neighbors${CODE_EXTENSION}`),
new RegExp(`^src/server/services/(?:connectivityDiagnosticsService|deviceInventoryService|devicePolicyService|liveTrafficService|singboxSelectorService)${CODE_EXTENSION}`),
new RegExp(`^src/shared/(?:connectivityDiagnostics|errors|liveTraffic)${CODE_EXTENSION}`),
/^src\/server\/infrastructure\/dataplane\//,
];
const dataplane = [
new RegExp(`^src/server/dataplane${CODE_EXTENSION}`),
new RegExp(`^src/server/services/(?:deviceTrafficService|domainTrafficService)${CODE_EXTENSION}`),
];
const control = [
/^index\.html$/,
/^monitoring\//,
/^public\//,
/^src\/server\//,
/^src\/shared\//,
/^src\/web\//,
/^vite\.config\.[cm]?[jt]s$/,
];
function matchesAny(file, patterns) {
return patterns.some((pattern) => pattern.test(file));
}
function normalizeFile(file) {
return file.trim().replaceAll('\\', '/').replace(/^\.\//, '');
}
export function classifyRuntimeImpact(files) {
const affected = new Set();
for (const value of files) {
const file = normalizeFile(value);
if (!file || matchesAny(file, noRuntimeImpact)) continue;
if (matchesAny(file, foundation) || matchesAny(file, controlAndDataplane)) {
affected.add('control');
affected.add('dataplane');
} else if (matchesAny(file, dataplane)) {
affected.add('dataplane');
} else if (matchesAny(file, control)) {
affected.add('control');
} else {
throw new Error(`Unclassified path: ${file}`);
}
}
const affectedComponents = ['control', 'dataplane'].filter((component) => affected.has(component));
const restartScope = affected.has('dataplane') ? 'both' : affected.has('control') ? 'control' : 'none';
return { affectedComponents, restartScope };
}
function formatImpact(impact) {
return [
`affected-components=${impact.affectedComponents.join('+') || 'none'}`,
`restart-scope=${impact.restartScope}`,
].join('\n');
}
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
try {
const args = process.argv.slice(2);
const files = args.includes('--stdin')
? fs.readFileSync(0, 'utf8').split(/\r?\n/)
: args;
console.log(formatImpact(classifyRuntimeImpact(files)));
} catch (error) {
console.error(`[runtime-impact] ${error.message}`);
process.exitCode = 1;
}
}