diff --git a/packages/angular/cli/commands/add-impl.ts b/packages/angular/cli/commands/add-impl.ts index 8932f04dc6dc..4e9e87c2ea58 100644 --- a/packages/angular/cli/commands/add-impl.ts +++ b/packages/angular/cli/commands/add-impl.ts @@ -18,6 +18,7 @@ import { colors } from '../utilities/color'; import { getPackageManager } from '../utilities/package-manager'; import { NgAddSaveDepedency, + PackageIdentifier, PackageManifest, fetchPackageManifest, fetchPackageMetadata, @@ -50,10 +51,26 @@ export class AddCommand extends SchematicCommand { } if (packageIdentifier.registry && this.isPackageInstalled(packageIdentifier.name)) { - // Already installed so just run schematic - this.logger.info('Skipping installation: Package already installed'); + let validVersion = false; + const installedVersion = await this.findProjectVersion(packageIdentifier.name); + if (installedVersion) { + if (packageIdentifier.type === 'range') { + validVersion = satisfies(installedVersion, packageIdentifier.fetchSpec); + } else if (packageIdentifier.type === 'version') { + const v1 = valid(packageIdentifier.fetchSpec); + const v2 = valid(installedVersion); + validVersion = v1 !== null && v1 === v2; + } else if (!packageIdentifier.rawSpec) { + validVersion = true; + } + } - return this.executeSchematic(packageIdentifier.name, options['--']); + if (validVersion) { + // Already installed so just run schematic + this.logger.info('Skipping installation: Package already installed'); + + return this.executeSchematic(packageIdentifier.name, options['--']); + } } const packageManager = await getPackageManager(this.workspace.root); diff --git a/tests/legacy-cli/e2e/tests/commands/add/add-material.ts b/tests/legacy-cli/e2e/tests/commands/add/add-material.ts index 44b075a20a0a..ad0c81629ef3 100644 --- a/tests/legacy-cli/e2e/tests/commands/add/add-material.ts +++ b/tests/legacy-cli/e2e/tests/commands/add/add-material.ts @@ -8,4 +8,24 @@ export default async function () { await ng('add', '@angular/material'); await expectFileToMatch('package.json', /@angular\/material/); + + const output1 = await ng('add', '@angular/material'); + if (!output1.stdout.includes('Skipping installation: Package already installed')) { + throw new Error('Installation was not skipped'); + } + + const output2 = await ng('add', '@angular/material@latest'); + if (output2.stdout.includes('Skipping installation: Package already installed')) { + throw new Error('Installation should not have been skipped'); + } + + const output3 = await ng('add', '@angular/material@8.0.0'); + if (output3.stdout.includes('Skipping installation: Package already installed')) { + throw new Error('Installation should not have been skipped'); + } + + const output4 = await ng('add', '@angular/material@8'); + if (!output4.stdout.includes('Skipping installation: Package already installed')) { + throw new Error('Installation was not skipped'); + } }