Merge pull request #2033 from balena-io/post-capitano-refactor

Improve command suggestions, add topic help
This commit is contained in:
bulldozer-balena[bot] 2020-09-10 18:26:29 +00:00 committed by GitHub
commit e65caed64e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 69 additions and 11 deletions

View File

@ -2082,7 +2082,7 @@ Sample registry-secrets YAML file:
password: '{escaped contents of the GCR keyfile.json file}' password: '{escaped contents of the GCR keyfile.json file}'
``` ```
For a sample project using registry secrets with the Google Container Registry, For a sample project using registry secrets with the Google Container Registry,
check: https://github.com/balena-io-playground/sample-gcr-registry-secrets check: https://github.com/balena-io-examples/sample-gcr-registry-secrets
If the --registry-secrets option is not specified, and a secrets.yml or If the --registry-secrets option is not specified, and a secrets.yml or
secrets.json file exists in the balena directory (usually $HOME/.balena), secrets.json file exists in the balena directory (usually $HOME/.balena),
@ -2358,7 +2358,7 @@ Sample registry-secrets YAML file:
password: '{escaped contents of the GCR keyfile.json file}' password: '{escaped contents of the GCR keyfile.json file}'
``` ```
For a sample project using registry secrets with the Google Container Registry, For a sample project using registry secrets with the Google Container Registry,
check: https://github.com/balena-io-playground/sample-gcr-registry-secrets check: https://github.com/balena-io-examples/sample-gcr-registry-secrets
If the --registry-secrets option is not specified, and a secrets.yml or If the --registry-secrets option is not specified, and a secrets.yml or
secrets.json file exists in the balena directory (usually $HOME/.balena), secrets.json file exists in the balena directory (usually $HOME/.balena),
@ -2580,7 +2580,7 @@ Sample registry-secrets YAML file:
password: '{escaped contents of the GCR keyfile.json file}' password: '{escaped contents of the GCR keyfile.json file}'
``` ```
For a sample project using registry secrets with the Google Container Registry, For a sample project using registry secrets with the Google Container Registry,
check: https://github.com/balena-io-playground/sample-gcr-registry-secrets check: https://github.com/balena-io-examples/sample-gcr-registry-secrets
If the --registry-secrets option is not specified, and a secrets.yml or If the --registry-secrets option is not specified, and a secrets.yml or
secrets.json file exists in the balena directory (usually $HOME/.balena), secrets.json file exists in the balena directory (usually $HOME/.balena),

View File

@ -82,7 +82,7 @@ export default class DeviceRmCmd extends Command {
); );
// Remove // Remove
for (const uuid of params.uuid.split(',')) { for (const uuid of uuids) {
try { try {
await balena.models.device.remove(tryAsInteger(uuid)); await balena.models.device.remove(tryAsInteger(uuid));
} catch (err) { } catch (err) {

View File

@ -40,6 +40,27 @@ export default class BalenaHelp extends Help {
return; return;
} }
// If they've typed a topic (e.g. `balena os`) that isn't also a command (e.g. `balena device`)
// then list the associated commands.
const topicCommands = this.config.commands.filter((c) => {
return c.id.startsWith(`${subject}:`);
});
if (topicCommands.length > 0) {
console.log(`${chalk.yellow(subject)} commands include:`);
console.log(this.formatCommands(topicCommands));
console.log(
`\nRun ${chalk.cyan.bold(
'balena help -v',
)} for a list of all available commands,`,
);
console.log(
` or ${chalk.cyan.bold(
'balena help <command>',
)} for detailed help on a specific command.`,
);
return;
}
throw new ExpectedError(`command ${chalk.cyan.bold(subject)} not found`); throw new ExpectedError(`command ${chalk.cyan.bold(subject)} not found`);
} }

View File

@ -22,10 +22,12 @@ import type { IConfig } from '@oclif/config';
A modified version of the command-not-found plugin logic, A modified version of the command-not-found plugin logic,
which deals with spaces separators stead of colons, and which deals with spaces separators stead of colons, and
prints suggested commands instead of prompting interactively. prints suggested commands instead of prompting interactively.
Also see help.ts showHelp() for handling of topics.
*/ */
const hook: Hook<'command-not-found'> = async function ( const hook: Hook<'command-not-found'> = async function (
opts: object & { config: IConfig; id?: string }, opts: object & { config: IConfig; id?: string; argv?: string[] },
) { ) {
const Levenshtein = await import('fast-levenshtein'); const Levenshtein = await import('fast-levenshtein');
const _ = await import('lodash'); const _ = await import('lodash');
@ -44,16 +46,36 @@ const hook: Hook<'command-not-found'> = async function (
return _.minBy(commandIDs, (c) => Levenshtein.get(cmd, c))!; return _.minBy(commandIDs, (c) => Levenshtein.get(cmd, c))!;
} }
const suggestions: string[] = [];
suggestions.push(closest(commandId).replace(':', ' ') || '');
// opts.argv contains everything after the first command word
// if there's something there, also test if it might be a double
// word command spelt wrongly, rather than command args.
if (opts.argv?.[0]) {
suggestions.unshift(
closest(`${commandId}: + ${opts.argv[0]}`).replace(':', ' ') || '',
);
}
// Output suggestions
console.error( console.error(
`${color.yellow(command)} is not a recognized balena command.\n`, `${color.yellow(command)} is not a recognized balena command.\n`,
); );
console.error(`Did you mean: ? `);
const suggestion = closest(commandId).replace(':', ' ') || ''; suggestions.forEach((s) => {
console.log(`Did you mean: ${color.cmd(suggestion)} ? `); console.error(` ${color.cmd(s)}`);
console.log( });
`Run ${color.cmd('balena help -v')} for a list of available commands.`, console.error(
`\nRun ${color.cmd('balena help -v')} for a list of available commands,`,
);
console.error(
` or ${color.cmd(
'balena help <command>',
)} for detailed help on a specific command.`,
); );
// Exit
const COMMAND_NOT_FOUND = 127; const COMMAND_NOT_FOUND = 127;
process.exit(COMMAND_NOT_FOUND); process.exit(COMMAND_NOT_FOUND);
}; };

View File

@ -61,7 +61,7 @@ Sample registry-secrets YAML file:
password: '{escaped contents of the GCR keyfile.json file}' password: '{escaped contents of the GCR keyfile.json file}'
\`\`\` \`\`\`
For a sample project using registry secrets with the Google Container Registry, For a sample project using registry secrets with the Google Container Registry,
check: https://github.com/balena-io-playground/sample-gcr-registry-secrets check: https://github.com/balena-io-examples/sample-gcr-registry-secrets
If the --registry-secrets option is not specified, and a secrets.yml or If the --registry-secrets option is not specified, and a secrets.yml or
secrets.json file exists in the balena directory (usually $HOME/.balena), secrets.json file exists in the balena directory (usually $HOME/.balena),

View File

@ -0,0 +1,15 @@
diff --git a/node_modules/@oclif/config/lib/config.js b/node_modules/@oclif/config/lib/config.js
index aba1da9..830f800 100644
--- a/node_modules/@oclif/config/lib/config.js
+++ b/node_modules/@oclif/config/lib/config.js
@@ -165,7 +165,9 @@ class Config {
debug('runCommand %s %o', id, argv);
const c = this.findCommand(id);
if (!c) {
- await this.runHook('command_not_found', { id });
+ // argv added to command_not_found hook
+ // We should try to upstream this change
+ await this.runHook('command_not_found', { id, argv });
throw new errors_1.CLIError(`command ${id} not found`);
}
const command = c.load();