From 5ad145722f66af526a36983b259c6d625c93f307 Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Fri, 22 Oct 2021 11:56:28 +0200 Subject: [PATCH] fix(@angular/cli): error when updating Angular packages across multi-major migrations With this change we show an error message when users try to update `@angular/` and `@nguniversal/` packages across multiple major versions. (cherry picked from commit 57d7eb5b1623b2227486a33f577a2868e0dd239c) --- packages/angular/cli/commands/update-impl.ts | 52 ++++---- .../migrations/migration-collection.json | 120 ------------------ .../tests/update/update-multiple-versions.ts | 35 +++++ 3 files changed, 63 insertions(+), 144 deletions(-) create mode 100644 tests/legacy-cli/e2e/tests/update/update-multiple-versions.ts diff --git a/packages/angular/cli/commands/update-impl.ts b/packages/angular/cli/commands/update-impl.ts index 44fec1059d8d..c0c461452bd0 100644 --- a/packages/angular/cli/commands/update-impl.ts +++ b/packages/angular/cli/commands/update-impl.ts @@ -607,36 +607,40 @@ export class UpdateCommand extends Command { return 1; } - if (node.package?.name === '@angular/cli') { - // Migrations for non LTS versions of Angular CLI are no longer included in @schematics/angular v12. + 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 = +node.package.version.split('.')[0]; - if (currentMajorVersion < 10 && toBeInstalledMajorVersion >= 12) { - const updateVersions: Record = { - 1: 6, - 6: 7, - 7: 8, - 8: 9, - 9: 10, - }; - - const updateTo = updateVersions[currentMajorVersion]; - this.logger.error( - 'Updating multiple major versions at once is not recommended. ' + - `Run 'ng update @angular/cli@${updateTo}' in your workspace directory ` + - `to update to latest '${updateTo}.x' version of '@angular/cli'.\n\n` + - 'For more information about the update process, see https://update.angular.io/.', - ); + 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; } } - if (manifest.version === node.package?.version) { - this.logger.info(`Package '${packageName}' is already up to date.`); - continue; - } - packagesToUpdate.push(requestIdentifier.toString()); } diff --git a/packages/schematics/angular/migrations/migration-collection.json b/packages/schematics/angular/migrations/migration-collection.json index 1df6534c049d..7f7835399925 100644 --- a/packages/schematics/angular/migrations/migration-collection.json +++ b/packages/schematics/angular/migrations/migration-collection.json @@ -1,125 +1,5 @@ { "schematics": { - "lazy-loading-syntax": { - "version": "9.0.0-next.6", - "factory": "./update-12/update-lazy-module-paths", - "description": "Lazy loading syntax migration. Update lazy loading syntax to use dynamic imports." - }, - "tslint-version-6": { - "version": "10.0.0-beta.0", - "factory": "./update-10/update-tslint", - "description": "Update tslint to version 6 and adjust rules to maintain existing behavior." - }, - "rename-browserslist-config": { - "version": "10.0.0-beta.0", - "factory": "./update-10/rename-browserslist-config", - "description": "Update Browserslist configuration file name to '.browserslistrc' from deprecated 'browserslist'." - }, - "remove-es5-browser-support-option": { - "version": "10.0.0-beta.2", - "factory": "./update-10/remove-es5-browser-support", - "description": "Remove deprecated 'es5BrowserSupport' browser builder option. The inclusion for ES5 polyfills will be determined from the browsers listed in the browserslist configuration." - }, - "schematic-options-10": { - "version": "10.0.0-beta.2", - "factory": "./update-10/schematic-options", - "description": "Replace deprecated and removed 'styleext' and 'spec' Angular schematic options with 'style' and 'skipTests', respectively." - }, - "update-angular-config": { - "version": "10.0.0-beta.6", - "factory": "./update-10/update-angular-config", - "description": "Remove deprecated options from 'angular.json' that are no longer present in v10." - }, - "tslint-add-deprecation-rule": { - "version": "10.0.0-beta.7", - "factory": "./update-10/add-deprecation-rule-tslint", - "description": "Add the tslint deprecation rule to tslint JSON configuration files." - }, - "update-libraries-tslib": { - "version": "10.0.0-beta.7", - "factory": "./update-10/update-libraries-tslib", - "description": "Update library projects to use tslib version 2 as a direct dependency. Read more about this here: https://v10.angular.io/guide/migration-update-libraries-tslib" - }, - "update-workspace-dependencies": { - "version": "10.0.0-rc.2", - "factory": "./update-10/update-dependencies", - "description": "Update workspace dependencies to match a new v10 project." - }, - "update-module-and-target-compiler-options": { - "version": "10.0.1", - "factory": "./update-10/update-module-and-target-compiler-options", - "description": "Update 'module' and 'target' TypeScript compiler options. Read more about this here: https://v10.angular.io/guide/migration-update-module-and-target-compiler-options" - }, - "remove-solution-style-tsconfig": { - "version": "10.1.0-next.5", - "factory": "./update-10/remove-solution-style-tsconfig", - "description": "Removing \"Solution Style\" TypeScript configuration file support." - }, - "replace-ng-packagr-builder": { - "version": "11.0.0-next.0", - "factory": "./update-11/replace-ng-packagr-builder", - "description": "Replace deprecated library builder '@angular-devkit/build-ng-packagr'." - }, - "add-declaration-map-compiler-option": { - "version": "11.0.0-next.2", - "factory": "./update-11/add-declaration-map-compiler-option", - "description": "Add 'declarationMap' compiler options for non production library builds." - }, - "update-angular-config-v11": { - "version": "11.0.0-next.8", - "factory": "./update-11/update-angular-config", - "description": "Remove deprecated options from 'angular.json' that are no longer present in v11." - }, - "update-workspace-dependencies-v11": { - "version": "11.0.0", - "factory": "./update-11/update-dependencies", - "description": "Update workspace dependencies to match a new v11 project." - }, - "update-angular-config-v12": { - "version": "12.0.0-next.0", - "factory": "./update-12/update-angular-config", - "description": "Remove deprecated options from 'angular.json' that are no longer present in v12." - }, - "update-zonejs": { - "version": "12.0.0-next.1", - "factory": "./update-12/update-zonejs", - "description": "Update 'zone.js' to version 0.11.x. Read more about this here: https://github.com/angular/angular/blob/master/packages/zone.js/CHANGELOG.md#breaking-changes-since-zonejs-v0111" - }, - "remove-emit-decorator-metadata": { - "version": "12.0.0-next.2", - "factory": "./update-12/remove-emit-decorator-metadata", - "description": "Remove 'emitDecoratorMetadata' TypeScript compiler option. Decorator metadata is no longer needed by Angular. Read more about this here: https://www.typescriptlang.org/docs/handbook/decorators.html#metadata" - }, - "lazy-loading-string-syntax": { - "version": "12.0.0-next.4", - "factory": "./update-12/update-lazy-module-paths", - "description": "Lazy loading syntax migration. Update lazy loading string syntax to use dynamic imports." - }, - "remove-deprecated-i18n-options": { - "version": "12.0.0-next.7", - "factory": "./update-12/update-i18n", - "description": "Remove deprecated ViewEngine-based i18n build and extract options. Options present in the configuration will be converted to use non-deprecated options." - }, - "update-web-workers-webpack-5": { - "version": "12.0.0-next.7", - "factory": "./update-12/update-web-workers", - "description": "Updates Web Worker consumer usage to use the new syntax supported directly by Webpack 5." - }, - "schematic-options-12": { - "version": "12.0.1", - "factory": "./update-12/schematic-options", - "description": "Remove invalid 'skipTests' option in '@schematics/angular:module' Angular schematic options." - }, - "replace-deprecated-prod-flag": { - "version": "12.1.0", - "factory": "./update-12/replace-prod-flag", - "description": "Replace the deprecated '--prod' in package.json scripts." - }, - "production-by-default": { - "version": "9999.0.0", - "factory": "./update-12/production-default-config", - "description": "Optional migration to update Angular CLI workspace configurations to 'production' mode by default." - }, "schematic-options-13": { "version": "13.0.0", "factory": "./update-13/schematic-options", 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..deffd21ef365 --- /dev/null +++ b/tests/legacy-cli/e2e/tests/update/update-multiple-versions.ts @@ -0,0 +1,35 @@ +import { createProjectFromAsset } from '../../utils/assets'; +import { installWorkspacePackages, setRegistry } from '../../utils/packages'; +import { ng } from '../../utils/process'; +import { isPrereleaseCli } from '../../utils/project'; +import { expectToFail } from '../../utils/utils'; + +export default async function () { + try { + await createProjectFromAsset('9.0-project', true, true); + await setRegistry(false); + await installWorkspacePackages(); + + await setRegistry(true); + const extraArgs = ['--force']; + if (isPrereleaseCli()) { + extraArgs.push('--next'); + } + + const { message } = await expectToFail(() => + ng('update', '@angular/cli', '--force', ...extraArgs), + ); + if ( + !message.includes( + `Updating multiple major versions of '@angular/cli' at once is not supported`, + ) + ) { + console.error(message); + throw new Error( + `Expected error message to include "Updating multiple major versions of '@angular/cli' at once is not supported" but didn't.`, + ); + } + } finally { + await setRegistry(true); + } +}