fix: YAML-first 治理 CI/CD target (#919)

* docs: specify cicd yaml target governance

* fix: resolve cicd targets from yaml

---------

Co-authored-by: Codex <codex@noreply.local>
This commit is contained in:
Lyon
2026-06-26 01:14:38 +08:00
committed by GitHub
parent 3777577df4
commit edfddd2445
35 changed files with 1079 additions and 181 deletions
+7 -5
View File
@@ -1,4 +1,5 @@
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. cleanup module for scripts/src/ci.ts.
// SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets.
// Moved mechanically from scripts/src/ci.ts:1206-1428 for #903.
@@ -24,7 +25,7 @@ import { runSshCommandCapture } from "../ssh";
import type { CiCleanupFailedPodsOptions, CiCleanupRunsOptions, CiTarget } from "./types";
import { ciTargetGuardShellLines, shellQuote, tailTextLines } from "./options";
import { runRemoteKubectl } from "./remote";
import { ciTarget, tektonPipelineVersion, tektonTriggersVersion } from "./types";
import { ciTarget, ciTargetSourceSummary, tektonPipelineVersion, tektonTriggersVersion } from "./types";
export async function status(target = ciTarget(null)): Promise<Record<string, unknown>> {
const summary = await runRemoteKubectl([
@@ -40,6 +41,7 @@ export async function status(target = ciTarget(null)): Promise<Record<string, un
return {
ok: true,
providerId: target.providerId,
target: ciTargetSourceSummary(target),
orchestrator: "native-k3s",
tekton: {
pipelineVersion: tektonPipelineVersion,
@@ -156,8 +158,8 @@ export async function cleanupRuns(config: UniDeskConfig, options: CiCleanupRunsO
stderrTail: tailTextLines(deletion.stderr, 80),
},
next: options.confirm
? { status: `bun scripts/cli.ts ci status --provider-id ${options.target.providerId}` }
: { confirm: `bun scripts/cli.ts ci cleanup-runs --provider-id ${options.target.providerId} --min-age-minutes ${options.minAgeMinutes} --limit ${options.limit} --confirm` },
? { status: `bun scripts/cli.ts ci status --target ${options.target.targetId}` }
: { confirm: `bun scripts/cli.ts ci cleanup-runs --target ${options.target.targetId} --min-age-minutes ${options.minAgeMinutes} --limit ${options.limit} --confirm` },
};
}
@@ -244,7 +246,7 @@ export async function cleanupFailedPods(config: UniDeskConfig, options: CiCleanu
stderrTail: tailTextLines(result.stderr, 20),
},
next: options.confirm
? { status: `bun scripts/cli.ts ci status --provider-id ${options.target.providerId}` }
: { confirm: `bun scripts/cli.ts ci cleanup-failed-pods --provider-id ${options.target.providerId} --namespace ${options.namespace} --min-age-minutes ${options.minAgeMinutes} --limit ${options.limit} --confirm` },
? { status: `bun scripts/cli.ts ci status --target ${options.target.targetId}` }
: { confirm: `bun scripts/cli.ts ci cleanup-failed-pods --target ${options.target.targetId} --namespace ${options.namespace} --min-age-minutes ${options.minAgeMinutes} --limit ${options.limit} --confirm` },
};
}
+20 -4
View File
@@ -1,4 +1,5 @@
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. entry module for scripts/src/ci.ts.
// SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets.
// Moved mechanically from scripts/src/ci.ts:3410-3600 for #903.
@@ -29,7 +30,7 @@ import { logs } from "./logs";
import { blockedArtifactResult, blockedReason, boolFlag, ciCleanupFailedPodsOptions, ciCleanupRunsOptions, ciLogsOptions, isHelpArg, numberOption, publishTransportOption, requireDesiredRef, requireFullCommit, requireRepoRelativePath, requireRevision, requireServiceId, resolveCatalogArtifact, stringOption, userServicePublishBoundaryBlock } from "./options";
import { backendCoreArtifactSourceHostPath, userServiceArtifactSourceHostPath } from "./pipelinerun";
import { publishBackendCoreArtifact, publishUserServiceArtifact, run } from "./publish";
import { ciTarget, d601ProviderId, providerIdOption } from "./types";
import { ciTarget, ciTargetSourceSummary, providerIdOption } from "./types";
export async function runCiCommand(config: UniDeskConfig, args: string[]): Promise<Record<string, unknown>> {
const [action = "status", nameArg] = args;
@@ -44,6 +45,21 @@ export async function runCiCommand(config: UniDeskConfig, args: string[]): Promi
return options.wait ? install(config, options) : installAsync(options);
}
if (action === "install-status") return installStatus(nameArg ?? "latest");
if (action === "plan") {
const target = ciTarget(providerIdOption(args));
return {
ok: true,
action: "ci-plan",
mutation: false,
target: ciTargetSourceSummary(target),
configTruth: target.configSource.configPath,
next: {
status: `bun scripts/cli.ts ci status --target ${target.targetId}`,
installDryRun: `bun scripts/cli.ts ci install --target ${target.targetId} --skip-prewarm --skip-tekton-install`,
run: `bun scripts/cli.ts ci run --target ${target.targetId} --revision <commit>`,
},
};
}
if (action === "status") return status(ciTarget(providerIdOption(args)));
if (action === "run") {
const target = ciTarget(providerIdOption(args));
@@ -130,12 +146,12 @@ export async function runCiCommand(config: UniDeskConfig, args: string[]): Promi
if (action === "logs") return logs(config, nameArg ?? "", ciTarget(providerIdOption(args)), ciLogsOptions(args));
if (action === "cleanup-runs") return cleanupRuns(config, ciCleanupRunsOptions(args));
if (action === "cleanup-failed-pods") return cleanupFailedPods(config, ciCleanupFailedPodsOptions(args));
throw new Error("ci command must be one of: install, status, run, publish-backend-core, publish-user-service, run-dev-e2e, logs, cleanup-runs, cleanup-failed-pods");
throw new Error("ci command must be one of: install, plan, status, run, publish-backend-core, publish-user-service, run-dev-e2e, logs, cleanup-runs, cleanup-failed-pods");
}
export function startCiInstallJob(providerId = d601ProviderId): Record<string, unknown> {
export function startCiInstallJob(targetId?: string): Record<string, unknown> {
return installAsync({
target: ciTarget(providerId),
target: ciTarget(targetId ?? null),
skipPrewarm: false,
skipTektonInstall: false,
wait: false,
+9 -7
View File
@@ -1,4 +1,5 @@
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. help module for scripts/src/ci.ts.
// SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets.
// Moved mechanically from scripts/src/ci.ts:3273-3409 for #903.
@@ -58,9 +59,10 @@ export function ciHelp(): Record<string, unknown> {
"bun scripts/cli.ts ci install --skip-prewarm --skip-tekton-install",
"bun scripts/cli.ts ci install-status latest",
"bun scripts/cli.ts ci install --wait --skip-prewarm --skip-tekton-install",
"bun scripts/cli.ts ci install --provider-id G14",
"bun scripts/cli.ts ci plan --target D601",
"bun scripts/cli.ts ci install --target G14",
"bun scripts/cli.ts ci run --revision <commit>",
"bun scripts/cli.ts ci run --provider-id G14 --revision <commit>",
"bun scripts/cli.ts ci run --target G14 --revision <commit>",
"bun scripts/cli.ts ci publish-backend-core --commit <full-sha>",
"bun scripts/cli.ts ci publish-user-service --service baidu-netdisk --commit <full-sha>",
"bun scripts/cli.ts ci publish-user-service --service mdtodo --commit <full-sha>",
@@ -69,11 +71,11 @@ export function ciHelp(): Record<string, unknown> {
"bun scripts/cli.ts ci publish-user-service --service decision-center --commit <full-sha>",
"bun scripts/cli.ts ci publish-user-service --service frontend --commit <full-sha>",
"bun scripts/cli.ts ci run-dev-e2e --wait-ms 600000",
"bun scripts/cli.ts ci logs <runId-or-pipelineRun> [--provider-id G14] [--tail-lines 80]",
"bun scripts/cli.ts ci cleanup-runs --provider-id D601 --min-age-minutes 60 --limit 50 --dry-run",
"bun scripts/cli.ts ci cleanup-runs --provider-id D601 --min-age-minutes 60 --limit 50 --confirm",
"bun scripts/cli.ts ci cleanup-failed-pods --provider-id D601 --namespace unidesk-ci --min-age-minutes 60 --dry-run",
"bun scripts/cli.ts ci cleanup-failed-pods --provider-id D601 --namespace unidesk-ci --min-age-minutes 60 --confirm",
"bun scripts/cli.ts ci logs <runId-or-pipelineRun> [--target G14] [--tail-lines 80]",
"bun scripts/cli.ts ci cleanup-runs --target D601 --min-age-minutes 60 --limit 50 --dry-run",
"bun scripts/cli.ts ci cleanup-runs --target D601 --min-age-minutes 60 --limit 50 --confirm",
"bun scripts/cli.ts ci cleanup-failed-pods --target D601 --namespace unidesk-ci --min-age-minutes 60 --dry-run",
"bun scripts/cli.ts ci cleanup-failed-pods --target D601 --namespace unidesk-ci --min-age-minutes 60 --confirm",
],
tekton: {
pipelineVersion: tektonPipelineVersion,
+3 -2
View File
@@ -1,4 +1,5 @@
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. install module for scripts/src/ci.ts.
// SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets.
// Moved mechanically from scripts/src/ci.ts:1429-1559 for #903.
@@ -99,8 +100,8 @@ export function ciInstallCommand(options: CiInstallOptions): string[] {
"scripts/cli.ts",
"ci",
"install",
"--provider-id",
options.target.providerId,
"--target",
options.target.targetId,
"--wait",
...(options.skipPrewarm ? ["--skip-prewarm"] : []),
...(options.skipTektonInstall ? ["--skip-tekton-install"] : []),
+6 -2
View File
@@ -1,4 +1,5 @@
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. logs module for scripts/src/ci.ts.
// SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets.
// Moved mechanically from scripts/src/ci.ts:3168-3272 for #903.
@@ -61,6 +62,7 @@ export function pipelineRunLogsScript(name: string, options: CiLogsOptions): str
export function ciLogsResultFromCapture(args: {
ok: boolean;
providerId: string;
targetId: string;
kind: "run" | "pipelinerun";
name: string;
options: CiLogsOptions;
@@ -86,8 +88,8 @@ export function ciLogsResultFromCapture(args: {
...(args.dispatchTaskId === undefined ? {} : { dispatchTaskId: args.dispatchTaskId }),
fullOutputAvailable: args.options.capture === "ssh-stream",
next: [
`bun scripts/cli.ts ci logs ${args.name} --provider-id ${args.providerId} --tail-lines ${Math.min(args.options.tailLines * 2, 2000)}`,
`bun scripts/cli.ts ci status --provider-id ${args.providerId}`,
`bun scripts/cli.ts ci logs ${args.name} --target ${args.targetId} --tail-lines ${Math.min(args.options.tailLines * 2, 2000)}`,
`bun scripts/cli.ts ci status --target ${args.targetId}`,
],
};
}
@@ -104,6 +106,7 @@ export async function logs(config: UniDeskConfig, name: string, target = ciTarge
return ciLogsResultFromCapture({
ok: resultOk,
providerId: target.providerId,
targetId: target.targetId,
kind: "run",
name,
options,
@@ -121,6 +124,7 @@ export async function logs(config: UniDeskConfig, name: string, target = ciTarge
return ciLogsResultFromCapture({
ok: result.exitCode === 0,
providerId: target.providerId,
targetId: target.targetId,
kind: "pipelinerun",
name,
options,
+4 -3
View File
@@ -1,4 +1,5 @@
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. publish-preflight module for scripts/src/ci.ts.
// SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets.
// Moved mechanically from scripts/src/ci.ts:2317-2567 for #903.
@@ -89,7 +90,7 @@ export async function publishUserServicePreflight(
raw: sshProbe.ok ? undefined : dispatchPreflightFailure("host.ssh readonly probe", sshProbe).raw,
}));
const registryOptions = parseArtifactRegistryOptions(["--provider-id", providerId]);
const registryOptions = parseArtifactRegistryOptions(["--target", providerId]);
const registryProbe = buildArtifactRegistryReadonlyProbe("health", registryOptions);
const registryDispatch = await transport.dispatchHostSsh(registryProbe.script, Math.max(registryProbe.timeoutMs, 30_000), registryProbe.timeoutMs);
const registryCommand = commandResultFromDispatch(transport.artifactRegistryCommand(registryProbe), transport.commandCwd, registryDispatch);
@@ -131,7 +132,7 @@ export async function publishUserServicePreflight(
? "From a Code Queue runner, rerun this read-only preflight through the existing remote frontend transport: bun scripts/cli.ts --main-server-ip <host> ci publish-user-service --service <id> --commit <full-sha> --dry-run."
: "Run from the main-server CLI or use remote frontend transport against a healthy frontend/backend-core path.",
"Restore backend-core/database/provider-gateway/Host SSH connectivity before retrying artifact publication.",
"Use bun scripts/cli.ts artifact-registry health --provider-id D601 to recheck registry reachability after the control bridge is restored.",
"Use bun scripts/cli.ts artifact-registry health --target D601 to recheck registry reachability after the control bridge is restored.",
],
boundary: "preflight is read-only: no D601 source export, no Tekton PipelineRun, no image push, no deploy apply, no service restart",
};
@@ -182,7 +183,7 @@ export async function publishBackendCorePreflight(
raw: ciRunnerReady ? undefined : dispatchPreflightFailure("backend-core ci runner readonly probe", ciProbe).raw,
}));
const registryOptions = parseArtifactRegistryOptions(["--provider-id", providerId]);
const registryOptions = parseArtifactRegistryOptions(["--target", providerId]);
const registryProbe = buildArtifactRegistryReadonlyProbe("health", registryOptions);
const registryDispatch = await transport.dispatchHostSsh(registryProbe.script, Math.max(registryProbe.timeoutMs, 30_000), registryProbe.timeoutMs);
const registryCommand = commandResultFromDispatch(transport.artifactRegistryCommand(registryProbe), transport.commandCwd, registryDispatch);
+3 -2
View File
@@ -1,4 +1,5 @@
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. publish module for scripts/src/ci.ts.
// SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets.
// Moved mechanically from scripts/src/ci.ts:2568-2959 for #903.
@@ -56,8 +57,8 @@ export async function run(options: CiOptions): Promise<Record<string, unknown>>
},
condition,
next: [
`bun scripts/cli.ts ci logs ${name} --provider-id ${options.target.providerId}`,
`bun scripts/cli.ts ci status --provider-id ${options.target.providerId}`,
`bun scripts/cli.ts ci logs ${name} --target ${options.target.targetId}`,
`bun scripts/cli.ts ci status --target ${options.target.targetId}`,
],
};
}
+48 -31
View File
@@ -1,4 +1,5 @@
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. types module for scripts/src/ci.ts.
// SPEC: PJ2026-01060308 cicd-yaml-targets draft-2026-06-25-cicd-yaml-targets.
// Moved mechanically from scripts/src/ci.ts:1-267 for #903.
@@ -20,13 +21,17 @@ import {
} from "../artifact-registry";
import { d601K3sGuardShellLines, d601NativeKubeconfig } from "../d601-k3s-guard";
import { runSshCommandCapture } from "../ssh";
import { cicdTargetSummary, resolveCicdTarget, type TargetConfigSource } from "../ops/targets";
import { status } from "./cleanup";
import { stringOption } from "./options";
export const d601ProviderId = "D601";
const d601YamlTarget = resolveCicdTarget("D601");
const g14YamlTarget = resolveCicdTarget("G14");
export const d601Kubeconfig = d601NativeKubeconfig;
export const d601ProviderId = d601YamlTarget.providerId;
export const d601Kubeconfig = d601YamlTarget.kubeconfig;
export const tektonPipelineVersion = "v1.12.0";
@@ -46,9 +51,9 @@ export const codeQueueDirectDockerBaseImage = "unidesk-code-queue:d601";
export const providerDispatchCompletionLagMs = 45_000;
export const defaultCiPipelineManifest = "src/components/microservices/k3sctl-adapter/k3s/ci/unidesk-ci.pipeline.yaml";
export const defaultCiPipelineManifest = d601YamlTarget.pipelineManifest;
export const g14CiPipelineManifest = "src/components/microservices/k3sctl-adapter/k3s/ci/unidesk-ci.pipeline.g14.yaml";
export const g14CiPipelineManifest = g14YamlTarget.pipelineManifest;
export const ciRuntimeImages = [
"rancher/mirrored-pause:3.6",
@@ -65,36 +70,44 @@ export const ciRuntimeImages = [
];
export function ciTarget(providerId: string | null): CiTarget {
const normalized = providerId ?? d601ProviderId;
if (normalized === d601ProviderId) {
return {
providerId: d601ProviderId,
kubeconfig: d601Kubeconfig,
hostCwd: "/home/ubuntu",
homeDir: "/home/ubuntu",
pipelineManifest: defaultCiPipelineManifest,
codeQueueImage: ciCodeQueueImage,
guardName: "d601_native_k3s_guard",
requiredNodeName: "d601",
};
}
if (normalized === "G14") {
return {
providerId: "G14",
kubeconfig: d601Kubeconfig,
hostCwd: "/root",
homeDir: "/root",
pipelineManifest: g14CiPipelineManifest,
codeQueueImage: ciCodeQueueImage,
guardName: "g14_native_k3s_guard",
requiredNodeLabel: { key: "unidesk.ai/node-id", value: "G14" },
};
}
throw new Error(`ci --provider-id currently supports D601 or G14, got ${normalized}`);
const target = resolveCicdTarget(providerId);
return {
targetId: target.targetId,
providerId: target.providerId,
kubeRoute: target.kubeRoute,
kubeconfig: target.kubeconfig,
hostCwd: target.hostCwd,
homeDir: target.homeDir,
pipelineManifest: target.pipelineManifest,
codeQueueImage: target.codeQueueImage,
guardName: target.guardName,
requiredNodeName: target.requiredNodeName,
requiredNodeLabel: target.requiredNodeLabel,
artifactRegistryConfigRef: target.artifactRegistryConfigRef,
configSource: target.configSource,
};
}
export function providerIdOption(args: string[]): string | null {
return stringOption(args, "--provider-id") ?? stringOption(args, "--provider");
return stringOption(args, "--target") ?? stringOption(args, "--provider-id") ?? stringOption(args, "--provider");
}
export function ciTargetSourceSummary(target: CiTarget): Record<string, unknown> {
return cicdTargetSummary({
targetId: target.targetId,
providerId: target.providerId,
kubeRoute: target.kubeRoute,
kubeconfig: target.kubeconfig,
hostCwd: target.hostCwd,
homeDir: target.homeDir,
pipelineManifest: target.pipelineManifest,
codeQueueImage: target.codeQueueImage,
guardName: target.guardName,
requiredNodeName: target.requiredNodeName,
requiredNodeLabel: target.requiredNodeLabel,
artifactRegistryConfigRef: target.artifactRegistryConfigRef,
configSource: target.configSource,
});
}
export interface CiOptions {
@@ -112,7 +125,9 @@ export interface CiInstallOptions {
}
export interface CiTarget {
targetId: string;
providerId: string;
kubeRoute: string;
kubeconfig: string;
hostCwd: string;
homeDir: string;
@@ -121,6 +136,8 @@ export interface CiTarget {
guardName: string;
requiredNodeName?: string;
requiredNodeLabel?: { key: string; value: string };
artifactRegistryConfigRef?: string;
configSource: TargetConfigSource;
}
export interface CiPublishBackendCoreOptions {