diff --git a/packages/angular/cli/lib/init.ts b/packages/angular/cli/lib/init.ts index 9b94a248c1..f0620e7a14 100644 --- a/packages/angular/cli/lib/init.ts +++ b/packages/angular/cli/lib/init.ts @@ -10,12 +10,20 @@ import 'symbol-observable'; // symbol polyfill must go first import { promises as fs } from 'fs'; import * as path from 'path'; -import { SemVer } from 'semver'; +import { SemVer, major } from 'semver'; import { colors } from '../src/utilities/color'; import { isWarningEnabled } from '../src/utilities/config'; import { disableVersionCheck } from '../src/utilities/environment-options'; import { VERSION } from '../src/utilities/version'; +/** + * Angular CLI versions prior to v14 may not exit correctly if not forcibly exited + * via `process.exit()`. When bootstrapping, `forceExit` will be set to `true` + * if the local CLI version is less than v14 to prevent the CLI from hanging on + * exit in those cases. + */ +let forceExit = false; + (async () => { /** * Disable Browserslist old data warning as otherwise with every release we'd need to update this dependency @@ -57,6 +65,11 @@ import { VERSION } from '../src/utilities/version'; } } + // Ensure older versions of the CLI fully exit + if (major(localVersion) < 14) { + forceExit = true; + } + let isGlobalGreater = false; try { isGlobalGreater = !!localVersion && globalVersion.compare(localVersion) > 0; @@ -107,6 +120,9 @@ import { VERSION } from '../src/utilities/version'; }); }) .then((exitCode: number) => { + if (forceExit) { + process.exit(exitCode); + } process.exitCode = exitCode; }) .catch((err: Error) => { diff --git a/tests/legacy-cli/e2e/tests/misc/cli-exit-interop.ts b/tests/legacy-cli/e2e/tests/misc/cli-exit-interop.ts new file mode 100644 index 0000000000..3d4b72befd --- /dev/null +++ b/tests/legacy-cli/e2e/tests/misc/cli-exit-interop.ts @@ -0,0 +1,34 @@ +import { createProjectFromAsset } from '../../utils/assets'; +import { moveFile, replaceInFile } from '../../utils/fs'; +import { setRegistry } from '../../utils/packages'; +import { noSilentNg } from '../../utils/process'; +import { useCIChrome } from '../../utils/project'; +import { expectToFail } from '../../utils/utils'; + +/** + * @fileoverview This tests that using the latest version of the CLI globally does not cause older (< 14) + * versions of the CLI to never exit after completing certain commands. + * This test will timeout in a failure condition. + */ + +export default async function () { + try { + // We need to use the public registry because in the local NPM server we don't have + // older versions @angular/cli packages which would cause `npm install` during `ng update` to fail. + await setRegistry(false); + await createProjectFromAsset('12.0-project', true); + + // A missing stylesheet error will trigger the stuck process issue with v12 when building + await moveFile('src/styles.css', 'src/styles.scss'); + await expectToFail(() => noSilentNg('build')); + + // Setup a SCSS global stylesheet + // Simulates issue https://github.com/angular/angular-cli/issues/23289 + await replaceInFile('angular.json', /styles\.css/g, 'styles.scss'); + + await useCIChrome(); + await noSilentNg('test', '--watch=false'); + } finally { + await setRegistry(true); + } +}