Pipeline Engine
Define multi-step CI/CD pipelines with dependency DAG, matrix builds, conditional execution, and retry.
Basic Pipeline​
import { Pipeline } from '@xec-sh/ops';
const result = await Pipeline.create('ci')
.env({ NODE_ENV: 'test' })
.step('install', { run: 'pnpm install' })
.step('lint', { run: 'pnpm lint', dependsOn: ['install'] })
.step('test', { run: 'pnpm test', dependsOn: ['install'] })
.step('build', { run: 'pnpm build', dependsOn: ['lint', 'test'] })
.run();
console.log(result.summary); // { total: 4, passed: 4, failed: 0, skipped: 0 }
Features​
Dependencies​
Steps run only when their dependencies complete:
Pipeline.create('build')
.step('a', { run: 'echo a' })
.step('b', { run: 'echo b', dependsOn: ['a'] })
.step('c', { run: 'echo c', dependsOn: ['a'] }) // b and c can run in parallel
.step('d', { run: 'echo d', dependsOn: ['b', 'c'] }) // waits for both
Matrix Builds​
Run the same step across multiple configurations:
.step('test', {
run: 'pnpm test',
matrix: {
node: ['18', '20', '22'],
os: ['linux', 'macos'],
},
})
// Creates 6 test runs: node18+linux, node18+macos, node20+linux, ...
Conditional Execution​
Skip steps based on runtime conditions:
.step('deploy', {
run: 'pnpm deploy',
condition: (ctx) => ctx.branch === 'main',
})
Retry​
Retry flaky steps:
.step('e2e', {
run: 'pnpm test:e2e',
retry: { maxAttempts: 3, delay: 5000 },
})
Continue on Error​
Mark steps as non-blocking:
.step('lint', {
run: 'pnpm lint',
continueOnError: true, // Pipeline continues even if lint fails
})
Function Steps​
Use TypeScript functions instead of shell commands:
.step('validate', {
run: async (ctx) => {
const config = JSON.parse(await fs.readFile('config.json', 'utf-8'));
if (!config.version) throw new Error('Missing version');
},
})
Context​
Pipeline context is available in conditions and function steps:
const result = await Pipeline.create('release')
.env({ CI: 'true' })
.step('deploy', {
run: async (ctx) => {
console.log(ctx.env.CI); // 'true'
console.log(ctx.branch); // from run() options
console.log(ctx.outputs); // step outputs
},
condition: (ctx) => ctx.branch === 'main',
})
.run({ branch: 'main', commit: 'abc123' });