diff --git a/packages/angular/cli/models/schematic-command.ts b/packages/angular/cli/models/schematic-command.ts index 15adbe941e31..11d272e7496a 100644 --- a/packages/angular/cli/models/schematic-command.ts +++ b/packages/angular/cli/models/schematic-command.ts @@ -128,8 +128,21 @@ export abstract class SchematicCommand extends Command { workflow.registry.addSmartDefaultProvider('projectName', (_schema: JsonObject) => { if (this._workspace) { + try { return this._workspace.getProjectByPath(normalize(process.cwd())) || this._workspace.getDefaultProjectName(); + } catch (e) { + if (e instanceof experimental.workspace.AmbiguousProjectPathException) { + this.logger.warn(tags.oneLine` + Two or more projects are using identical roots. + Unable to determine project using current working directory. + Using default workspace project instead. + `); + + return this._workspace.getDefaultProjectName(); + } + throw e; + } } return undefined; @@ -346,7 +359,7 @@ export abstract class SchematicCommand extends Command { private _cleanDefaults(defaults: T, undefinedOptions: string[]): T { (Object.keys(defaults) as K[]) - .filter(key => !undefinedOptions.map(strings.camelize).includes(key)) + .filter(key => !undefinedOptions.map(strings.camelize).includes(key as string)) .forEach(key => { delete defaults[key]; }); diff --git a/packages/angular/cli/utilities/config.ts b/packages/angular/cli/utilities/config.ts index 9e89aab50015..e17620818e11 100644 --- a/packages/angular/cli/utilities/config.ts +++ b/packages/angular/cli/utilities/config.ts @@ -140,11 +140,22 @@ export function validateWorkspace(json: JsonObject) { return true; } +function getProjectByCwd(workspace: experimental.workspace.Workspace): string | null { + try { + return workspace.getProjectByPath(normalize(process.cwd())); + } catch (e) { + if (e instanceof experimental.workspace.AmbiguousProjectPathException) { + return workspace.getDefaultProjectName(); + } + throw e; + } +} + export function getPackageManager(): string { let workspace = getWorkspace('local'); if (workspace) { - const project = workspace.getProjectByPath(normalize(process.cwd())); + const project = getProjectByCwd(workspace); if (project && workspace.getProjectCli(project)) { const value = workspace.getProjectCli(project)['packageManager']; if (typeof value == 'string') { @@ -258,7 +269,7 @@ export function getDefaultSchematicCollection(): string { let workspace = getWorkspace('local'); if (workspace) { - const project = workspace.getProjectByPath(normalize(process.cwd())); + const project = getProjectByCwd(workspace); if (project && workspace.getProjectCli(project)) { const value = workspace.getProjectCli(project)['defaultCollection']; if (typeof value == 'string') { @@ -319,7 +330,7 @@ export function getSchematicDefaults( } } - project = project || workspace.getProjectByPath(normalize(process.cwd())); + project = project || getProjectByCwd(workspace); if (project && workspace.getProjectSchematics(project)) { const schematicObject = workspace.getProjectSchematics(project)[fullName]; if (schematicObject) { @@ -339,7 +350,7 @@ export function isWarningEnabled(warning: string): boolean { let workspace = getWorkspace('local'); if (workspace) { - const project = workspace.getProjectByPath(normalize(process.cwd())); + const project = getProjectByCwd(workspace); if (project && workspace.getProjectCli(project)) { const warnings = workspace.getProjectCli(project)['warnings']; if (typeof warnings == 'object' && !Array.isArray(warnings)) { diff --git a/packages/angular_devkit/core/src/workspace/workspace.ts b/packages/angular_devkit/core/src/workspace/workspace.ts index 09c4f5bc4689..d8964e6fa5f0 100644 --- a/packages/angular_devkit/core/src/workspace/workspace.ts +++ b/packages/angular_devkit/core/src/workspace/workspace.ts @@ -49,6 +49,11 @@ export class WorkspaceNotYetLoadedException extends BaseException { constructor() { super(`Workspace needs to be loaded before it is used.`); } } +export class AmbiguousProjectPathException extends BaseException { + constructor(public readonly path: Path, public readonly projects: ReadonlyArray) { + super(`Current active project is ambiguous (${projects.join(',')}) using path: '${path}'`); + } +} export class Workspace { private readonly _workspaceSchemaPath = join(normalize(__dirname), 'workspace-schema.json'); @@ -175,11 +180,25 @@ export class Workspace { // the sort is stable and the first declared project will win). .sort((a, b) => b[0].length - a[0].length); - if (projects[0]) { - return projects[0][1]; + if (projects.length === 0) { + return null; + } else if (projects.length > 1) { + const found = new Set(); + const sameRoots = projects.filter(v => { + if (!found.has(v[0])) { + found.add(v[0]); + + return false; + } + + return true; + }); + if (sameRoots.length > 0) { + throw new AmbiguousProjectPathException(path, sameRoots.map(v => v[1])); + } } - return null; + return projects[0][1]; } getCli() {