diff --git a/packages/angular/cli/commands/update-impl.ts b/packages/angular/cli/commands/update-impl.ts index 6d972746a9ee..7002d4f8c8a4 100644 --- a/packages/angular/cli/commands/update-impl.ts +++ b/packages/angular/cli/commands/update-impl.ts @@ -629,11 +629,40 @@ export class UpdateCommand extends Command { return 1; } - if (manifest.version === node.package.version) { + if (manifest.version === node.package?.version) { this.logger.info(`Package '${packageName}' is already up to date.`); continue; } + if (node.package && /^@(?:angular|nguniversal)\//.test(node.package.name)) { + const { name, version } = node.package; + const toBeInstalledMajorVersion = +manifest.version.split('.')[0]; + const currentMajorVersion = +version.split('.')[0]; + + if (toBeInstalledMajorVersion - currentMajorVersion > 1) { + // Only allow updating a single version at a time. + if (currentMajorVersion < 6) { + // Before version 6, the major versions were not always sequential. + // Example @angular/core skipped version 3, @angular/cli skipped versions 2-5. + this.logger.error( + `Updating multiple major versions of '${name}' at once is not supported. Please migrate each major version individually.\n` + + `For more information about the update process, see https://update.angular.io/.`, + ); + } else { + const nextMajorVersionFromCurrent = currentMajorVersion + 1; + + this.logger.error( + `Updating multiple major versions of '${name}' at once is not supported. Please migrate each major version individually.\n` + + `Run 'ng update ${name}@${nextMajorVersionFromCurrent}' in your workspace directory ` + + `to update to latest '${nextMajorVersionFromCurrent}.x' version of '${name}'.\n\n` + + `For more information about the update process, see https://update.angular.io/?v=${currentMajorVersion}.0-${nextMajorVersionFromCurrent}.0`, + ); + } + + return 1; + } + } + packagesToUpdate.push(requestIdentifier.toString()); } diff --git a/tests/legacy-cli/e2e/tests/update/update-multiple-versions.ts b/tests/legacy-cli/e2e/tests/update/update-multiple-versions.ts new file mode 100644 index 000000000000..1a5bbb2c4d4f --- /dev/null +++ b/tests/legacy-cli/e2e/tests/update/update-multiple-versions.ts @@ -0,0 +1,20 @@ +import { createProjectFromAsset } from '../../utils/assets'; +import { ng } from '../../utils/process'; +import { expectToFail } from '../../utils/utils'; + +export default async function () { + await createProjectFromAsset('7.0-project'); + + const extraArgs = ['--force']; + const { message } = await expectToFail(() => + ng('update', '@angular/core', ...extraArgs), + ); + if ( + !message.includes(`Updating multiple major versions of '@angular/core' at once is not supported`) + ) { + console.error(message); + throw new Error( + `Expected error message to include "Updating multiple major versions of '@angular/core' at once is not supported" but didn't.`, + ); + } +}