Skip to content

Commit 4857b17

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.
1 parent 6dc0ca7 commit 4857b17

File tree

3 files changed

+50
-8
lines changed

3 files changed

+50
-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: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ const DEFAULT_ENV = Object.freeze({
1919
});
2020

2121
export default async function () {
22+
if (process.platform === 'win32') {
23+
await windowsTests();
24+
return; // Windows should never prompt for autocompletion.
25+
}
26+
2227
// Sets up autocompletion after user accepts a prompt from any command.
2328
await mockHome(async (home) => {
2429
const bashrc = path.join(home, '.bashrc');
@@ -42,7 +47,7 @@ export default async function () {
4247
const bashrcContents = await fs.readFile(bashrc, 'utf-8');
4348
if (!bashrcContents.includes('source <(ng completion script)')) {
4449
throw new Error(
45-
'Autocompletion was *not* added to `~/.bashrc` after accepting the setup' + ' prompt.',
50+
'Autocompletion was *not* added to `~/.bashrc` after accepting the setup prompt.',
4651
);
4752
}
4853

@@ -74,13 +79,13 @@ export default async function () {
7479
const bashrcContents = await fs.readFile(bashrc, 'utf-8');
7580
if (bashrcContents.includes('ng completion')) {
7681
throw new Error(
77-
'Autocompletion was incorrectly added to `~/.bashrc` after refusing the setup' + ' prompt.',
82+
'Autocompletion was incorrectly added to `~/.bashrc` after refusing the setup prompt.',
7883
);
7984
}
8085

8186
if (stdout.includes('Appended `source <(ng completion script)`')) {
8287
throw new Error(
83-
'CLI printed that it successfully set up autocompletion when it actually' + " didn't.",
88+
"CLI printed that it successfully set up autocompletion when it actually didn't.",
8489
);
8590
}
8691

@@ -363,6 +368,23 @@ source <(ng completion script)
363368
});
364369
}
365370

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

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

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

66
export default async function () {
7+
if (process.platform === 'win32') {
8+
await windowsTests(); // Windows does not support autocompletion.
9+
10+
return;
11+
}
12+
713
// Generates new `.bashrc` file.
814
await mockHome(async (home) => {
915
await execAndWaitForOutputToMatch(
@@ -302,25 +308,37 @@ source <(ng completion script)
302308
}
303309

304310
// Fails for no `$SHELL`.
305-
{
311+
await mockHome(async (home) => {
306312
const err = await execAndCaptureError('ng', ['completion'], {
307313
...process.env,
308314
SHELL: undefined,
315+
HOME: home,
309316
});
310317
if (!err.message.includes('`$SHELL` environment variable not set.')) {
311318
throw new Error(`Expected unset \`$SHELL\` error message, but got:\n\n${err.message}`);
312319
}
313-
}
320+
});
314321

315322
// Fails for unknown `$SHELL`.
316-
{
323+
await mockHome(async (home) => {
317324
const err = await execAndCaptureError('ng', ['completion'], {
318325
...process.env,
319326
SHELL: '/usr/bin/unknown',
327+
HOME: home,
320328
});
321329
if (!err.message.includes('Unknown `$SHELL` environment variable')) {
322330
throw new Error(`Expected unknown \`$SHELL\` error message, but got:\n\n${err.message}`);
323331
}
332+
});
333+
}
334+
335+
async function windowsTests(): Promise<void> {
336+
// Should fail with a clear error message.
337+
const err = await execAndCaptureError('ng', ['completion']);
338+
if (!err.message.includes("Cmd and Powershell don't support command autocompletion")) {
339+
throw new Error(
340+
`Expected Windows autocompletion to fail with custom error, but got:\n\n${err.message}`,
341+
);
324342
}
325343
}
326344

0 commit comments

Comments
 (0)