Skip to content

Commit

Permalink
fix(@angular/cli): avoid exceptions for expected errors in architect …
Browse files Browse the repository at this point in the history
…commands

Errors caused by invalid options or workspace configuration will now be presented as fatal console messages and the CLI will exit gracefully with an exit code of 1.
  • Loading branch information
clydin authored and filipesilva committed Mar 10, 2021
1 parent af1cc2d commit 0633551
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 20 deletions.
6 changes: 1 addition & 5 deletions packages/angular/cli/commands/deploy-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,7 @@ export class DeployCommand extends ArchitectCommand<DeployCommandSchema> {
public readonly target = 'deploy';
public readonly missingTargetError = BuilderMissing;

public async run(options: ArchitectCommandOptions & Arguments) {
return this.runArchitectTarget(options);
}

public async initialize(options: DeployCommandSchema & Arguments): Promise<void> {
public async initialize(options: DeployCommandSchema & Arguments): Promise<number | void> {
if (!options.help) {
return super.initialize(options);
}
Expand Down
32 changes: 22 additions & 10 deletions packages/angular/cli/models/architect-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,15 @@ export abstract class ArchitectCommand<
target: string | undefined;
missingTargetError: string | undefined;

public async initialize(options: T & Arguments): Promise<void> {
await super.initialize(options);

public async initialize(options: T & Arguments): Promise<number | void> {
this._registry = new json.schema.CoreSchemaRegistry();
this._registry.addPostTransform(json.schema.transforms.addUndefinedDefaults);
this._registry.useXDeprecatedProvider(msg => this.logger.warn(msg));

if (!this.workspace) {
throw new Error('A workspace is required for an architect command.');
this.logger.fatal('A workspace is required for this command.');

return 1;
}

this._architectHost = new WorkspaceNodeModulesArchitectHost(this.workspace, this.workspace.basePath);
Expand All @@ -57,15 +57,19 @@ export abstract class ArchitectCommand<

const specifier = this._makeTargetSpecifier(options);
if (!specifier.project || !specifier.target) {
throw new Error('Cannot determine project or target for command.');
this.logger.fatal('Cannot determine project or target for command.');

return 1;
}

return;
}

let projectName = options.project;
if (projectName && !this.workspace.projects.has(projectName)) {
throw new Error(`Project '${projectName}' does not exist.`);
this.logger.fatal(`Project '${projectName}' does not exist.`);

return 1;
}

const commandLeftovers = options['--'];
Expand All @@ -77,12 +81,16 @@ export abstract class ArchitectCommand<
}

if (targetProjectNames.length === 0) {
throw new Error(this.missingTargetError || `No projects support the '${this.target}' target.`);
this.logger.fatal(this.missingTargetError || `No projects support the '${this.target}' target.`);

return 1;
}

if (projectName && !targetProjectNames.includes(projectName)) {
throw new Error(this.missingTargetError ||
this.logger.fatal(this.missingTargetError ||
`Project '${projectName}' does not support the '${this.target}' target.`);

return 1;
}

if (!projectName && commandLeftovers && commandLeftovers.length > 0) {
Expand Down Expand Up @@ -141,11 +149,13 @@ export abstract class ArchitectCommand<
}

if (!projectName && this.multiTarget && builderNames.size > 1) {
throw new Error(tags.oneLine`
this.logger.fatal(tags.oneLine`
Architect commands with command line overrides cannot target different builders. The
'${this.target}' target would run on projects ${targetProjectNames.join()} which have the
following builders: ${'\n ' + [...builderNames].join('\n ')}
`);

return 1;
}
}

Expand All @@ -159,7 +169,9 @@ export abstract class ArchitectCommand<
// This is a special case where we just return.
return;
} else {
throw new Error(this.missingTargetError || 'Cannot determine project or target for command.');
this.logger.fatal(this.missingTargetError || 'Cannot determine project or target for command.');

return 1;
}
}

Expand Down
11 changes: 6 additions & 5 deletions packages/angular/cli/models/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ export abstract class Command<T extends BaseCommandOptions = BaseCommandOptions>
this.analytics = context.analytics || new analytics.NoopAnalytics();
}

async initialize(options: T & Arguments): Promise<void> {
return;
}
async initialize(options: T & Arguments): Promise<number | void> {}

async printHelp(): Promise<number> {
await this.printHelpUsage();
Expand Down Expand Up @@ -169,7 +167,10 @@ export abstract class Command<T extends BaseCommandOptions = BaseCommandOptions>
if (!(options.help === true || options.help === 'json' || options.help === 'JSON')) {
await this.validateScope();
}
await this.initialize(options);
let result = await this.initialize(options);
if (typeof result === 'number' && result !== 0) {
return result;
}

if (options.help === true) {
return this.printHelp();
Expand All @@ -180,7 +181,7 @@ export abstract class Command<T extends BaseCommandOptions = BaseCommandOptions>
if (this.useReportAnalytics) {
await this.reportAnalytics([this.description.name], options);
}
const result = await this.run(options);
result = await this.run(options);
const endTime = +new Date();

this.analytics.timing(this.description.name, 'duration', endTime - startTime);
Expand Down

0 comments on commit 0633551

Please sign in to comment.