Skip to content

Commit 644f86d

Browse files
committed
fix(@angular/cli): improve error message for Windows autocompletion use cases
Windows Cmd and Powershell don't support autocompletion, but it can be done with utilities like Windows Subsystem for Linux and Git Bash, which should "just work" due to emulating a Linux environment. This clarifies the error message most users will see to call out the state of the world with regard to autocompletion on Windows platforms. (cherry picked from commit 3ab1142)
1 parent e542c88 commit 644f86d

File tree

3 files changed

+54
-8
lines changed

3 files changed

+54
-8
lines changed

packages/angular/cli/src/utilities/completion.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,9 @@ export async function initializeAutocomplete(): Promise<string> {
193193
if (!shell) {
194194
throw new Error(
195195
'`$SHELL` environment variable not set. Angular CLI autocompletion only supports Bash or' +
196-
' Zsh.',
196+
" Zsh. If you're on Windows, Cmd and Powershell don't support command autocompletion," +
197+
' but Git Bash or Windows Subsystem for Linux should work, so please try again in one of' +
198+
' those environments.',
197199
);
198200
}
199201
const home = env['HOME'];
@@ -234,7 +236,7 @@ export async function initializeAutocomplete(): Promise<string> {
234236
return rcFile;
235237
}
236238

237-
/** Returns an ordered list of possibile candidates of RC files used by the given shell. */
239+
/** Returns an ordered list of possible candidates of RC files used by the given shell. */
238240
function getShellRunCommandCandidates(shell: string, home: string): string[] | undefined {
239241
if (shell.toLowerCase().includes('bash')) {
240242
return ['.bashrc', '.bash_profile', '.profile'].map((file) => path.join(home, file));

tests/legacy-cli/e2e/tests/misc/completion-prompt.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ const DEFAULT_ENV = Object.freeze({
1919
});
2020

2121
export default async function () {
22+
// Windows Cmd and Powershell do not support autocompletion. Run a different set of tests to
23+
// confirm autocompletion skips the prompt appropriately.
24+
if (process.platform === 'win32') {
25+
await windowsTests();
26+
return;
27+
}
28+
2229
// Sets up autocompletion after user accepts a prompt from any command.
2330
await mockHome(async (home) => {
2431
const bashrc = path.join(home, '.bashrc');
@@ -42,7 +49,7 @@ export default async function () {
4249
const bashrcContents = await fs.readFile(bashrc, 'utf-8');
4350
if (!bashrcContents.includes('source <(ng completion script)')) {
4451
throw new Error(
45-
'Autocompletion was *not* added to `~/.bashrc` after accepting the setup' + ' prompt.',
52+
'Autocompletion was *not* added to `~/.bashrc` after accepting the setup prompt.',
4653
);
4754
}
4855

@@ -74,13 +81,13 @@ export default async function () {
7481
const bashrcContents = await fs.readFile(bashrc, 'utf-8');
7582
if (bashrcContents.includes('ng completion')) {
7683
throw new Error(
77-
'Autocompletion was incorrectly added to `~/.bashrc` after refusing the setup' + ' prompt.',
84+
'Autocompletion was incorrectly added to `~/.bashrc` after refusing the setup prompt.',
7885
);
7986
}
8087

8188
if (stdout.includes('Appended `source <(ng completion script)`')) {
8289
throw new Error(
83-
'CLI printed that it successfully set up autocompletion when it actually' + " didn't.",
90+
"CLI printed that it successfully set up autocompletion when it actually didn't.",
8491
);
8592
}
8693

@@ -363,6 +370,23 @@ source <(ng completion script)
363370
});
364371
}
365372

373+
async function windowsTests(): Promise<void> {
374+
// Should *not* prompt on Windows, autocompletion isn't supported.
375+
await mockHome(async (home) => {
376+
const bashrc = path.join(home, '.bashrc');
377+
await fs.writeFile(bashrc, `# Other content...`);
378+
379+
const { stdout } = await execWithEnv('ng', ['version'], { ...env });
380+
381+
if (AUTOCOMPLETION_PROMPT.test(stdout)) {
382+
throw new Error(
383+
'Execution prompted to set up autocompletion on Windows despite not actually being' +
384+
' supported.',
385+
);
386+
}
387+
});
388+
}
389+
366390
async function mockHome(cb: (home: string) => Promise<void>): Promise<void> {
367391
const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), 'angular-cli-e2e-home-'));
368392

tests/legacy-cli/e2e/tests/misc/completion.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@ import * as path from 'path';
44
import { execAndCaptureError, execAndWaitForOutputToMatch } from '../../utils/process';
55

66
export default async function () {
7+
// Windows Cmd and Powershell do not support autocompletion. Run a different set of tests to
8+
// confirm autocompletion fails gracefully.
9+
if (process.platform === 'win32') {
10+
await windowsTests();
11+
12+
return;
13+
}
14+
715
// Generates new `.bashrc` file.
816
await mockHome(async (home) => {
917
await execAndWaitForOutputToMatch(
@@ -302,25 +310,37 @@ source <(ng completion script)
302310
}
303311

304312
// Fails for no `$SHELL`.
305-
{
313+
await mockHome(async (home) => {
306314
const err = await execAndCaptureError('ng', ['completion'], {
307315
...process.env,
308316
SHELL: undefined,
317+
HOME: home,
309318
});
310319
if (!err.message.includes('`$SHELL` environment variable not set.')) {
311320
throw new Error(`Expected unset \`$SHELL\` error message, but got:\n\n${err.message}`);
312321
}
313-
}
322+
});
314323

315324
// Fails for unknown `$SHELL`.
316-
{
325+
await mockHome(async (home) => {
317326
const err = await execAndCaptureError('ng', ['completion'], {
318327
...process.env,
319328
SHELL: '/usr/bin/unknown',
329+
HOME: home,
320330
});
321331
if (!err.message.includes('Unknown `$SHELL` environment variable')) {
322332
throw new Error(`Expected unknown \`$SHELL\` error message, but got:\n\n${err.message}`);
323333
}
334+
});
335+
}
336+
337+
async function windowsTests(): Promise<void> {
338+
// Should fail with a clear error message.
339+
const err = await execAndCaptureError('ng', ['completion']);
340+
if (!err.message.includes("Cmd and Powershell don't support command autocompletion")) {
341+
throw new Error(
342+
`Expected Windows autocompletion to fail with custom error, but got:\n\n${err.message}`,
343+
);
324344
}
325345
}
326346

0 commit comments

Comments
 (0)