cicd branch follower native closeout
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
// SPEC: PJ2026-01060703 CI/CD branch follower native Kubernetes helpers.
|
||||
// Responsibility: submit/probe Kubernetes Jobs and Tekton PipelineRuns via file-backed native scripts.
|
||||
import { repoRoot, rootPath } from "./config";
|
||||
import { runCommand, type CommandResult } from "./command";
|
||||
import type { NativeK8sJobResult } from "./cicd-types";
|
||||
|
||||
const NATIVE_SCRIPT_DIR = "scripts/native/cicd";
|
||||
|
||||
export function runNativeTektonPipelineRun(namespace: string, pipelineRun: string, manifest: Record<string, unknown>, wait: boolean, timeoutSeconds: number): CommandResult {
|
||||
return runCommand(["node", rootPath(NATIVE_SCRIPT_DIR, "submit-pipelinerun.mjs")], repoRoot, {
|
||||
input: Buffer.from(JSON.stringify(manifest), "utf8").toString("base64"),
|
||||
timeoutMs: Math.max(5, timeoutSeconds + 10) * 1000,
|
||||
env: {
|
||||
...process.env,
|
||||
NAMESPACE: namespace,
|
||||
PIPELINERUN: pipelineRun,
|
||||
WAIT: wait ? "true" : "false",
|
||||
TIMEOUT_SECONDS: String(timeoutSeconds),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function runNativeK8sJob(namespace: string, jobName: string, manifest: Record<string, unknown>, timeoutSeconds: number, logContainer: string): NativeK8sJobResult {
|
||||
const result = runCommand(["node", rootPath(NATIVE_SCRIPT_DIR, "native-job.mjs")], repoRoot, {
|
||||
input: Buffer.from(JSON.stringify(manifest), "utf8").toString("base64"),
|
||||
timeoutMs: Math.max(5, timeoutSeconds + 10) * 1000,
|
||||
env: {
|
||||
...process.env,
|
||||
NAMESPACE: namespace,
|
||||
JOB_NAME: jobName,
|
||||
LOG_CONTAINER: logContainer,
|
||||
TIMEOUT_SECONDS: String(timeoutSeconds),
|
||||
},
|
||||
});
|
||||
const parsed = result.exitCode === 0 ? parseJsonObject(result.stdout) : null;
|
||||
return {
|
||||
ok: result.exitCode === 0 && parsed?.ok === true,
|
||||
completed: parsed?.completed === true,
|
||||
failed: parsed?.failed === true || result.exitCode !== 0,
|
||||
timedOut: parsed?.timedOut === true || result.timedOut,
|
||||
created: parsed?.created === true,
|
||||
reused: parsed?.reused === true,
|
||||
jobName,
|
||||
namespace,
|
||||
polls: numberOrNull(parsed?.polls) ?? 0,
|
||||
elapsedMs: numberOrNull(parsed?.elapsedMs) ?? 0,
|
||||
logsTail: stringOrNull(parsed?.logsTail),
|
||||
conditionReason: stringOrNull(parsed?.conditionReason),
|
||||
conditionMessage: stringOrNull(parsed?.conditionMessage) ?? (result.exitCode === 0 ? null : tailText(result.stderr || result.stdout, 500)),
|
||||
statusAuthority: "kubernetes-api-serviceaccount",
|
||||
parsedDownstreamCliOutput: false,
|
||||
};
|
||||
}
|
||||
|
||||
function parseJsonObject(text: string): Record<string, unknown> | null {
|
||||
const trimmed = text.trim();
|
||||
if (trimmed.length === 0) return null;
|
||||
try {
|
||||
const parsed = JSON.parse(trimmed) as unknown;
|
||||
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed as Record<string, unknown> : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function stringOrNull(value: unknown): string | null {
|
||||
return typeof value === "string" && value.length > 0 ? value : null;
|
||||
}
|
||||
|
||||
function numberOrNull(value: unknown): number | null {
|
||||
return typeof value === "number" && Number.isFinite(value) ? value : null;
|
||||
}
|
||||
|
||||
function tailText(text: string, maxChars: number): string {
|
||||
return text.length <= maxChars ? text : text.slice(text.length - maxChars);
|
||||
}
|
||||
Reference in New Issue
Block a user