From 8795536a31efbed6373787188cb21c5d1e0accbd Mon Sep 17 00:00:00 2001 From: Alan Agius Date: Thu, 28 Oct 2021 10:44:12 +0200 Subject: [PATCH] fix(@angular/cli): update `ng update` output for Angular packages With #21986 we now error when updating `@angular/` and `@nguniversal/` packages across multiple major versions. With this chnage we update `ng update` output to show the correct instructions. Before ``` $ ng update --next We analyzed your package.json, there are some packages to update: Name Version Command to update -------------------------------------------------------------------------------- @angular/cli 12.2.12 -> 13.0.0-rc.2 ng update @angular/cli --next @angular/core 11.2.14 -> 13.0.0-rc.2 ng update @angular/core --next ``` Now ``` $ ng update --next We analyzed your package.json, there are some packages to update: Name Version Command to update -------------------------------------------------------------------------------- @angular/cli 12.2.12 -> 13.0.0-rc.2 ng update @angular/cli --next @angular/core 11.2.14 -> 12.2.9 ng update @angular/core@12 ``` Closes #19381 (cherry picked from commit 9b32066e88a8d177b52783f977716eaf2688a163) --- .../src/commands/update/schematic/index.ts | 43 +++++++++++++++---- .../tests/update/update-multiple-versions.ts | 20 ++++++--- 2 files changed, 49 insertions(+), 14 deletions(-) diff --git a/packages/angular/cli/src/commands/update/schematic/index.ts b/packages/angular/cli/src/commands/update/schematic/index.ts index e7d7a60752df..4e951adee87a 100644 --- a/packages/angular/cli/src/commands/update/schematic/index.ts +++ b/packages/angular/cli/src/commands/update/schematic/index.ts @@ -418,13 +418,39 @@ function _usageMessage( const packageGroups = new Map(); const packagesToUpdate = [...infoMap.entries()] .map(([name, info]) => { - const tag = options.next + let tag = options.next ? info.npmPackageJson['dist-tags']['next'] ? 'next' : 'latest' : 'latest'; - const version = info.npmPackageJson['dist-tags'][tag]; - const target = info.npmPackageJson.versions[version]; + let version = info.npmPackageJson['dist-tags'][tag]; + let target = info.npmPackageJson.versions[version]; + + const versionDiff = semver.diff(info.installed.version, version); + if ( + versionDiff !== 'patch' && + versionDiff !== 'minor' && + /^@(?:angular|nguniversal)\//.test(name) + ) { + const installedMajorVersion = semver.parse(info.installed.version)?.major; + const toInstallMajorVersion = semver.parse(version)?.major; + if ( + installedMajorVersion !== undefined && + toInstallMajorVersion !== undefined && + installedMajorVersion < toInstallMajorVersion - 1 + ) { + const nextMajorVersion = `${installedMajorVersion + 1}.`; + const nextMajorVersions = Object.keys(info.npmPackageJson.versions) + .filter((v) => v.startsWith(nextMajorVersion)) + .sort((a, b) => (a > b ? -1 : 1)); + + if (nextMajorVersions.length) { + version = nextMajorVersions[0]; + target = info.npmPackageJson.versions[version]; + tag = ''; + } + } + } return { name, @@ -442,10 +468,9 @@ function _usageMessage( }) .map(({ name, info, version, tag, target }) => { // Look for packageGroup. - if (target['ng-update'] && target['ng-update']['packageGroup']) { - const packageGroup = target['ng-update']['packageGroup']; - const packageGroupName = - target['ng-update']['packageGroupName'] || target['ng-update']['packageGroup'][0]; + const packageGroup = target['ng-update']?.['packageGroup']; + if (packageGroup) { + const packageGroupName = packageGroup?.[0]; if (packageGroupName) { if (packageGroups.has(name)) { return null; @@ -458,7 +483,9 @@ function _usageMessage( } let command = `ng update ${name}`; - if (tag == 'next') { + if (!tag) { + command += `@${semver.parse(version)?.major || version}`; + } else if (tag == 'next') { command += ' --next'; } diff --git a/tests/legacy-cli/e2e/tests/update/update-multiple-versions.ts b/tests/legacy-cli/e2e/tests/update/update-multiple-versions.ts index deffd21ef365..34a80522b33d 100644 --- a/tests/legacy-cli/e2e/tests/update/update-multiple-versions.ts +++ b/tests/legacy-cli/e2e/tests/update/update-multiple-versions.ts @@ -9,24 +9,32 @@ export default async function () { 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), - ); + // Update Angular from v9 to 10 + const { stdout } = await ng('update', ...extraArgs); + if (!/@angular\/core\s+9\.\d\.\d+ -> 10\.\d\.\d+\s+ng update @angular\/core@10/.test(stdout)) { + // @angular/core 9.x.x -> 10.x.x ng update @angular/core@11 + throw new Error( + `Output didn't match "@angular/core 9.x.x -> 10.x.x ng update @angular/core@10". OUTPUT: \n` + + stdout, + ); + } + + const { message } = await expectToFail(() => ng('update', '@angular/cli', ...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.`, + `Expected error message to include "Updating multiple major versions of '@angular/cli' at once is not supported" but didn't. OUTPUT: \n` + + message, ); } } finally {