Skip to content

Commit f75bd57

Browse files
clydinalan-agius4
authored andcommitted
fix(@angular/cli): remove npm 7 incompatibility notification
npm 7.5.6 contains several fixes that allow it to work successfully with the Angular CLI. The minimum npm engine value is now set to support npm versions greater than 7.5.6 (npm 6 support remains unchanged). A warning will be shown to users with npm 7 versions less than 7.5.6 when used with the new, add, or update commands.
1 parent a4d091c commit f75bd57

File tree

5 files changed

+75
-28
lines changed

5 files changed

+75
-28
lines changed

lib/packages.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ function loadPackageJson(p: string) {
8484
case 'engines':
8585
pkg['engines'] = {
8686
'node': '>= 10.13.0',
87-
'npm': '^6.11.0',
87+
'npm': '^6.11.0 || ^7.5.6',
8888
'yarn': '>= 1.13.0',
8989
};
9090
break;

packages/angular/cli/commands/new-impl.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ export class NewCommand extends SchematicCommand<NewCommandSchema> {
2424
}
2525

2626
public async run(options: NewCommandSchema & Arguments) {
27-
await ensureCompatibleNpm(this.workspace.root);
28-
2927
// Register the version of the CLI in the registry.
3028
const packageJson = require('../package.json');
3129
const version = packageJson.version;

packages/angular/cli/models/schematic-command.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import {
4040
getWorkspaceRaw,
4141
} from '../utilities/config';
4242
import { parseJsonSchemaToOptions } from '../utilities/json-schema';
43-
import { getPackageManager } from '../utilities/package-manager';
43+
import { ensureCompatibleNpm, getPackageManager } from '../utilities/package-manager';
4444
import { isTTY } from '../utilities/tty';
4545
import { isPackageNameSafeForAnalytics } from './analytics';
4646
import { BaseCommandOptions, Command } from './command';
@@ -534,6 +534,16 @@ export abstract class SchematicCommand<
534534
}
535535
});
536536

537+
// Temporary compatibility check for NPM 7
538+
if (collectionName === '@schematics/angular' && schematicName === 'ng-new') {
539+
if (
540+
!input.skipInstall &&
541+
(input.packageManager === undefined || input.packageManager === 'npm')
542+
) {
543+
await ensureCompatibleNpm(this.workspace.root);
544+
}
545+
}
546+
537547
return new Promise<number | void>(resolve => {
538548
workflow
539549
.execute({

packages/angular/cli/utilities/package-manager.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import { execSync } from 'child_process';
99
import { existsSync } from 'fs';
1010
import { join } from 'path';
11+
import { satisfies, valid } from 'semver';
1112
import { PackageManager } from '../lib/config/schema';
1213
import { getConfiguredPackageManager } from './config';
1314

@@ -56,27 +57,27 @@ export async function getPackageManager(root: string): Promise<PackageManager> {
5657
}
5758

5859
/**
59-
* Checks if the npm version is version 6.x. If not, display a message and exit.
60+
* Checks if the npm version is a supported 7.x version. If not, display a warning.
6061
*/
6162
export async function ensureCompatibleNpm(root: string): Promise<void> {
6263
if ((await getPackageManager(root)) !== PackageManager.Npm) {
6364
return;
6465
}
6566

6667
try {
67-
const version = execSync('npm --version', {encoding: 'utf8', stdio: 'pipe'}).trim();
68-
const major = Number(version.match(/^(\d+)\./)?.[1]);
69-
if (major === 6) {
68+
const versionText = execSync('npm --version', {encoding: 'utf8', stdio: 'pipe'}).trim();
69+
const version = valid(versionText);
70+
if (!version) {
7071
return;
7172
}
7273

73-
// tslint:disable-next-line: no-console
74-
console.error(
75-
`npm version ${version} detected.\n` +
76-
'The Angular CLI currently requires npm version 6.\n\n' +
77-
'Please install a compatible version to proceed (`npm install --global npm@6`).\n',
78-
);
79-
process.exit(3);
74+
if (satisfies(version, '>=7 <7.5.6')) {
75+
// tslint:disable-next-line: no-console
76+
console.warn(
77+
`npm version ${version} detected.` +
78+
' When using npm 7 with the Angular CLI, npm version 7.5.6 or higher is recommended.',
79+
);
80+
}
8081
} catch {
8182
// npm is not installed
8283
}

tests/legacy-cli/e2e/tests/misc/npm-7.ts

Lines changed: 51 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1+
import { rimraf } from '../../utils/fs';
12
import { ng, npm } from '../../utils/process';
23
import { expectToFail } from '../../utils/utils';
34

4-
const errorText = 'The Angular CLI currently requires npm version 6.';
5+
const warningText = 'npm version 7.5.6 or higher is recommended';
56

67
export default async function() {
78
// Windows CI fails with permission errors when trying to replace npm
@@ -11,29 +12,66 @@ export default async function() {
1112

1213
const currentDirectory = process.cwd();
1314
try {
14-
// Install version 7.x
15-
await npm('install', '--global', 'npm@7');
15+
// Install version >=7.5.6
16+
await npm('install', '--global', 'npm@>=7.5.6');
1617

17-
// Ensure `ng add` exits and shows npm error
18+
// Ensure `ng update` does not show npm warning
19+
const { stderr: stderrUpdate1 } = await ng('update');
20+
if (stderrUpdate1.includes(warningText)) {
21+
throw new Error('ng update expected to not show npm version warning.');
22+
}
23+
24+
// Install version <7.5.6
25+
await npm('install', '--global', '[email protected]');
26+
27+
// Ensure `ng add` shows npm warning
1828
const { message: stderrAdd } = await expectToFail(() => ng('add'));
19-
if (!stderrAdd.includes(errorText)) {
20-
throw new Error('ng add expected to show npm version error.');
29+
if (!stderrAdd.includes(warningText)) {
30+
throw new Error('ng add expected to show npm version warning.');
2131
}
2232

23-
// Ensure `ng update` exits and shows npm error
24-
const { message: stderrUpdate } = await expectToFail(() => ng('update'));
25-
if (!stderrUpdate.includes(errorText)) {
26-
throw new Error('ng update expected to show npm version error.');
33+
// Ensure `ng update` shows npm warning
34+
const { stderr: stderrUpdate2 } = await ng('update');
35+
if (!stderrUpdate2.includes(warningText)) {
36+
throw new Error('ng update expected to show npm version warning.');
2737
}
2838

29-
// Ensure `ng new` exits and shows npm error
39+
// Ensure `ng build` executes successfully
40+
const { stderr: stderrBuild } = await ng('build');
41+
if (stderrBuild.includes(warningText)) {
42+
throw new Error('ng build expected to not show npm version warning.');
43+
}
44+
45+
// Ensure `ng new` shows npm warning
3046
// Must be outside the project for `ng new`
3147
process.chdir('..');
3248
const { message: stderrNew } = await expectToFail(() => ng('new'));
33-
if (!stderrNew.includes(errorText)) {
34-
throw new Error('ng new expected to show npm version error.');
49+
if (!stderrNew.includes(warningText)) {
50+
throw new Error('ng new expected to show npm version warning.');
51+
}
52+
53+
// Ensure `ng new --package-manager=npm` shows npm warning
54+
const { message: stderrNewNpm } = await expectToFail(() => ng('new', '--package-manager=npm'));
55+
if (!stderrNewNpm.includes(warningText)) {
56+
throw new Error('ng new expected to show npm version warning.');
57+
}
58+
59+
// Ensure `ng new --skip-install` executes successfully
60+
const { stderr: stderrNewSkipInstall } = await ng('new', 'npm-seven-skip', '--skip-install');
61+
if (stderrNewSkipInstall.includes(warningText)) {
62+
throw new Error('ng new --skip-install expected to not show npm version warning.');
63+
}
64+
65+
// Ensure `ng new --package-manager=yarn` executes successfully
66+
const { stderr: stderrNewYarn } = await ng('new', 'npm-seven-yarn', '--package-manager=yarn');
67+
if (stderrNewYarn.includes(warningText)) {
68+
throw new Error('ng new --package-manager=yarn expected to not show npm version warning.');
3569
}
3670
} finally {
71+
// Cleanup extra test projects
72+
await rimraf('npm-seven-skip');
73+
await rimraf('npm-seven-yarn');
74+
3775
// Change directory back
3876
process.chdir(currentDirectory);
3977

0 commit comments

Comments
 (0)