From c7c6832becf1b6e17c16f07be6b06544d6ccb08b Mon Sep 17 00:00:00 2001 From: Codex Date: Wed, 1 Jul 2026 13:03:56 +0000 Subject: [PATCH] fix: render sub2api apply output concisely --- scripts/src/platform-infra/options.ts | 133 +++++++++++++++++++++++++- 1 file changed, 131 insertions(+), 2 deletions(-) diff --git a/scripts/src/platform-infra/options.ts b/scripts/src/platform-infra/options.ts index 3dade8e2..310d6b5f 100644 --- a/scripts/src/platform-infra/options.ts +++ b/scripts/src/platform-infra/options.ts @@ -71,7 +71,11 @@ export async function runPlatformInfraCommand(config: UniDeskConfig, args: strin const result = plan(parseTargetOptions(planArgs)); return planArgs.includes("--full") || planArgs.includes("--raw") ? result : renderSub2ApiPlan(result); } - if (action === "apply") return await apply(config, parseApplyOptions(args.slice(2))); + if (action === "apply") { + const options = parseApplyOptions(args.slice(2)); + const result = await apply(config, options); + return options.full || options.raw ? result : renderSub2ApiApply(result); + } if (action === "status") { const options = parseDisclosureOptions(args.slice(2)); const result = await status(config, options); @@ -90,6 +94,8 @@ export interface ApplyOptions { dryRun: boolean; confirm: boolean; wait: boolean; + full: boolean; + raw: boolean; } export interface DisclosureOptions { @@ -207,6 +213,126 @@ function renderSub2ApiStatus(result: Record): RenderedCliResult return rendered(result, "platform-infra sub2api status", lines); } +function renderSub2ApiApply(result: Record): RenderedCliResult { + const target = record(result.target); + const remote = record(result.remote); + const policy = arrayRecords(result.policy); + const failedPolicy = policy.filter((item) => item.ok === false); + const mode = stringValue(result.mode); + const targetId = stringValue(target.id, stringValue(result.target)); + const route = stringValue(target.route, stringValue(remote.route)); + const namespace = stringValue(target.namespace, "-"); + const status = result.ok === false ? "failed" : "ok"; + const lines = [ + "PLATFORM-INFRA SUB2API APPLY", + ...table(["TARGET", "ROUTE", "NAMESPACE", "MODE", "STATUS"], [[targetId, route, namespace, mode, status]]), + "", + "POLICY", + failedPolicy.length === 0 ? "ok" : `failed=${failedPolicy.length}`, + ]; + + if (mode === "policy-blocked") { + lines.push( + "", + "FAILED POLICY", + ...(failedPolicy.length === 0 ? ["-"] : table(["NAME", "DETAIL"], failedPolicy.map((item) => [stringValue(item.name), stringValue(item.detail)]))), + "", + "NEXT", + ` plan: bun scripts/cli.ts platform-infra sub2api plan --target ${targetId}`, + ` full: bun scripts/cli.ts platform-infra sub2api apply --target ${targetId} --dry-run --full`, + ); + return rendered(result, "platform-infra sub2api apply", lines); + } + + if (mode === "async-job") { + const job = record(result.job); + const next = record(result.next); + lines.push( + "", + "JOB", + ...table(["ID", "STATUS", "COMMAND"], [[stringValue(job.id), stringValue(job.status, "started"), stringValue(result.statusCommand)]]), + "", + "NEXT", + ` status: ${stringValue(next.status, stringValue(result.statusCommand))}`, + ` rollout: ${stringValue(next.rollout, `bun scripts/cli.ts platform-infra sub2api status --target ${targetId}`)}`, + ` validate: ${stringValue(next.validate, `bun scripts/cli.ts platform-infra sub2api validate --target ${targetId}`)}`, + ` full: bun scripts/cli.ts platform-infra sub2api apply --target ${targetId} --confirm --wait --full`, + ); + return rendered(result, "platform-infra sub2api apply", lines); + } + + lines.push( + "", + "REMOTE", + ...renderApplyRemoteSummary(remote), + ); + + const pk01Exposure = record(result.pk01Exposure); + if (Object.keys(pk01Exposure).length > 0) { + lines.push( + "", + "PK01_EXPOSURE", + ...table(["CHECK", "VALUE"], [ + ["ok", boolText(pk01Exposure.ok)], + ["mode", stringValue(pk01Exposure.mode)], + ["valuesPrinted", "false"], + ]), + ); + } + + const next = record(result.next); + lines.push( + "", + "NEXT", + ` status: ${stringValue(next.status, `bun scripts/cli.ts platform-infra sub2api status --target ${targetId}`)}`, + ` validate: ${stringValue(next.validate, `bun scripts/cli.ts platform-infra sub2api validate --target ${targetId}`)}`, + ` full: bun scripts/cli.ts platform-infra sub2api apply --target ${targetId} ${mode === "confirmed" ? "--confirm --wait" : "--dry-run"} --full`, + "Disclosure: default output is bounded; use --full or --raw for remote stdout/stderr details.", + ); + return rendered(result, "platform-infra sub2api apply", lines); +} + +function renderApplyRemoteSummary(remote: Record): string[] { + const steps = record(remote.steps); + const stepRows = Object.entries(steps).map(([name, value]) => { + const step = record(value); + return [name, stringValue(step.exitCode), step.exitCode === 0 ? "ok" : "failed"]; + }); + for (const name of ["clientDryRun", "serverDryRun", "accountLocalProxySecretDryRun"]) { + const step = record(remote[name]); + if (step.exitCode !== undefined) stepRows.push([name, stringValue(step.exitCode), step.exitCode === 0 ? "ok" : "failed"]); + } + const ports = record(remote.ports); + const runtime = stringValue(remote.runtimeMode, record(remote.serverDryRun).exitCode !== undefined ? "k3s" : "-"); + const rows = [ + ["ok", boolText(remote.ok), "runtime", runtime], + ["target", stringValue(remote.target), "route", stringValue(remote.route)], + ]; + if (remote.namespace !== undefined) rows.push(["namespace", stringValue(remote.namespace), "existsBeforeDryRun", boolText(remote.namespaceExistsBeforeDryRun)]); + if (remote.image !== undefined || remote.projectName !== undefined) rows.push(["image", stringValue(remote.image), "project", stringValue(remote.projectName)]); + const lines = [ + ...table(["FIELD", "VALUE", "DETAIL", "VALUE"], rows), + ]; + if (Object.keys(ports).length > 0) { + lines.push( + "", + "PORTS", + ...table(["NAME", "VALUE"], [ + ["app", stringValue(ports.app)], + ["redis", stringValue(ports.redis)], + ["observed", stringValue(ports.observed).replace(/\s+/gu, " ").trim()], + ]), + ); + } + lines.push( + "", + "STEPS", + ...(stepRows.length === 0 ? ["-"] : table(["STEP", "EXIT", "STATUS"], stepRows)), + "valuesPrinted=false", + ); + return lines; +} + function rendered(result: Record, command: string, lines: string[]): RenderedCliResult { return { ok: result.ok !== false, @@ -254,13 +380,16 @@ export function unsupported(args: string[]): Record { export function parseApplyOptions(args: string[]): ApplyOptions { const target = parseTargetOptions(args); - validateOptions(args, new Set(["--dry-run", "--confirm", "--wait", "--target"])); + validateOptions(args, new Set(["--dry-run", "--confirm", "--wait", "--target", "--full", "--raw"])); if (args.includes("--dry-run") && args.includes("--confirm")) throw new Error("apply accepts only one of --dry-run or --confirm"); + const raw = args.includes("--raw"); return { targetId: target.targetId, dryRun: args.includes("--dry-run") || !args.includes("--confirm"), confirm: args.includes("--confirm"), wait: args.includes("--wait"), + full: raw || args.includes("--full"), + raw, }; }