import { readFileSync } from "node:fs"; const key = process.argv[2] || ""; const input = JSON.parse(readFileSync(0, "utf8")); function cleanMap(value) { if (!value || typeof value !== "object" || Array.isArray(value)) return {}; const out = {}; for (const [k, v] of Object.entries(value)) { if (k === "kubectl.kubernetes.io/last-applied-configuration") continue; out[k] = v; } return out; } function metadata(obj) { return { name: obj?.metadata?.name || null, namespace: obj?.metadata?.namespace || null, labels: cleanMap(obj?.metadata?.labels), annotations: cleanMap(obj?.metadata?.annotations), }; } function compactContainer(container) { return { name: container?.name || null, image: container?.image || null, env: Array.isArray(container?.env) ? container.env.filter((item) => item && typeof item.name === "string" && typeof item.value === "string").map((item) => ({ name: item.name, value: item.value })) : [], }; } function condition(obj, type) { const conditions = Array.isArray(obj?.status?.conditions) ? obj.status.conditions : []; return conditions.find((item) => item?.type === type) || conditions[0] || null; } function timestampMs(value) { const parsed = Date.parse(String(value || "")); return Number.isFinite(parsed) ? parsed : null; } function durationSeconds(start, end) { const s = timestampMs(start); const e = timestampMs(end); return s === null || e === null || e < s ? null : Math.round((e - s) / 1000); } let output = input; if (key === "pipelineRun") { const succeeded = condition(input, "Succeeded"); output = { apiVersion: input.apiVersion, kind: input.kind, metadata: metadata(input), spec: { pipelineRef: { name: input?.spec?.pipelineRef?.name || null }, params: Array.isArray(input?.spec?.params) ? input.spec.params : [], }, status: { conditions: Array.isArray(input?.status?.conditions) ? input.status.conditions : [], startTime: input?.status?.startTime || null, completionTime: input?.status?.completionTime || null, durationSeconds: durationSeconds(input?.status?.startTime, input?.status?.completionTime), succeeded: succeeded?.status || null, reason: succeeded?.reason || null, }, }; } else if (key === "pipeline") { const tasks = Array.isArray(input?.spec?.tasks) ? input.spec.tasks : []; const runtimeReady = tasks.find((item) => item?.name === "runtime-ready") || null; const gitopsPromote = tasks.find((item) => item?.name === "gitops-promote") || null; const gitopsResults = Array.isArray(gitopsPromote?.taskSpec?.results) ? gitopsPromote.taskSpec.results : []; output = { apiVersion: input.apiVersion, kind: input.kind, metadata: { name: input?.metadata?.name || null, namespace: input?.metadata?.namespace || null, annotations: { sourceConfig: input?.metadata?.annotations?.["hwlab.pikastech.local/source-config"] || null, ciContract: input?.metadata?.annotations?.["hwlab.pikastech.local/ci-contract"] || null, policy: input?.metadata?.annotations?.["hwlab.pikastech.local/policy"] || null, }, }, spec: { taskCount: tasks.length, runtimeReadyTask: { present: runtimeReady !== null, name: runtimeReady?.name || null, runAfter: Array.isArray(runtimeReady?.runAfter) ? runtimeReady.runAfter.slice(0, 6) : [], when: Array.isArray(runtimeReady?.when) ? runtimeReady.when.slice(0, 4).map((item) => ({ input: item?.input || null, operator: item?.operator || null, values: Array.isArray(item?.values) ? item.values.slice(0, 6) : [], })) : [], }, gitopsPromoteTask: { present: gitopsPromote !== null, name: gitopsPromote?.name || null, resultNames: gitopsResults .map((item) => item?.name || null) .filter((item) => typeof item === "string") .slice(0, 8), runtimeReadyRequiredResult: gitopsResults.some((item) => item?.name === "runtime-ready-required"), }, }, }; } else if (key === "taskRuns") { const items = (Array.isArray(input?.items) ? input.items : []).map((item) => { const succeeded = condition(item, "Succeeded"); return { name: item?.metadata?.name || null, namespace: item?.metadata?.namespace || null, pipelineTask: item?.metadata?.labels?.["tekton.dev/pipelineTask"] || item?.metadata?.labels?.["tekton.dev/task"] || null, status: succeeded?.status || null, reason: succeeded?.reason || null, startTime: item?.status?.startTime || null, completionTime: item?.status?.completionTime || null, durationSeconds: durationSeconds(item?.status?.startTime, item?.status?.completionTime), }; }).sort((left, right) => String(left.startTime || "").localeCompare(String(right.startTime || ""))); const slow = items.filter((item) => typeof item.durationSeconds === "number" && item.durationSeconds > 60); output = { ok: true, count: items.length, succeededCount: items.filter((item) => item.status === "True").length, failedCount: items.filter((item) => item.status === "False").length, activeCount: items.filter((item) => item.status !== "True" && item.status !== "False").length, items, performance: { slowCount: slow.length, slowTaskRuns: slow.slice(0, 8), warning: slow.length > 0 ? "taskrun-over-60s" : null }, statusAuthority: "kubernetes-api-serviceaccount", }; } else if (key === "argoApplication") { const resources = Array.isArray(input?.status?.resources) ? input.status.resources : []; const syncResultResources = Array.isArray(input?.status?.operationState?.syncResult?.resources) ? input.status.operationState.syncResult.resources .filter(problemSyncResource) .slice(0, 8) .map((item) => ({ group: item.group || null, kind: item.kind || null, namespace: item.namespace || null, name: item.name || null, status: item.status || null, hookPhase: item.hookPhase || null, syncPhase: item.syncPhase || null, message: item.message || null, })) : []; const nonReadyResources = resources .filter((item) => item?.health?.status && item.health.status !== "Healthy") .slice(0, 8) .map((item) => ({ kind: item.kind || null, namespace: item.namespace || null, name: item.name || null, status: item.status || null, healthStatus: item.health?.status || null, healthMessage: item.health?.message || null, })); output = { apiVersion: input.apiVersion, kind: input.kind, metadata: metadata(input), status: { sync: input?.status?.sync || null, health: input?.status?.health || null, conditions: Array.isArray(input?.status?.conditions) ? input.status.conditions.slice(0, 8).map((item) => ({ type: item.type || null, message: item.message || null, lastTransitionTime: item.lastTransitionTime || null })) : [], nonReadyResources, operationState: input?.status?.operationState ? { phase: input.status.operationState.phase || null, message: input.status.operationState.message || null, startedAt: input.status.operationState.startedAt || null, finishedAt: input.status.operationState.finishedAt || null, durationSeconds: durationSeconds(input.status.operationState.startedAt, input.status.operationState.finishedAt), syncResultResources, } : null, }, }; } else if (/^workload\d+$/.test(key)) { const template = input?.spec?.template || {}; output = { apiVersion: input.apiVersion, kind: input.kind, metadata: metadata(input), spec: { replicas: input?.spec?.replicas ?? null, template: { metadata: { labels: cleanMap(template?.metadata?.labels), annotations: cleanMap(template?.metadata?.annotations) }, spec: { containers: Array.isArray(template?.spec?.containers) ? template.spec.containers.map(compactContainer) : [] }, }, }, status: { replicas: input?.status?.replicas ?? null, readyReplicas: input?.status?.readyReplicas ?? null, availableReplicas: input?.status?.availableReplicas ?? null, updatedReplicas: input?.status?.updatedReplicas ?? null, conditions: Array.isArray(input?.status?.conditions) ? input.status.conditions.map((item) => ({ type: item.type || null, status: item.status || null, reason: item.reason || null })) : [], }, }; } console.log(JSON.stringify(output)); function problemSyncResource(item) { const message = String(item?.message || ""); return (item?.status && item.status !== "Synced") || (item?.hookPhase && item.hookPhase !== "Succeeded") || /fail|error|backoff|forbidden|invalid|denied|exceeded/iu.test(message); }