Orchestrated Workflow
A parent command that executes child commands in sequence, passing data between steps. Useful for release pipelines, build systems, or deployments.
1 FILESTry in Playground
All Example Files
FILE EXPLORER
orchestrated-workflow.ts
1import { cli, makeComposableBuilder, chain } from 'cli-forge';
2
3// Shared options
4const withProjectOption = makeComposableBuilder((args) =>
5 args.option('project', {
6 type: 'string',
7 description: 'Project name to operate on',
8 required: true,
9 })
10);
11
12const withDryRunOption = makeComposableBuilder((args) =>
13 args.option('dryRun', {
14 type: 'boolean',
15 description: 'Print what would happen without making changes',
16 default: false,
17 })
18);
19
20// Result types for each step
21interface ValidationResult {
22 project: string;
23 isClean: boolean;
24 version: string;
25}
26
27interface BuildResult {
28 project: string;
29 outputPath: string;
30 artifacts: string[];
31}
32
33interface PublishResult {
34 project: string;
35 publishedVersion: string;
36 registry: string;
37}
38
39const withValidateCommand = makeComposableBuilder((args) =>
40 args.command('validate', {
41 description: 'Check that the project is ready for release',
42 builder: (cmd) => chain(cmd, withProjectOption),
43 handler: (args): ValidationResult => {
44 console.log(`Validating ${args.project}...`);
45
46 const result: ValidationResult = {
47 project: args.project,
48 isClean: true,
49 version: '1.2.3',
50 };
51
52 console.log(`Validation passed: ${args.project} v${result.version}`);
53 return result;
54 },
55 })
56);
57
58const withBuildCommand = makeComposableBuilder((args) =>
59 args.command('build', {
60 description: 'Build the project for distribution',
61 builder: (cmd) => chain(cmd, withProjectOption),
62 handler: (args): BuildResult => {
63 console.log(`Building ${args.project}...`);
64
65 const result: BuildResult = {
66 project: args.project,
67 outputPath: `dist/${args.project}`,
68 artifacts: [`${args.project}.js`, `${args.project}.d.ts`],
69 };
70
71 console.log(`Build output: ${result.outputPath}`);
72 console.log(`Artifacts: ${result.artifacts.join(', ')}`);
73 return result;
74 },
75 })
76);
77
78const withPublishCommand = makeComposableBuilder((args) =>
79 args.command('publish', {
80 description: 'Publish the built package to npm',
81 builder: (cmd) =>
82 chain(cmd, withProjectOption, withDryRunOption).option('registry', {
83 type: 'string',
84 description: 'Registry URL',
85 default: 'https://registry.npmjs.org',
86 }),
87 handler: (args): PublishResult => {
88 const action = args.dryRun ? '[dry-run] Would publish' : 'Publishing';
89 console.log(`${action} ${args.project} to ${args.registry}...`);
90
91 const result: PublishResult = {
92 project: args.project,
93 publishedVersion: '1.2.3',
94 registry: args.registry,
95 };
96
97 if (!args.dryRun) {
98 console.log(`Published ${result.project}@${result.publishedVersion}`);
99 }
100 return result;
101 },
102 })
103);
104
105cli('release', {
106 description: 'Validate, build, and publish a project',
107 builder: (args) =>
108 chain(
109 args,
110 withProjectOption,
111 withDryRunOption,
112 withValidateCommand,
113 withBuildCommand,
114 withPublishCommand
115 ),
116
117 handler: async (args, ctx) => {
118 const { project, dryRun } = args;
119 const children = ctx.command.getChildren();
120
121 const validateHandler = children.validate.getHandler();
122 const buildHandler = children.build.getHandler();
123 const publishHandler = children.publish.getHandler();
124
125 if (!validateHandler || !buildHandler || !publishHandler) {
126 throw new Error('Missing required command handlers');
127 }
128
129 console.log(`Starting release workflow for ${project}`);
130 console.log(dryRun ? '(dry run mode)\n' : '\n');
131
132 const validation = await validateHandler({ project });
133 if (!validation.isClean) {
134 console.error('Validation failed - aborting release');
135 process.exitCode = 1;
136 return;
137 }
138 console.log('');
139
140 const build = await buildHandler({ project: validation.project });
141 console.log('');
142
143 const publish = await publishHandler({
144 project: build.project,
145 dryRun,
146 registry: 'https://registry.npmjs.org',
147 });
148 console.log('');
149
150 console.log('='.repeat(40));
151 console.log('Release complete!');
152 console.log(` Project: ${publish.project}`);
153 console.log(` Version: ${publish.publishedVersion}`);
154 console.log(` Artifacts: ${build.artifacts.length} files`);
155 console.log(` Registry: ${publish.registry}`);
156 },
157}).forge();
158