UNPKG

@kui-shell/plugin-tekton

Version:
358 lines 14.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); const debug_1 = require("debug"); const core_1 = require("@kui-shell/core"); const success_1 = require("./success"); const resource_1 = require("../model/resource"); const debug = debug_1.default('plugins/tekton/lib/tekton2graph'); const defaultHeight = 13; const defaultCharWidth = 3.25; const makeSubGraph = (label = 'root', { visited, children, tooltip, tooltipColor, type, onclick } = { children: [] }) => { return { id: label, label, onclick, children, visited, edges: [], nParents: 0, nChildren: 0, type, tooltip, tooltipColor }; }; const stepId = (taskRef, step) => `__step__${taskRef.name}__${step.name}`; const getPipeline = (jsons) => { const declaredPipeline = jsons.find(_ => _.kind === 'Pipeline'); if (resource_1.isPipeline(declaredPipeline)) { return declaredPipeline; } else { const tasks = jsons.filter(_ => _.kind === 'Task'); if (tasks.length === 0) { throw new Error('No pipeline defined, and no Tasks defined'); } else { const pipeline = { apiVersion: 'tekton.dev/v1alpha1', kind: 'Pipeline', metadata: { name: 'pipeline' }, originatingCommand: undefined, spec: { tasks: tasks.map(task => ({ name: task.metadata.name, taskRef: { name: task.metadata.name } })) } }; return pipeline; } } }; function addEdge(graph, parent, child, { singletonSource, singletonTarget, hasRuns }) { debug('addEdge', parent.id, child.id); if (!parent.ports) { parent.ports = []; } if (!child.ports) { child.ports = []; } const targetPort = `${child.id}-` + (singletonTarget ? 'pTargetSingleton' : `p${child.ports.length}`); if (!child.ports.find(_ => _.id === targetPort)) { child.ports.push({ id: targetPort }); } const sourcePort = `${parent.id}-` + (singletonSource ? 'pSourceSingleton' : `p${parent.ports.length}`); if (!parent.ports.find(_ => _.id === sourcePort)) { parent.ports.push({ id: sourcePort }); } graph.edges.push({ id: `${parent.id}-${child.id}`, source: parent.id, sourcePort, target: child.id, targetPort, visited: !hasRuns ? undefined : !!(parent.visited && child.visited) }); child.nParents++; parent.nChildren++; } function default_1(jsons, filepath, run) { return __awaiter(this, void 0, void 0, function* () { debug('jsons', jsons); const pipeline = getPipeline(jsons); debug('pipeline', pipeline); const taskName2Task = jsons .filter(_ => _.kind === 'Task') .reduce((symtab, task) => { symtab[task.metadata.name] = task; return symtab; }, {}); const taskRefName2Task = pipeline.spec.tasks.reduce((symtab, taskRef) => { symtab[taskRef.name] = taskName2Task[taskRef.taskRef.name]; return symtab; }, {}); const taskRefName2TaskRef = pipeline.spec.tasks.reduce((symtab, taskRef) => { symtab[taskRef.name] = taskRef; return symtab; }, {}); const runs = run && run.status.taskRuns; const startVisit = (run && [ { start: new Date(run.status.startTime).getTime(), duration: 0, response: { success: true } } ]) || []; const endVisit = (run && run.status.completionTime && [ { start: new Date(run.status.completionTime).getTime(), duration: 0, response: { success: success_1.default(run.status.conditions) } } ]) || []; const runInfo = runs && Object.keys(runs).reduce((M, _) => { const taskRun = runs[_]; const taskRefName = taskRun.pipelineTaskName; const task = taskRefName2Task[taskRefName]; if (task) { const start = new Date(taskRun.status.startTime).getTime(); task.visitedIdx = M.length; M.push({ start, duration: taskRun.status.completionTime ? new Date(taskRun.status.completionTime).getTime() - start : 0, response: { success: success_1.default(taskRun.status.conditions) } }); taskRun.status.steps.forEach(stepRun => { const start = new Date(stepRun.terminated.startedAt).getTime(); const end = new Date(stepRun.terminated.finishedAt).getTime(); const success = stepRun.terminated.reason !== 'Error'; const step = task.spec.steps.find(_ => _.name === stepRun.name); if (step) { step.visitedIdx = M.length; M.push({ start, duration: end - start, response: { success } }); } }); } return M; }, startVisit.concat(endVisit)); const graph = { id: 'root', label: 'root', edges: [], children: [], nChildren: 0, nParents: 0, runs: runInfo, properties: { maxLabelLength: 24, fontSize: '4px' } }; const start = { id: 'Entry', label: 'start', type: 'Entry', width: 18, height: 18, nChildren: 0, nParents: 0, visited: run && [0], properties: { title: 'The flow starts here', fontSize: '4.5px' } }; const end = { id: 'Exit', label: 'end', type: 'Exit', width: 18, height: 18, nChildren: 0, nParents: 0, visited: run && [1], properties: { title: 'The flow ends here', fontSize: '4.5px' } }; const symbolTable = pipeline.spec.tasks.reduce((symtab, taskRef) => { const task = taskName2Task[taskRef.taskRef.name]; debug('TaskRef', taskRef.name, task); const filearg = filepath ? `-f ${core_1.encodeComponent(filepath)}` : ''; let node; if (task && task.spec.steps && task.spec.steps.length > 0) { const resources = (task.spec.inputs && task.spec.inputs.resources) || []; const resourceList = `${resources.map(_ => `<span class='color-base0A'>${_.type}</span>:${_.name}`).join(', ')}`; const params = (task.spec.inputs && task.spec.inputs.params) || []; const paramList = `(${params.map(_ => _.name).join(', ')})`; const subgraph = makeSubGraph(taskRef.name, { type: 'Tekton Task', tooltip: `<table><tr><td><strong>Resources</strong></td><td>${resourceList}</td></tr><tr><td><strong>Params</strong></td><td>${paramList}</td></tr></table>`, tooltipColor: '0C', onclick: `tekton get task ${core_1.encodeComponent(pipeline.metadata.name)} ${core_1.encodeComponent(task.metadata.name)} ${filearg}`, visited: task.visitedIdx !== undefined ? [task.visitedIdx] : undefined, children: task.spec.steps.map(step => { const stepNode = { id: stepId(taskRef, step), label: step.name, width: step.name.length * defaultCharWidth, height: defaultHeight, nChildren: 0, nParents: 0, deployed: false, visited: step.visitedIdx !== undefined ? [step.visitedIdx] : undefined, type: 'Tekton Step', tooltip: `<strong>Image</strong>: ${step.image}`, tooltipColor: '0E', onclick: `tekton get step ${core_1.encodeComponent(pipeline.metadata.name)} ${core_1.encodeComponent(task.metadata.name)} ${core_1.encodeComponent(step.name)} ${filearg}` }; symtab[stepNode.id] = stepNode; return stepNode; }) }); subgraph.children.slice(1).reduce((cur, next) => { addEdge(subgraph, cur, next, { hasRuns: runs !== undefined }); return next; }, subgraph.children[0]); node = subgraph; } else { node = { id: taskRef.name, label: taskRef.name, width: taskRef.name.length * defaultCharWidth, height: defaultHeight, nChildren: 0, nParents: 0, type: 'Tekton Task', tooltip: 'test' }; } symtab[taskRef.name] = node; graph.children.push(node); return symtab; }, {}); const lastStepOf = (node) => { const taskRef = taskRefName2TaskRef[node.id]; const task = taskRefName2Task[node.id]; return task && symbolTable[stepId(taskRef, task.spec.steps[task.spec.steps.length - 1])]; }; const firstStepOf = (node) => { const taskRef = taskRefName2TaskRef[node.id]; const task = taskRefName2Task[node.id]; return task && symbolTable[stepId(taskRef, task.spec.steps[0])]; }; const _addEdge = (parent, child, opts = { hasRuns: runs !== undefined }) => { const lastStepOfParentTask = lastStepOf(parent); const firstStepOfChildTask = firstStepOf(child); if (lastStepOfParentTask && firstStepOfChildTask) { addEdge(graph, lastStepOfParentTask, firstStepOfChildTask, { singletonSource: true, singletonTarget: true, hasRuns: runs !== undefined }); parent.nChildren++; child.nParents++; } else if (!lastStepOfParentTask && firstStepOfChildTask) { addEdge(graph, parent, firstStepOfChildTask, { singletonSource: opts.singletonSource || false, singletonTarget: true, hasRuns: runs !== undefined }); child.nParents++; } else if (lastStepOfParentTask && !firstStepOfChildTask) { addEdge(graph, lastStepOfParentTask, child, { singletonSource: true, singletonTarget: opts.singletonTarget || false, hasRuns: runs !== undefined }); parent.nChildren++; } else { addEdge(graph, parent, child, Object.assign({}, opts, { hasRuns: runs !== undefined })); } }; const wire = (parentTaskRefName, childTaskRef) => { const parent = symbolTable[parentTaskRefName]; const child = symbolTable[childTaskRef.name]; if (parent) { _addEdge(parent, child); } else { console.error('parent not found', childTaskRef); } }; pipeline.spec.tasks.forEach((task) => { if (task.runAfter) { task.runAfter.forEach(parentTaskName => { wire(parentTaskName, task); }); } if (task.resources) { const wirePorts = (ports) => { if (ports) { ports.forEach(port => { if (port.from) { port.from.forEach(parentTaskName => { wire(parentTaskName, task); }); } }); } }; wirePorts(task.resources.inputs); wirePorts(task.resources.outputs); } }); graph.children .filter(child => child.nParents === 0) .forEach(child => _addEdge(start, child, { singletonSource: true, hasRuns: graph.runs !== undefined })); graph.children .filter(parent => parent.nChildren === 0) .forEach(parent => _addEdge(parent, end, { singletonTarget: true, hasRuns: graph.runs !== undefined })); graph.children.push(start); graph.children.push(end); return graph; }); } exports.default = default_1; //# sourceMappingURL=tekton2graph.js.map