Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/angular/cli/src/utilities/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,9 @@ export async function initializeAutocomplete(): Promise<string> {
if (!shell) {
throw new Error(
'`$SHELL` environment variable not set. Angular CLI autocompletion only supports Bash or' +
' Zsh.',
" Zsh. If you're on Windows, Cmd and Powershell don't support command autocompletion," +
' but Git Bash or Windows Subsystem for Linux should work, so please try again in one of' +
' those environments.',
);
}
const home = env['HOME'];
Expand Down Expand Up @@ -234,7 +236,7 @@ export async function initializeAutocomplete(): Promise<string> {
return rcFile;
}

/** Returns an ordered list of possibile candidates of RC files used by the given shell. */
/** Returns an ordered list of possible candidates of RC files used by the given shell. */
function getShellRunCommandCandidates(shell: string, home: string): string[] | undefined {
if (shell.toLowerCase().includes('bash')) {
return ['.bashrc', '.bash_profile', '.profile'].map((file) => path.join(home, file));
Expand Down
30 changes: 27 additions & 3 deletions tests/legacy-cli/e2e/tests/misc/completion-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ const DEFAULT_ENV = Object.freeze({
});

export default async function () {
// Windows Cmd and Powershell do not support autocompletion. Run a different set of tests to
// confirm autocompletion skips the prompt appropriately.
if (process.platform === 'win32') {
await windowsTests();
return;
}

// Sets up autocompletion after user accepts a prompt from any command.
await mockHome(async (home) => {
const bashrc = path.join(home, '.bashrc');
Expand All @@ -42,7 +49,7 @@ export default async function () {
const bashrcContents = await fs.readFile(bashrc, 'utf-8');
if (!bashrcContents.includes('source <(ng completion script)')) {
throw new Error(
'Autocompletion was *not* added to `~/.bashrc` after accepting the setup' + ' prompt.',
'Autocompletion was *not* added to `~/.bashrc` after accepting the setup prompt.',
);
}

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

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

Expand Down Expand Up @@ -363,6 +370,23 @@ source <(ng completion script)
});
}

async function windowsTests(): Promise<void> {
// Should *not* prompt on Windows, autocompletion isn't supported.
await mockHome(async (home) => {
const bashrc = path.join(home, '.bashrc');
await fs.writeFile(bashrc, `# Other content...`);

const { stdout } = await execWithEnv('ng', ['version'], { ...env });

if (AUTOCOMPLETION_PROMPT.test(stdout)) {
throw new Error(
'Execution prompted to set up autocompletion on Windows despite not actually being' +
' supported.',
);
}
});
}

async function mockHome(cb: (home: string) => Promise<void>): Promise<void> {
const tempHome = await fs.mkdtemp(path.join(os.tmpdir(), 'angular-cli-e2e-home-'));

Expand Down
26 changes: 23 additions & 3 deletions tests/legacy-cli/e2e/tests/misc/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ import * as path from 'path';
import { execAndCaptureError, execAndWaitForOutputToMatch } from '../../utils/process';

export default async function () {
// Windows Cmd and Powershell do not support autocompletion. Run a different set of tests to
// confirm autocompletion fails gracefully.
if (process.platform === 'win32') {
await windowsTests();

return;
}

// Generates new `.bashrc` file.
await mockHome(async (home) => {
await execAndWaitForOutputToMatch(
Expand Down Expand Up @@ -302,25 +310,37 @@ source <(ng completion script)
}

// Fails for no `$SHELL`.
{
await mockHome(async (home) => {
const err = await execAndCaptureError('ng', ['completion'], {
...process.env,
SHELL: undefined,
HOME: home,
});
if (!err.message.includes('`$SHELL` environment variable not set.')) {
throw new Error(`Expected unset \`$SHELL\` error message, but got:\n\n${err.message}`);
}
}
});

// Fails for unknown `$SHELL`.
{
await mockHome(async (home) => {
const err = await execAndCaptureError('ng', ['completion'], {
...process.env,
SHELL: '/usr/bin/unknown',
HOME: home,
});
if (!err.message.includes('Unknown `$SHELL` environment variable')) {
throw new Error(`Expected unknown \`$SHELL\` error message, but got:\n\n${err.message}`);
}
});
}

async function windowsTests(): Promise<void> {
// Should fail with a clear error message.
const err = await execAndCaptureError('ng', ['completion']);
if (!err.message.includes("Cmd and Powershell don't support command autocompletion")) {
throw new Error(
`Expected Windows autocompletion to fail with custom error, but got:\n\n${err.message}`,
);
}
}

Expand Down