feat(nx): support passing args to run-commands builder

This commit is contained in:
Victor Savkin 2019-05-07 10:51:59 -04:00
parent 857ee73142
commit 7d5fdcd1d3
5 changed files with 90 additions and 9 deletions

View File

@ -4,15 +4,11 @@ Run commands
## Properties ## Properties
### commands ### args
Type: `array` of `object`
#### command
Type: `string` 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 ### parallel

View File

@ -23,7 +23,6 @@ describe('ng-add', () => {
.toPromise(); .toPromise();
const packageJson = readJsonInTree(result, 'package.json'); const packageJson = readJsonInTree(result, 'package.json');
console.log(packageJson);
expect(packageJson.dependencies['@nrwl/nest']).toBeUndefined(); expect(packageJson.dependencies['@nrwl/nest']).toBeUndefined();
expect(packageJson.devDependencies['@nrwl/nest']).toBeDefined(); expect(packageJson.devDependencies['@nrwl/nest']).toBeDefined();
expect(packageJson.dependencies['@nestjs/core']).toBeDefined(); expect(packageJson.dependencies['@nestjs/core']).toBeDefined();

View File

@ -194,4 +194,52 @@ describe('Command Runner Builder', () => {
expect(result).toEqual({ success: false }); expect(result).toEqual({ success: false });
expect(readFile(f)).toEqual('1'); 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');
});
}); });

View File

@ -15,6 +15,8 @@ export interface RunCommandsBuilderOptions {
commands: { command: string }[]; commands: { command: string }[];
parallel?: boolean; parallel?: boolean;
readyWhen?: string; readyWhen?: string;
args?: string;
parsedArgs?: { [k: string]: string };
} }
export default class RunCommandsBuilder export default class RunCommandsBuilder
@ -22,6 +24,10 @@ export default class RunCommandsBuilder
run( run(
config: BuilderConfiguration<RunCommandsBuilderOptions> config: BuilderConfiguration<RunCommandsBuilderOptions>
): Observable<BuildEvent> { ): Observable<BuildEvent> {
config.options.parsedArgs = {
...(config.options as any),
...this.parseArgs(config.options.args)
};
return Observable.create(async observer => { return Observable.create(async observer => {
if (!config || !config.options || !config.options.commands) { if (!config || !config.options || !config.options.commands) {
observer.error( observer.error(
@ -62,7 +68,10 @@ export default class RunCommandsBuilder
config: BuilderConfiguration<RunCommandsBuilderOptions> config: BuilderConfiguration<RunCommandsBuilderOptions>
) { ) {
const procs = config.options.commands.map(c => 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, result,
command: c.command command: c.command
})) }))
@ -106,7 +115,7 @@ export default class RunCommandsBuilder
>(async (m, c) => { >(async (m, c) => {
if ((await m) === null) { if ((await m) === null) {
const success = await this.createProcess( const success = await this.createProcess(
c.command, this.transformCommand(c.command, config.options.parsedArgs),
config.options.readyWhen config.options.readyWhen
); );
return !success ? c.command : null; 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;
}, {});
}
} }

View File

@ -25,6 +25,10 @@
"readyWhen": { "readyWhen": {
"type": "string", "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." "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"] "required": ["commands"]