refactor: split control-plane cli modules
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
// SPEC: PJ2026-01060307 控制面模块化 draft-2026-06-25-p0. pipelinerun-runtime module for scripts/src/ci.ts.
|
||||
|
||||
// Moved mechanically from scripts/src/ci.ts:1899-1968 for #903.
|
||||
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { existsSync, mkdtempSync, readFileSync, rmSync } from "node:fs";
|
||||
import { tmpdir } from "node:os";
|
||||
import { join, posix as posixPath } from "node:path";
|
||||
import { blockedCatalogArtifactIds, catalogSummary, findCiCatalogArtifact, loadCiCatalog, supportedSourceBuildArtifactIds, type CiCatalogArtifact, type CiSourceBuildCatalogArtifact, type CiUpstreamImageCatalogArtifact } from "../ci-catalog";
|
||||
import { runCommand } from "../command";
|
||||
import { type UniDeskConfig, repoRoot, rootPath } from "../config";
|
||||
import { ensureGithubSshIdentityForProvider, gitSshHttpConnectProxySource } from "../deploy-ssh-identity";
|
||||
import { jobWithTail, listJobs, readJob, startJob } from "../jobs";
|
||||
import { coreInternalFetch } from "../microservices";
|
||||
import {
|
||||
artifactRegistryReadonlyResultFromCommand,
|
||||
buildArtifactRegistryReadonlyProbe,
|
||||
parseArtifactRegistryOptions,
|
||||
type ArtifactRegistryReadonlyProbe,
|
||||
} from "../artifact-registry";
|
||||
import { d601K3sGuardShellLines, d601NativeKubeconfig } from "../d601-k3s-guard";
|
||||
import { runSshCommandCapture } from "../ssh";
|
||||
|
||||
import type { DispatchResult, PipelineRunCondition } from "./types";
|
||||
import { status } from "./cleanup";
|
||||
import { ciTargetGuardShellLines, shellQuote } from "./options";
|
||||
import { dispatchSsh, runRemoteKubectl, runRemoteKubectlRaw, uploadRemoteBase64 } from "./remote";
|
||||
import { ciTarget } from "./types";
|
||||
|
||||
export async function remoteCreatePipelineRun(manifest: string, target = ciTarget(null)): Promise<string> {
|
||||
const encoded = Buffer.from(manifest, "utf8").toString("base64");
|
||||
const token = randomUUID().replace(/-/gu, "").slice(0, 12);
|
||||
const b64Path = `/tmp/unidesk-ci-pipelinerun-${token}.b64`;
|
||||
const upload = await uploadRemoteBase64(b64Path, encoded, target);
|
||||
if (!upload.ok) throw new Error(`failed to upload PipelineRun manifest: ${upload.stderr || upload.stdout}`);
|
||||
const result = await runRemoteKubectl([
|
||||
"tmp=$(mktemp /tmp/unidesk-ci-run.XXXXXX.yaml)",
|
||||
`b64_path=${shellQuote(b64Path)}`,
|
||||
"trap 'rm -f \"$tmp\" \"$b64_path\"' EXIT",
|
||||
"base64 -d \"$b64_path\" > \"$tmp\"",
|
||||
"kubectl create -f \"$tmp\" -o jsonpath='{.metadata.name}'",
|
||||
].join("\n"), 60_000, 45_000, target);
|
||||
return result.stdout.trim();
|
||||
}
|
||||
|
||||
export async function waitForPipelineRun(name: string, waitMs: number, target = ciTarget(null)): Promise<DispatchResult | null> {
|
||||
if (waitMs <= 0) return null;
|
||||
const command = [
|
||||
"set -euo pipefail",
|
||||
...ciTargetGuardShellLines(target),
|
||||
`printf 'waiting_pipelinerun=%s\\n' ${shellQuote(name)}`,
|
||||
`deadline=$((SECONDS + ${Math.ceil(waitMs / 1000)}))`,
|
||||
"while [ \"$SECONDS\" -lt \"$deadline\" ]; do",
|
||||
` condition="$(kubectl get pipelinerun/${shellQuote(name)} -n unidesk-ci -o jsonpath='{range .status.conditions[?(@.type==\"Succeeded\")]}{.status}{\"\\t\"}{.reason}{\"\\t\"}{.message}{end}' 2>/dev/null || true)"`,
|
||||
" case \"$condition\" in",
|
||||
" True*)",
|
||||
" printf 'condition=%s\\n' \"$condition\"",
|
||||
` kubectl get taskrun -n unidesk-ci -l tekton.dev/pipelineRun=${shellQuote(name)} --no-headers 2>/dev/null || true`,
|
||||
" exit 0",
|
||||
" ;;",
|
||||
" False*)",
|
||||
" printf 'condition=%s\\n' \"$condition\"",
|
||||
` kubectl get taskrun,pod -n unidesk-ci -l tekton.dev/pipelineRun=${shellQuote(name)} 2>/dev/null || true`,
|
||||
" exit 1",
|
||||
" ;;",
|
||||
" esac",
|
||||
" sleep 2",
|
||||
"done",
|
||||
`echo "Timed out waiting for pipelinerun/${name}" >&2`,
|
||||
`kubectl get pipelinerun/${shellQuote(name)} -n unidesk-ci -o json`,
|
||||
"exit 124",
|
||||
].join("\n");
|
||||
return dispatchSsh(command, waitMs + 30_000, waitMs + 20_000, true, target);
|
||||
}
|
||||
|
||||
export async function readPipelineRunCondition(name: string, target = ciTarget(null)): Promise<PipelineRunCondition> {
|
||||
const result = await runRemoteKubectlRaw([
|
||||
"set -euo pipefail",
|
||||
`condition="$(kubectl get pipelinerun/${shellQuote(name)} -n unidesk-ci -o jsonpath='{range .status.conditions[?(@.type==\"Succeeded\")]}{.status}{\"\\t\"}{.reason}{\"\\t\"}{.message}{end}' 2>/dev/null || true)"`,
|
||||
"printf '%s\\n' \"$condition\"",
|
||||
].join("\n"), 30_000, 15_000, target);
|
||||
const [status = "", reason = "", ...messageParts] = result.stdout.trim().split("\t");
|
||||
const message = messageParts.join("\t");
|
||||
return {
|
||||
ok: status === "True" ? true : status === "False" ? false : null,
|
||||
status,
|
||||
reason,
|
||||
message,
|
||||
query: {
|
||||
ok: result.ok,
|
||||
status: result.status,
|
||||
exitCode: result.exitCode,
|
||||
stdoutTail: result.stdout.slice(-1200),
|
||||
stderrTail: result.stderr.slice(-1200),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function pipelineRunWaitSucceeded(wait: DispatchResult | null, condition: PipelineRunCondition | null): boolean {
|
||||
if (wait === null) return true;
|
||||
if (condition?.ok === true) return true;
|
||||
if (condition?.ok === false) return false;
|
||||
return wait.ok || wait.exitCode === 0 || wait.stdout.includes("condition=True\tSucceeded\t");
|
||||
}
|
||||
Reference in New Issue
Block a user