mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-16 18:43:42 +08:00
Previously, when using an older version of the Angular CLI, during `ng update`, we download the temporary `latest` version to run the update. The ensured that when running that the runner used to run the update contains the latest bug fixes and improvements. This however, can be problematic in some cases. Such as when there are API breaking changes, when running a relatively old schematic with the latest CLI can cause runtime issues, especially since those schematics were never meant to be executed on a CLI X major versions in the future. With this change, we improve the logic to determine which version of the Angular CLI should be used to run the update. Below is a summarization of this. - When using the `--next` command line argument, the `@next` version of the CLI will be used to run the update. - When updating an `@angular/` or `@nguniversal/` package, the target version will be used to run the update. Example: `ng update @angular/core@12`, the update will run on most recent patch version of `@angular/cli` of that major version `@12.2.6`. - When updating an `@angular/` or `@nguniversal/` and no target version is specified. Example: `ng update @angular/core` the update will run on most latest version of the `@angular/cli`. - When updating a third-party package, the most recent patch version of the installed `@angular/cli` will be used to run the update. Example if `13.0.0` is installed and `13.1.1` is available on NPM, the latter will be used.
122 lines
4.3 KiB
TypeScript
122 lines
4.3 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import 'symbol-observable';
|
|
// symbol polyfill must go first
|
|
import { promises as fs } from 'fs';
|
|
import * as path from 'path';
|
|
import { SemVer } from 'semver';
|
|
import { VERSION } from '../models/version';
|
|
import { colors } from '../utilities/color';
|
|
import { isWarningEnabled } from '../utilities/config';
|
|
|
|
(async () => {
|
|
/**
|
|
* Disable Browserslist old data warning as otherwise with every release we'd need to update this dependency
|
|
* which is cumbersome considering we pin versions and the warning is not user actionable.
|
|
* `Browserslist: caniuse-lite is outdated. Please run next command `npm update`
|
|
* See: https://github.com/browserslist/browserslist/blob/819c4337456996d19db6ba953014579329e9c6e1/node.js#L324
|
|
*/
|
|
process.env.BROWSERSLIST_IGNORE_OLD_DATA = '1';
|
|
|
|
const disableVersionCheckEnv = process.env['NG_DISABLE_VERSION_CHECK'];
|
|
/**
|
|
* Disable CLI version mismatch checks and forces usage of the invoked CLI
|
|
* instead of invoking the local installed version.
|
|
*/
|
|
const disableVersionCheck =
|
|
disableVersionCheckEnv !== undefined &&
|
|
disableVersionCheckEnv !== '0' &&
|
|
disableVersionCheckEnv.toLowerCase() !== 'false';
|
|
|
|
if (disableVersionCheck) {
|
|
return (await import('./cli')).default;
|
|
}
|
|
|
|
let cli;
|
|
try {
|
|
// No error implies a projectLocalCli, which will load whatever
|
|
// version of ng-cli you have installed in a local package.json
|
|
const projectLocalCli = require.resolve('@angular/cli', { paths: [process.cwd()] });
|
|
cli = await import(projectLocalCli);
|
|
|
|
const globalVersion = new SemVer(VERSION.full);
|
|
|
|
// Older versions might not have the VERSION export
|
|
let localVersion = cli.VERSION?.full;
|
|
if (!localVersion) {
|
|
try {
|
|
const localPackageJson = await fs.readFile(
|
|
path.join(path.dirname(projectLocalCli), '../../package.json'),
|
|
'utf-8',
|
|
);
|
|
localVersion = (JSON.parse(localPackageJson) as { version: string }).version;
|
|
} catch (error) {
|
|
// eslint-disable-next-line no-console
|
|
console.error('Version mismatch check skipped. Unable to retrieve local version: ' + error);
|
|
}
|
|
}
|
|
|
|
let isGlobalGreater = false;
|
|
try {
|
|
isGlobalGreater = !!localVersion && globalVersion.compare(localVersion) > 0;
|
|
} catch (error) {
|
|
// eslint-disable-next-line no-console
|
|
console.error('Version mismatch check skipped. Unable to compare local version: ' + error);
|
|
}
|
|
|
|
if (isGlobalGreater) {
|
|
// If using the update command and the global version is greater, use the newer update command
|
|
// This allows improvements in update to be used in older versions that do not have bootstrapping
|
|
if (
|
|
process.argv[2] === 'update' &&
|
|
cli.VERSION &&
|
|
cli.VERSION.major - globalVersion.major <= 1
|
|
) {
|
|
cli = await import('./cli');
|
|
} else if (await isWarningEnabled('versionMismatch')) {
|
|
// Otherwise, use local version and warn if global is newer than local
|
|
const warning =
|
|
`Your global Angular CLI version (${globalVersion}) is greater than your local ` +
|
|
`version (${localVersion}). The local Angular CLI version is used.\n\n` +
|
|
'To disable this warning use "ng config -g cli.warnings.versionMismatch false".';
|
|
|
|
// eslint-disable-next-line no-console
|
|
console.error(colors.yellow(warning));
|
|
}
|
|
}
|
|
} catch {
|
|
// If there is an error, resolve could not find the ng-cli
|
|
// library from a package.json. Instead, include it from a relative
|
|
// path to this script file (which is likely a globally installed
|
|
// npm package). Most common cause for hitting this is `ng new`
|
|
cli = await import('./cli');
|
|
}
|
|
|
|
if ('default' in cli) {
|
|
cli = cli['default'];
|
|
}
|
|
|
|
return cli;
|
|
})()
|
|
.then((cli) => {
|
|
return cli({
|
|
cliArgs: process.argv.slice(2),
|
|
inputStream: process.stdin,
|
|
outputStream: process.stdout,
|
|
});
|
|
})
|
|
.then((exitCode: number) => {
|
|
process.exit(exitCode);
|
|
})
|
|
.catch((err: Error) => {
|
|
// eslint-disable-next-line no-console
|
|
console.error('Unknown error: ' + err.toString());
|
|
process.exit(127);
|
|
});
|