mirror of
https://github.com/serverless/serverless.git
synced 2026-01-25 15:07:39 +00:00
feat(CLI): Modern help output
This commit is contained in:
parent
8c9bd4a6ed
commit
b2df3cc0c8
@ -6,6 +6,7 @@ const serviceCommands = require('./service');
|
||||
const commands = (module.exports = new Map());
|
||||
|
||||
commands.set('deploy', {
|
||||
groupName: 'main',
|
||||
usage: 'Deploy a Serverless service',
|
||||
options: {
|
||||
'conceal': {
|
||||
@ -48,6 +49,7 @@ commands.set('deploy', {
|
||||
});
|
||||
|
||||
commands.set('deploy function', {
|
||||
groupName: 'main',
|
||||
usage: 'Deploy a single function from the service',
|
||||
options: {
|
||||
'function': {
|
||||
@ -78,6 +80,7 @@ commands.set('deploy list functions', {
|
||||
});
|
||||
|
||||
commands.set('info', {
|
||||
groupName: 'main',
|
||||
usage: 'Display information about the service',
|
||||
options: {
|
||||
conceal: {
|
||||
@ -94,6 +97,7 @@ commands.set('info', {
|
||||
});
|
||||
|
||||
commands.set('invoke', {
|
||||
groupName: 'main',
|
||||
usage: 'Invoke a deployed function',
|
||||
options: {
|
||||
function: {
|
||||
@ -137,6 +141,7 @@ commands.set('invoke', {
|
||||
});
|
||||
|
||||
commands.set('invoke local', {
|
||||
groupName: 'main',
|
||||
usage: 'Invoke function locally',
|
||||
options: {
|
||||
'function': {
|
||||
@ -177,6 +182,7 @@ commands.set('invoke local', {
|
||||
});
|
||||
|
||||
commands.set('logs', {
|
||||
groupName: 'main',
|
||||
usage: 'Output the logs of a deployed function',
|
||||
options: {
|
||||
function: {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
const { legacy, writeText } = require('@serverless/utils/log');
|
||||
const resolveInput = require('../resolve-input');
|
||||
const renderOptionsHelp = require('./options');
|
||||
|
||||
@ -9,10 +10,14 @@ module.exports = (commandName) => {
|
||||
const { commandsSchema } = resolveInput();
|
||||
const commandSchema = commandsSchema.get(commandName);
|
||||
|
||||
if (commandSchema) process.stdout.write(`${generateCommandUsage(commandName, commandSchema)}\n`);
|
||||
if (commandSchema) {
|
||||
legacy.write(`${generateCommandUsage(commandName, commandSchema)}\n`);
|
||||
writeText(generateCommandUsage(commandName, commandSchema, { isModern: true }));
|
||||
}
|
||||
for (const [subCommandName, subCommandSchema] of commandsSchema) {
|
||||
if (!subCommandName.startsWith(`${commandName} `)) continue;
|
||||
process.stdout.write(`${generateCommandUsage(subCommandName, subCommandSchema)}\n`);
|
||||
legacy.write(`${generateCommandUsage(subCommandName, subCommandSchema)}\n`);
|
||||
writeText(generateCommandUsage(subCommandName, subCommandSchema, { isModern: true }));
|
||||
}
|
||||
if (commandSchema) renderOptionsHelp(Object.assign({}, commandSchema.options));
|
||||
|
||||
|
||||
@ -1,12 +1,86 @@
|
||||
'use strict';
|
||||
|
||||
const chalk = require('chalk');
|
||||
const { legacy, writeText, style } = require('@serverless/utils/log');
|
||||
const { version } = require('../../../package');
|
||||
const globalOptions = require('../commands-schema/common-options/global');
|
||||
const resolveInput = require('../resolve-input');
|
||||
const generateCommandUsage = require('./generate-command-usage');
|
||||
const renderOptions = require('./options');
|
||||
|
||||
module.exports = (loadedPlugins) => {
|
||||
const { commandsSchema } = resolveInput();
|
||||
|
||||
writeText(
|
||||
`Serverless Framework v${version}`,
|
||||
null,
|
||||
style.aside('Usage'),
|
||||
'serverless <command> <options>',
|
||||
'sls <command> <options>',
|
||||
null,
|
||||
style.aside('Get started'),
|
||||
`Run ${style.error('serverless')} to interactively setup a project.`,
|
||||
'Use --help-interactive to display the interactive setup help.',
|
||||
null,
|
||||
style.aside('Monitoring'),
|
||||
'Enable performance and error monitoring with the Serverless Dashboard.',
|
||||
`Learn more: ${style.link('https://serverless.com/monitoring')}`,
|
||||
null,
|
||||
style.aside('Plugins'),
|
||||
'Extend the Serverless Framework with plugins.',
|
||||
`Explore plugins: ${style.link('https://serverless.com/plugins')}`,
|
||||
null,
|
||||
style.aside('Options')
|
||||
);
|
||||
|
||||
renderOptions(globalOptions, { shouldWriteModernOnly: true });
|
||||
|
||||
const allCommands = new Map(
|
||||
Array.from(commandsSchema).filter(
|
||||
([commandName, { isHidden, lifecycleEvents }]) => commandName && !isHidden && lifecycleEvents
|
||||
)
|
||||
);
|
||||
const mainCommands = new Map(
|
||||
Array.from(allCommands).filter(([, { groupName }]) => groupName === 'main')
|
||||
);
|
||||
|
||||
if (mainCommands.size) {
|
||||
writeText(null, style.aside('Main commands'));
|
||||
for (const [commandName, commandSchema] of mainCommands) {
|
||||
writeText(generateCommandUsage(commandName, commandSchema, { isModern: true }));
|
||||
}
|
||||
writeText(null, style.aside('Other commands'));
|
||||
} else {
|
||||
writeText(null, style.aside('All commands'));
|
||||
}
|
||||
|
||||
const extensionCommandsSchema = new Map();
|
||||
|
||||
for (const [commandName, commandSchema] of allCommands) {
|
||||
if (commandSchema.isExtension) {
|
||||
if (!extensionCommandsSchema.has(commandSchema.sourcePlugin)) {
|
||||
extensionCommandsSchema.set(commandSchema.sourcePlugin, new Map());
|
||||
}
|
||||
extensionCommandsSchema.get(commandSchema.sourcePlugin).set(commandName, commandSchema);
|
||||
continue;
|
||||
}
|
||||
if (commandSchema.groupName === 'main') continue;
|
||||
|
||||
writeText(generateCommandUsage(commandName, commandSchema, { isModern: true }));
|
||||
}
|
||||
|
||||
if (loadedPlugins.size) {
|
||||
if (extensionCommandsSchema.size) {
|
||||
for (const [plugin, pluginCommandsSchema] of extensionCommandsSchema) {
|
||||
writeText(null, style.aside(plugin.constructor.name));
|
||||
for (const [commandName, commandSchema] of pluginCommandsSchema) {
|
||||
writeText(generateCommandUsage(commandName, commandSchema, { isModern: true }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
writeText();
|
||||
|
||||
const lines = [
|
||||
'',
|
||||
chalk.yellow.underline('Commands'),
|
||||
@ -42,19 +116,8 @@ module.exports = (loadedPlugins) => {
|
||||
'',
|
||||
];
|
||||
|
||||
const extensionCommandsSchema = new Map();
|
||||
|
||||
for (const [commandName, commandSchema] of commandsSchema) {
|
||||
if (!commandName) continue;
|
||||
if (commandSchema.isHidden) continue;
|
||||
if (!commandSchema.lifecycleEvents) continue;
|
||||
if (commandSchema.isExtension) {
|
||||
if (!extensionCommandsSchema.has(commandSchema.sourcePlugin)) {
|
||||
extensionCommandsSchema.set(commandSchema.sourcePlugin, new Map());
|
||||
}
|
||||
extensionCommandsSchema.get(commandSchema.sourcePlugin).set(commandName, commandSchema);
|
||||
continue;
|
||||
}
|
||||
for (const [commandName, commandSchema] of allCommands) {
|
||||
if (commandSchema.isExtension) continue;
|
||||
lines.push(generateCommandUsage(commandName, commandSchema));
|
||||
}
|
||||
|
||||
@ -80,5 +143,5 @@ module.exports = (loadedPlugins) => {
|
||||
}
|
||||
}
|
||||
|
||||
process.stdout.write(`${lines.join('\n')}\n`);
|
||||
legacy.write(`${lines.join('\n')}\n`);
|
||||
};
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const chalk = require('chalk');
|
||||
const { style } = require('@serverless/utils/log');
|
||||
|
||||
module.exports = (commandName, commandSchema) => {
|
||||
const dotsLength = 30;
|
||||
module.exports = (commandName, commandSchema, options = {}) => {
|
||||
const indentFillLength = 30;
|
||||
|
||||
const usage = commandSchema.usage;
|
||||
const dots = '.'.repeat(Math.max(dotsLength - commandName.length, 0));
|
||||
if (options.isModern) {
|
||||
return `${commandName} ${' '.repeat(
|
||||
Math.max(indentFillLength - commandName.length, 0)
|
||||
)} ${style.aside(usage)}`;
|
||||
}
|
||||
const dots = '.'.repeat(Math.max(indentFillLength - commandName.length, 0));
|
||||
return `${chalk.yellow(commandName)} ${chalk.dim(dots)} ${usage}`;
|
||||
};
|
||||
|
||||
@ -1,12 +1,20 @@
|
||||
'use strict';
|
||||
|
||||
const chalk = require('chalk');
|
||||
const { legacy, writeText, style } = require('@serverless/utils/log');
|
||||
const commmandSchema = require('../commands-schema/no-service').get('');
|
||||
const renderOptions = require('./options');
|
||||
|
||||
module.exports = () => {
|
||||
process.stdout.write(`${chalk.yellow.underline('Interactive CLI')}\n`);
|
||||
process.stdout.write(
|
||||
writeText(
|
||||
style.aside('Interactive CLI'),
|
||||
`Run ${style.error('serverless')} to interactively setup a project.`,
|
||||
null,
|
||||
style.aside('Options')
|
||||
);
|
||||
|
||||
legacy.write(`${chalk.yellow.underline('Interactive CLI')}\n`);
|
||||
legacy.write(
|
||||
`${chalk.yellow(
|
||||
`Run serverless (or shortcut sls) a subcommand to initialize an interactive setup of
|
||||
functionalities related to given service or current environment`
|
||||
|
||||
@ -1,32 +1,53 @@
|
||||
'use strict';
|
||||
|
||||
const chalk = require('chalk');
|
||||
const { legacy, writeText, style } = require('@serverless/utils/log');
|
||||
|
||||
module.exports = (commandOptions) => {
|
||||
const dotsLength = 40;
|
||||
module.exports = (commandOptions, options = {}) => {
|
||||
const indentFillLength = 40;
|
||||
|
||||
for (const [option, optionsObject] of Object.entries(commandOptions)) {
|
||||
let optionsDots = '.'.repeat(Math.max(dotsLength - option.length, 0));
|
||||
let legacyOptionsIndentFill = '.'.repeat(Math.max(indentFillLength - option.length, 0));
|
||||
let optionsIndentFill = ' '.repeat(Math.max(indentFillLength - option.length - 4, 0));
|
||||
|
||||
if (optionsObject.required) {
|
||||
optionsDots = optionsDots.slice(0, optionsDots.length - 18);
|
||||
legacyOptionsIndentFill = legacyOptionsIndentFill.slice(
|
||||
0,
|
||||
legacyOptionsIndentFill.length - 18
|
||||
);
|
||||
optionsIndentFill = optionsIndentFill.slice(0, optionsIndentFill.length - 18);
|
||||
} else {
|
||||
optionsDots = optionsDots.slice(0, optionsDots.length - 7);
|
||||
legacyOptionsIndentFill = legacyOptionsIndentFill.slice(
|
||||
0,
|
||||
legacyOptionsIndentFill.length - 7
|
||||
);
|
||||
optionsIndentFill = optionsIndentFill.slice(0, optionsIndentFill.length - 7);
|
||||
}
|
||||
if (optionsObject.shortcut) {
|
||||
optionsDots = optionsDots.slice(0, optionsDots.length - 5);
|
||||
legacyOptionsIndentFill = legacyOptionsIndentFill.slice(
|
||||
0,
|
||||
legacyOptionsIndentFill.length - 5
|
||||
);
|
||||
optionsIndentFill = optionsIndentFill.slice(0, optionsIndentFill.length - 5);
|
||||
}
|
||||
|
||||
const optionInfo = ` --${option}`;
|
||||
let shortcutInfo = '';
|
||||
let requiredInfo = '';
|
||||
if (optionsObject.shortcut) shortcutInfo = ` / -${optionsObject.shortcut}`;
|
||||
|
||||
if (optionsObject.required) requiredInfo = ' (required)';
|
||||
|
||||
const optionsUsage = optionsObject.usage ? chalk.dim(optionsDots) + optionsObject.usage : '';
|
||||
const output = `${optionInfo}${shortcutInfo}${requiredInfo} ${optionsUsage}`;
|
||||
if (!options.shouldWriteModernOnly) {
|
||||
const legacyOptionsUsage = optionsObject.usage
|
||||
? chalk.dim(legacyOptionsIndentFill) + optionsObject.usage
|
||||
: '';
|
||||
const legacyOutput = ` --${option}${shortcutInfo}${requiredInfo} ${legacyOptionsUsage}`;
|
||||
legacy.write(`${chalk.yellow(legacyOutput)}\n`);
|
||||
}
|
||||
|
||||
process.stdout.write(`${chalk.yellow(output)}\n`);
|
||||
const optionsUsage = optionsObject.usage
|
||||
? optionsIndentFill + style.aside(optionsObject.usage)
|
||||
: '';
|
||||
writeText(`--${option}${shortcutInfo}${requiredInfo} ${optionsUsage}`);
|
||||
}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user