index.js (1940B)
1 // src/lib/pipeline/index.js - pipeline compilation 2 // 3 // compilePipeline turns the text of a .conductor.yml into the concrete task 4 // graph the scheduler stores. Every failure mode raises PipelineError with 5 // the full list of problems, so a bad pipeline is reported once rather than 6 // one mistake per push. 7 8 import { parsePipeline } from './parse.js'; 9 import { expandPipeline } from './expand.js'; 10 import { topologicalOrder, depths, CycleError } from './dag.js'; 11 import { selectForRef } from './only.js'; 12 import { PipelineError } from './schema.js'; 13 14 export { parsePipeline } from './parse.js'; 15 export { expandPipeline, interpolate } from './expand.js'; 16 export { topologicalOrder, depths, transitiveDependents, runnable, CycleError } from './dag.js'; 17 export { refMatches, taskRunsOnRef, selectForRef } from './only.js'; 18 export { PipelineError } from './schema.js'; 19 export { SUPPORTED_VERSION, VISIBILITIES, DEFAULT_WORKDIR, parseWorkdir } from './parse.js'; 20 21 export function compilePipeline(text, options = {}) { 22 const pipeline = parsePipeline(text, options); 23 const expanded = expandPipeline(pipeline, options); 24 25 // Tasks restricted to other refs drop out before the graph is checked, so 26 // ordering and depth describe the run that will actually happen. Without 27 // a ref nothing is filtered, which keeps validation of a pipeline 28 // separate from deciding what one push will run. 29 const tasks = options.ref === undefined ? expanded : selectForRef(expanded, options.ref); 30 31 try { 32 topologicalOrder(tasks); 33 } catch (e) { 34 if (e instanceof CycleError) { 35 throw new PipelineError([{ path: 'tasks', message: e.message }], pipeline.source); 36 } 37 throw e; 38 } 39 40 const depth = depths(tasks); 41 for (const task of tasks) task.depth = depth.get(task.name); 42 43 return { 44 version: pipeline.version, 45 source: pipeline.source, 46 visibility: pipeline.visibility, 47 workdir: pipeline.workdir, 48 tasks, 49 }; 50 }