mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-16 18:43:42 +08:00
feat(@angular/cli): verify Angular version is supported
This commit is contained in:
parent
bab9eb6b06
commit
5ec27db6bc
@ -95,7 +95,7 @@
|
||||
"@types/minimist": "^1.2.0",
|
||||
"@types/node": "10.9.4",
|
||||
"@types/request": "^2.47.1",
|
||||
"@types/semver": "^5.5.0",
|
||||
"@types/semver": "^6.0.0",
|
||||
"@types/source-map": "0.5.2",
|
||||
"@types/webpack": "^4.4.11",
|
||||
"@types/webpack-dev-server": "^3.1.0",
|
||||
@ -122,7 +122,7 @@
|
||||
"pidtree": "^0.3.0",
|
||||
"pidusage": "^2.0.17",
|
||||
"rxjs": "~6.4.0",
|
||||
"semver": "^5.3.0",
|
||||
"semver": "6.0.0",
|
||||
"source-map": "^0.5.6",
|
||||
"source-map-support": "^0.5.0",
|
||||
"spdx-satisfies": "^4.0.0",
|
||||
|
@ -8,16 +8,12 @@
|
||||
import { analytics } from '@angular-devkit/core';
|
||||
import { ArchitectCommand, ArchitectCommandOptions } from '../models/architect-command';
|
||||
import { Arguments } from '../models/interface';
|
||||
import { Version } from '../upgrade/version';
|
||||
import { Schema as BuildCommandSchema } from './build';
|
||||
|
||||
export class BuildCommand extends ArchitectCommand<BuildCommandSchema> {
|
||||
public readonly target = 'build';
|
||||
|
||||
public async run(options: ArchitectCommandOptions & Arguments) {
|
||||
// Check Angular version.
|
||||
Version.assertCompatibleAngularVersion(this.workspace.root);
|
||||
|
||||
return this.runArchitectTarget(options);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,6 @@
|
||||
import { analytics } from '@angular-devkit/core';
|
||||
import { ArchitectCommand, ArchitectCommandOptions } from '../models/architect-command';
|
||||
import { Arguments } from '../models/interface';
|
||||
import { Version } from '../upgrade/version';
|
||||
import { Schema as BuildCommandSchema } from './build';
|
||||
import { Schema as ServeCommandSchema } from './serve';
|
||||
|
||||
@ -16,9 +15,6 @@ export class ServeCommand extends ArchitectCommand<ServeCommandSchema> {
|
||||
public readonly target = 'serve';
|
||||
|
||||
public validate(_options: ArchitectCommandOptions & Arguments) {
|
||||
// Check Angular versions.
|
||||
Version.assertCompatibleAngularVersion(this.workspace.root);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import { Architect, Target } from '@angular-devkit/architect';
|
||||
import { WorkspaceNodeModulesArchitectHost } from '@angular-devkit/architect/node';
|
||||
import { experimental, json, schema, tags } from '@angular-devkit/core';
|
||||
import { NodeJsSyncHost } from '@angular-devkit/core/node';
|
||||
import { Version } from '../upgrade/version';
|
||||
import { BepJsonWriter } from '../utilities/bep';
|
||||
import { parseJsonSchemaToOptions } from '../utilities/json-schema';
|
||||
import { isPackageNameSafeForAnalytics } from './analytics';
|
||||
@ -274,6 +275,9 @@ export abstract class ArchitectCommand<
|
||||
protected async runArchitectTarget(
|
||||
options: ArchitectCommandOptions & Arguments,
|
||||
): Promise<number> {
|
||||
// Check Angular version.
|
||||
Version.assertCompatibleAngularVersion(this.workspace.root);
|
||||
|
||||
const extra = options['--'] || [];
|
||||
|
||||
try {
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
import { tags, terminal } from '@angular-devkit/core';
|
||||
import * as path from 'path';
|
||||
import { SemVer } from 'semver';
|
||||
import { SemVer, satisfies } from 'semver';
|
||||
|
||||
|
||||
export class Version {
|
||||
@ -26,6 +26,12 @@ export class Version {
|
||||
isGreaterThanOrEqualTo(other: SemVer) {
|
||||
return this._semver !== null && this._semver.compare(other) >= 0;
|
||||
}
|
||||
satisfies(other: string) {
|
||||
// This comparison includes pre-releases (like betas and rcs), and considers them to be
|
||||
// before the release proper.
|
||||
// e.g. '9.0.0-beta.1' will satisfy '>=7.0.0 <9.0.0', but '9.0.0' will not.
|
||||
return this._semver !== null && satisfies(this._semver, other, { includePrerelease: true });
|
||||
}
|
||||
|
||||
get major() { return this._semver ? this._semver.major : 0; }
|
||||
get minor() { return this._semver ? this._semver.minor : 0; }
|
||||
@ -36,11 +42,12 @@ export class Version {
|
||||
toString() { return this._version; }
|
||||
|
||||
static assertCompatibleAngularVersion(projectRoot: string) {
|
||||
let angularCliPkgJson;
|
||||
let angularPkgJson;
|
||||
let rxjsPkgJson;
|
||||
const resolveOptions = { paths: [projectRoot] };
|
||||
|
||||
try {
|
||||
const resolveOptions = { paths: [projectRoot] };
|
||||
const angularPackagePath = require.resolve('@angular/core/package.json', resolveOptions);
|
||||
const rxjsPackagePath = require.resolve('rxjs/package.json', resolveOptions);
|
||||
|
||||
@ -61,6 +68,26 @@ export class Version {
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
try {
|
||||
const angularCliPkgPath = require.resolve('@angular/cli/package.json', resolveOptions);
|
||||
angularCliPkgJson = require(angularCliPkgPath);
|
||||
if (!(angularCliPkgJson && angularCliPkgJson['version'])) {
|
||||
throw new Error();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(terminal.bold(terminal.red(tags.stripIndents`
|
||||
Cannot determine versions of "@angular/cli".
|
||||
This likely means your local installation is broken. Please reinstall your packages.
|
||||
`)));
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
const cliMajor = new Version(angularCliPkgJson['version']).major;
|
||||
// e.g. CLI 8.0 supports '>=8.0.0 <9.0.0', including pre-releases (betas, rcs, snapshots)
|
||||
// of both 8 and 9.
|
||||
const supportedAngularSemver = `^${cliMajor}.0.0-beta || ` +
|
||||
`>=${cliMajor}.0.0 <${cliMajor + 1}.0.0`;
|
||||
|
||||
const angularVersion = new Version(angularPkgJson['version']);
|
||||
const rxjsVersion = new Version(rxjsPkgJson['version']);
|
||||
|
||||
@ -70,9 +97,10 @@ export class Version {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!angularVersion.isGreaterThanOrEqualTo(new SemVer('5.0.0'))) {
|
||||
if (!angularVersion.satisfies(supportedAngularSemver)) {
|
||||
console.error(terminal.bold(terminal.red(tags.stripIndents`
|
||||
This version of CLI is only compatible with Angular version 5.0.0 or higher.
|
||||
This version of CLI is only compatible with Angular versions ${supportedAngularSemver},
|
||||
but Angular version ${angularVersion} was found instead.
|
||||
|
||||
Please visit the link below to find instructions on how to update Angular.
|
||||
https://angular-update-guide.firebaseapp.com/
|
||||
@ -84,7 +112,7 @@ export class Version {
|
||||
&& !rxjsVersion.isGreaterThanOrEqualTo(new SemVer('6.0.0-beta.0'))
|
||||
) {
|
||||
console.error(terminal.bold(terminal.red(tags.stripIndents`
|
||||
This project uses version ${rxjsVersion} of RxJs, which is not supported by Angular v6.
|
||||
This project uses version ${rxjsVersion} of RxJs, which is not supported by Angular v6+.
|
||||
The official RxJs version that is supported is 5.6.0-forward-compat.0 and greater.
|
||||
|
||||
Please visit the link below to find instructions on how to update RxJs.
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { HttpModule } from '@angular/http';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
@ -12,7 +11,6 @@ import { AppComponent } from './app.component';
|
||||
imports: [
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
HttpModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
|
@ -7,7 +7,7 @@ import { expectToFail } from '../../utils/utils';
|
||||
|
||||
|
||||
export default async function () {
|
||||
const extraUpdateArgs = await isPrereleaseCli() ? ['--next'] : [];
|
||||
const extraUpdateArgs = await isPrereleaseCli() ? ['--next', '--force'] : [];
|
||||
|
||||
await createProjectFromAsset('1.0-project');
|
||||
await useCIChrome('.');
|
||||
|
@ -5,7 +5,7 @@ import { expectToFail } from '../../utils/utils';
|
||||
|
||||
|
||||
export default async function () {
|
||||
const extraUpdateArgs = await isPrereleaseCli() ? ['--next'] : [];
|
||||
const extraUpdateArgs = await isPrereleaseCli() ? ['--next', '--force'] : [];
|
||||
|
||||
await createProjectFromAsset('1.7-project');
|
||||
await expectToFail(() => ng('build'));
|
||||
|
@ -7,7 +7,7 @@ import { expectToFail } from '../../utils/utils';
|
||||
|
||||
|
||||
export default async function () {
|
||||
const extraUpdateArgs = await isPrereleaseCli() ? ['--next'] : [];
|
||||
const extraUpdateArgs = await isPrereleaseCli() ? ['--next', '--force'] : [];
|
||||
|
||||
await createProjectFromAsset('1.7-project');
|
||||
await useCIChrome('.');
|
||||
|
38
tests/legacy-cli/e2e/tests/misc/supported-angular.ts
Normal file
38
tests/legacy-cli/e2e/tests/misc/supported-angular.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import { SemVer } from 'semver';
|
||||
import { getGlobalVariable } from '../../utils/env';
|
||||
import { readFile, writeFile } from '../../utils/fs';
|
||||
import { ng } from '../../utils/process';
|
||||
import { expectToFail } from '../../utils/utils';
|
||||
|
||||
|
||||
export default async function () {
|
||||
if (getGlobalVariable('argv')['ng-snapshots'] || getGlobalVariable('argv')['ivy']) {
|
||||
// Don't run this test in snapshots or Ivy test jobs.
|
||||
// The snapshots job won't work correctly because it doesn't use semver for Angular, and the
|
||||
// Ivy job will fail because Ivy wasn't stable in 7.
|
||||
return;
|
||||
}
|
||||
|
||||
const angularCliPkgJson = JSON.parse(await readFile('node_modules/@angular/cli/package.json'));
|
||||
const cliMajor = new SemVer(angularCliPkgJson.version as string).major;
|
||||
const angularCorePkgPath = 'node_modules/@angular/core/package.json';
|
||||
const originalAngularCorePkgJson = await readFile(angularCorePkgPath);
|
||||
|
||||
// Fake version by writing over the @angular/core version, since that's what the CLI checks.
|
||||
const fakeCoreVersion = async (newMajor: number) => {
|
||||
const tmpPkgJson = JSON.parse(originalAngularCorePkgJson);
|
||||
tmpPkgJson.version = `${newMajor}.0.0`;
|
||||
await writeFile(angularCorePkgPath, JSON.stringify(tmpPkgJson));
|
||||
};
|
||||
|
||||
// Major should succeed, but we don't need to test it here since it's tested everywhere else.
|
||||
// Major+1 and -1 should fail architect commands, but allow other commands.
|
||||
await fakeCoreVersion(cliMajor + 1);
|
||||
await expectToFail(() => ng('build'), 'Should fail Major+1');
|
||||
await ng('version');
|
||||
await fakeCoreVersion(cliMajor - 1);
|
||||
await ng('version');
|
||||
|
||||
// Restore the original core package.json.
|
||||
await writeFile(angularCorePkgPath, originalAngularCorePkgJson);
|
||||
}
|
@ -548,10 +548,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-3.0.12.tgz#6affe5aed1ba379175075a889adbe2bc3aa62159"
|
||||
integrity sha512-hYn+eoOehVUIdMwp5h34ZsGAO1ydja10GDup4BwyoFCdcH5MQ35nQq+AInSaBMEMopD5hEooFCyKo2Pajbe1ag==
|
||||
|
||||
"@types/semver@^5.5.0":
|
||||
version "5.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45"
|
||||
integrity sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==
|
||||
"@types/semver@^6.0.0":
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-6.0.0.tgz#86ba89f02a414e39c68d02b351872e4ed31bd773"
|
||||
integrity sha512-OO0srjOGH99a4LUN2its3+r6CBYcplhJ466yLqs+zvAWgphCpS8hYZEZ797tRDP/QKcqTdb/YCN6ifASoAWkrQ==
|
||||
|
||||
"@types/serve-static@*":
|
||||
version "1.13.2"
|
||||
|
Loading…
x
Reference in New Issue
Block a user