diff --git a/docs/api-builders/run-commands.md b/docs/api-builders/run-commands.md index d3da6442ddb81..763e415bd8148 100644 --- a/docs/api-builders/run-commands.md +++ b/docs/api-builders/run-commands.md @@ -4,15 +4,11 @@ Run commands ## Properties -### commands - -Type: `array` of `object` - -#### command +### args Type: `string` -Command to run in child process +Extra arguments. You can pass them as follows: ng run project:target --args='--wait=100'. You can them use {args.wait} syntax to interpolate them in angular.json ### parallel diff --git a/packages/nest/src/schematics/ng-add/ng-add.spec.ts b/packages/nest/src/schematics/ng-add/ng-add.spec.ts index c144473f2ac03..84a0fb6569817 100644 --- a/packages/nest/src/schematics/ng-add/ng-add.spec.ts +++ b/packages/nest/src/schematics/ng-add/ng-add.spec.ts @@ -23,7 +23,6 @@ describe('ng-add', () => { .toPromise(); const packageJson = readJsonInTree(result, 'package.json'); - console.log(packageJson); expect(packageJson.dependencies['@nrwl/nest']).toBeUndefined(); expect(packageJson.devDependencies['@nrwl/nest']).toBeDefined(); expect(packageJson.dependencies['@nestjs/core']).toBeDefined(); diff --git a/packages/workspace/src/builders/run-commands/run-commands.builder.spec.ts b/packages/workspace/src/builders/run-commands/run-commands.builder.spec.ts index d9333d16fcbee..169724a05c391 100644 --- a/packages/workspace/src/builders/run-commands/run-commands.builder.spec.ts +++ b/packages/workspace/src/builders/run-commands/run-commands.builder.spec.ts @@ -194,4 +194,52 @@ describe('Command Runner Builder', () => { expect(result).toEqual({ success: false }); expect(readFile(f)).toEqual('1'); }); + + it('should throw when invalid args', async () => { + const root = normalize('/root'); + const f = fileSync().name; + + try { + await builder + .run({ + root, + builder: '@nrwl/run-commands', + projectType: 'application', + options: { + commands: [ + { + command: `echo {args.key} >> ${f}` + } + ], + args: 'key=value' + } + }) + .toPromise(); + } catch (e) { + expect(e.message).toEqual('Invalid args: key=value'); + } + }); + + it('should enable parameter substitution', async () => { + const root = normalize('/root'); + const f = fileSync().name; + const result = await builder + .run({ + root, + builder: '@nrwl/run-commands', + projectType: 'application', + options: { + commands: [ + { + command: `echo {args.key} >> ${f}` + } + ], + args: '--key=value' + } + }) + .toPromise(); + + expect(result).toEqual({ success: true }); + expect(readFile(f)).toEqual('value'); + }); }); diff --git a/packages/workspace/src/builders/run-commands/run-commands.builder.ts b/packages/workspace/src/builders/run-commands/run-commands.builder.ts index af203fe72385e..77efae5e9e980 100644 --- a/packages/workspace/src/builders/run-commands/run-commands.builder.ts +++ b/packages/workspace/src/builders/run-commands/run-commands.builder.ts @@ -15,6 +15,8 @@ export interface RunCommandsBuilderOptions { commands: { command: string }[]; parallel?: boolean; readyWhen?: string; + args?: string; + parsedArgs?: { [k: string]: string }; } export default class RunCommandsBuilder @@ -22,6 +24,10 @@ export default class RunCommandsBuilder run( config: BuilderConfiguration ): Observable { + config.options.parsedArgs = { + ...(config.options as any), + ...this.parseArgs(config.options.args) + }; return Observable.create(async observer => { if (!config || !config.options || !config.options.commands) { observer.error( @@ -62,7 +68,10 @@ export default class RunCommandsBuilder config: BuilderConfiguration ) { const procs = config.options.commands.map(c => - this.createProcess(c.command, config.options.readyWhen).then(result => ({ + this.createProcess( + this.transformCommand(c.command, config.options.parsedArgs), + config.options.readyWhen + ).then(result => ({ result, command: c.command })) @@ -106,7 +115,7 @@ export default class RunCommandsBuilder >(async (m, c) => { if ((await m) === null) { const success = await this.createProcess( - c.command, + this.transformCommand(c.command, config.options.parsedArgs), config.options.readyWhen ); return !success ? c.command : null; @@ -151,4 +160,29 @@ export default class RunCommandsBuilder }); }); } + + private transformCommand(command: string, args: any) { + const regex = /{args\.([^}]+)}/g; + return command.replace(regex, (_, group: string) => args[group]); + } + + private parseArgs(args: string) { + if (!args) { + return {}; + } + return args + .split(' ') + .map(t => t.trim()) + .reduce((m, c) => { + if (!c.startsWith('--')) { + throw new Error(`Invalid args: ${args}`); + } + const [key, value] = c.substring(2).split('='); + if (!key || !value) { + throw new Error(`Invalid args: ${args}`); + } + m[key] = value; + return m; + }, {}); + } } diff --git a/packages/workspace/src/builders/run-commands/schema.json b/packages/workspace/src/builders/run-commands/schema.json index cc216e3ebd2a6..db7759bb34f7d 100644 --- a/packages/workspace/src/builders/run-commands/schema.json +++ b/packages/workspace/src/builders/run-commands/schema.json @@ -25,6 +25,10 @@ "readyWhen": { "type": "string", "description": "String to appear in stdout or stderr that indicates that the task is done. This option can only be used when parallel is set to true. If not specified, the task is done when all the child processes complete." + }, + "args": { + "type": "string", + "description": "Extra arguments. You can pass them as follows: ng run project:target --args='--wait=100'. You can them use {args.wait} syntax to interpolate them in angular.json" } }, "required": ["commands"]