Files
pikasTech-unidesk/scripts/ci-install-visibility-contract-test.ts
T
2026-06-11 10:34:43 +00:00

89 lines
4.0 KiB
TypeScript

import { readFileSync } from "node:fs";
import { ciHelp } from "./src/ci";
function assertCondition(condition: unknown, message: string, detail: unknown = {}): void {
if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
}
const source = readFileSync("scripts/src/ci.ts", "utf8");
const jobsSource = readFileSync("scripts/src/jobs.ts", "utf8");
const help = JSON.stringify(ciHelp());
assertCondition(
source.includes("interface CiInstallOptions")
&& source.includes("skipPrewarm: boolFlag(args, \"--skip-prewarm\")")
&& source.includes("skipTektonInstall: boolFlag(args, \"--skip-tekton-install\")")
&& source.includes("wait: boolFlag(args, \"--wait\")")
&& source.includes("prewarm: options.skipPrewarm ? \"skipped\" : \"completed\"")
&& source.includes("tektonInstall: options.skipTektonInstall ? \"skipped\" : \"completed\""),
"ci install must expose controlled manifest refresh skip modes",
);
assertCondition(
source.includes("function installAsync(options: CiInstallOptions)")
&& source.includes("\"ci_install\"")
&& source.includes("ciInstallCommand(options)")
&& source.includes("options.wait ? install(config, options) : installAsync(options)")
&& source.includes("if (action === \"install-status\") return installStatus(nameArg ?? \"latest\")"),
"ci install must default to async job mode with status follow-up",
);
assertCondition(
source.includes("event: \"ci.install.progress\"")
&& source.includes("emitCiInstallProgress(\"apply-manifest\", \"started\"")
&& source.includes("emitCiInstallProgress(\"upload-manifest\", \"started\"")
&& source.includes("emitCiInstallProgress(\"kubectl-apply\", \"started\"")
&& source.includes("emitCiInstallProgress(\"install\", \"failed\"")
&& jobsSource.includes("summarizeCiInstallJobProgress")
&& jobsSource.includes("parseJsonLineEvents(stderrTail, \"ci.install.progress\")"),
"ci install job status must expose stage progress events",
);
assertCondition(
source.includes("timeoutMs: Math.min(Math.max(waitMs, 15_000), 45_000)")
&& source.includes("maxResponseBytes: 3_000_000, timeoutMs: 15_000")
&& source.includes("backend-core-dispatch-timeout"),
"ci dispatch submit must use bounded backend-core fetch timeout",
);
assertCondition(
source.includes("runSshCommandCapture(config, `${target.providerId}:k3s`, [\"script\"], script)")
&& source.includes("base64 -d > \\\"$tmp\\\" <<'UNIDESK_CI_MANIFEST_B64'")
&& source.includes("test -s \\\"$tmp\\\"")
&& source.includes("manifest_bytes="),
"ci manifest apply must embed YAML through k3s route script with byte visibility",
);
assertCondition(
source.includes("ci_runtime_image_containerd_root_required=true")
&& source.includes("failureLines")
&& source.includes("rerun with: bun scripts/cli.ts ci install --skip-prewarm"),
"ci prewarm failure must expose concise root/containerd visibility and recovery",
);
assertCondition(
help.includes("ci install --skip-prewarm")
&& help.includes("ci install --skip-prewarm --skip-tekton-install")
&& help.includes("ci install-status latest")
&& help.includes("ci install --wait --skip-prewarm --skip-tekton-install")
&& help.includes("async-job")
&& help.includes("Use --wait only for explicit synchronous debugging")
&& help.includes("Use --skip-prewarm only to refresh Tekton/CI manifests")
&& help.includes("Use --skip-tekton-install with --skip-prewarm only when Tekton is already installed"),
"ci help must document manifest refresh boundaries",
ciHelp(),
);
console.log(JSON.stringify({
ok: true,
checks: [
"ci install exposes controlled manifest refresh skip modes",
"ci install defaults to async job mode with status follow-up",
"ci install job status exposes stage progress events",
"ci dispatch submit uses bounded backend-core fetch timeout",
"ci manifest apply embeds YAML through k3s route script with byte visibility",
"ci prewarm failure exposes concise root/containerd recovery",
"ci help documents manifest refresh boundaries",
],
}));