From a530908573a8ce14b17560c166be97cb2ca3cea9 Mon Sep 17 00:00:00 2001 From: maksimchepelev Date: Fri, 15 Feb 2019 16:50:42 +0300 Subject: [PATCH 1/5] feat(cli): help improvements + refactoring: cli validation moved from app-helper.js to base-cli-handler.js + help for one and help for all parameters functions Closes ENG-556 --- src/cli/base-cli-handler.js | 209 +++++++++++++++++++++++++++++++++++- src/cli/catalog.js | 6 +- src/cli/config.js | 4 +- src/cli/connector.js | 4 +- src/cli/controller.js | 4 +- src/cli/diagnostics.js | 4 +- src/cli/flow.js | 6 +- src/cli/iofog.js | 6 +- src/cli/microservice.js | 6 +- src/cli/registry.js | 4 +- src/cli/tunnel.js | 4 +- src/cli/user.js | 4 +- src/helpers/app-helper.js | 170 ----------------------------- 13 files changed, 233 insertions(+), 198 deletions(-) diff --git a/src/cli/base-cli-handler.js b/src/cli/base-cli-handler.js index 6b6e2c616..713470dcf 100644 --- a/src/cli/base-cli-handler.js +++ b/src/cli/base-cli-handler.js @@ -13,6 +13,9 @@ const commandLineArgs = require('command-line-args'); const commandLineUsage = require('command-line-usage'); +const AppHelper = require('../helpers/app-helper'); +const Errors = require('../helpers/errors'); +const ErrorMessages = require('../helpers/error-messages'); class CLIHandler { constructor() { @@ -29,9 +32,44 @@ class CLIHandler { return commandLineArgs(commandDefinitions, Object.assign({camelCase: true, partial: true,}, options)) } - help(hide = [], showOptions = true, hasCommands = true, additionalSection = []) { + help(show = [], showOptions = true, hasCommands = true, additionalSection = []) { + + if (show.length === 0) { + //show all + this.helpAll(show, showOptions, hasCommands, additionalSection) + } else { + //show list + this.helpSome(show, showOptions) + } + } + + helpSome(show = [], showOptions = true,) { + const options = Object.keys(this.commands) + .filter((key) => show.indexOf(key) !== -1) + .map((key) => ({ + header: key, + optionList: this.commandDefinitions, + group: [key], + })); + + const sections = [ + { + header: 'Usage', + content: `$ iofog-controller ${this.name} ${show.length === 1 ? show : ''} `, + }, + ].concat(showOptions ? options : []); + + const usage = [ + { + header: 'ioFogController', + content: 'Fog Controller project for Eclipse IoFog @ iofog.org \\nCopyright (c) 2018 Edgeworx, Inc.', + } + ].concat(sections); + console.log(commandLineUsage(usage)) + } + + helpAll(show = [], showOptions = true, hasCommands = true, additionalSection = []) { const options = Object.keys(this.commands) - .filter((key) => hide.indexOf(key) === -1) .map((key) => ({ header: key, optionList: this.commandDefinitions, @@ -62,6 +100,173 @@ class CLIHandler { ].concat(sections); console.log(commandLineUsage(usage)) } + + handleCLIError(error) { + switch (error.name) { + case "UNKNOWN_OPTION": + console.log("Invalid argument '" + error.optionName.split('-').join('') + "'"); + break; + case "UNKNOWN_VALUE": + console.log("Invalid value " + error.value); + break; + case "InvalidArgumentError": + console.log(error.message); + break; + case "InvalidArgumentTypeError": + console.log(error.message); + break; + case "ALREADY_SET": + console.log("Parameter '" + error.optionName + "' is used multiple times"); + break; + default: + console.log(JSON.stringify(error)); + break; + } + } + + validateParameters(command, commandDefinitions, args) { + // 1st argument = command + args.shift(); + + const possibleAliasesList = _getPossibleAliasesList(command, commandDefinitions); + const possibleArgsList = _getPossibleArgsList(command, commandDefinitions); + + let expectedValueType; + let currentArgName; + + if (args.length === 0) { + return + } + const argsMap = argsArrayAsMap(args); + + argsMap.forEach((values, key) => { + if (key.startsWith("--")) { // argument + // '--ssl-cert' format -> 'ssl-cert' format + const argument = key.substr(2); + _validateArg(argument, possibleArgsList); + currentArgName = argument; + expectedValueType = _getValType(argument, commandDefinitions); + } else if (key.startsWith("-")) { // alias + // '-q' format -> 'q' format + const alias = key.substr(1); + _validateArg(alias, possibleAliasesList); + currentArgName = alias; + expectedValueType = _getValType(alias, commandDefinitions); + } + + let valType; + if (values.length === 0) { + valType = 'boolean'; + } else if (values.length === 1) { + const firstVal = Number(values[0]); + if (Number.isNaN(firstVal.valueOf())) { + valType = 'string'; + } else if (Number.isInteger(firstVal.valueOf())) { + valType = 'integer'; + } else { + valType = 'float' + } + } + //TODO else validate multiply parameters. Add after multiply parameters will be used in cli api + + let isValidType = true; + if (expectedValueType === 'string' && valType === 'boolean') { + isValidType = false; + } else if ((expectedValueType === 'float' || expectedValueType === 'number') + && (valType !== 'float' && valType !== 'number' && valType !== 'integer')) { + isValidType = false; + } else if (expectedValueType === 'integer' && valType !== 'integer') { + isValidType = false; + } else if (expectedValueType === 'boolean' && valType !== 'boolean') { + isValidType = false; + } + + if (!isValidType) { + throw new Errors.InvalidArgumentTypeError(AppHelper.formatMessage(ErrorMessages.INVALID_CLI_ARGUMENT_TYPE, currentArgName, expectedValueType)); + } + }) + } +} + +function argsArrayAsMap(args) { + let argsVars = args.join(' ').split(/(?= -{1,2}[^-]+)/); + const argsMap = new Map(); + argsVars + .map(pair => pair.trim()) + .map(pair => { + const spaceIndex = pair.indexOf(' '); + let key, values; + if (spaceIndex !== -1) { + key = pair.substr(0, pair.indexOf(' ')); + values = pair.substr(pair.indexOf(' ')+1).split(' '); + argsMap.set(key, values); + } else { + key = pair; + values = []; + } + argsMap.set(key, values); + + }); + return argsMap; +} + +function _validateArg(arg, aliasesList) { + const valid = aliasesList.includes(arg); + if (!valid) { + throw new Errors.InvalidArgumentError("Invalid argument '" + arg + "'"); + } +} + +function _getPossibleAliasesList(command, commandDefinitions) { + const possibleAliasesList = []; + + for (const definition of commandDefinitions) { + const group = definition.group; + const isGroupArray = group.constructor === Array; + if (isGroupArray) { + for (const gr of group) { + if (gr === command) { + possibleAliasesList.push(definition.alias); + break; + } + } + } else { + if (group === command) { + possibleAliasesList.push(definition.alias); + } + } + } + + return possibleAliasesList; +} + +function _getPossibleArgsList(command, commandDefinitions) { + const possibleArgsList = []; + + for (const definition of commandDefinitions) { + const group = definition.group; + const isGroupArray = group.constructor === Array; + if (isGroupArray) { + for (const gr of group) { + if (gr === command) { + possibleArgsList.push(definition.name); + break; + } + } + } else { + if (group === command) { + possibleArgsList.push(definition.name); + } + } + } + + return possibleArgsList; +} + +function _getValType(arg, commandDefinitions) { + const command = commandDefinitions + .filter(def => def.name === arg || def.alias === arg)[0]; + return command.type.name.toLowerCase(); } module.exports = CLIHandler; \ No newline at end of file diff --git a/src/cli/catalog.js b/src/cli/catalog.js index 42c61c72e..013eb3941 100644 --- a/src/cli/catalog.js +++ b/src/cli/catalog.js @@ -158,7 +158,7 @@ class Catalog extends BaseCLIHandler { const command = catalogCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_ADD: @@ -181,12 +181,12 @@ class Catalog extends BaseCLIHandler { return this.help() } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } help() { - super.help([constants.CMD_LIST], true, true, [ + super.help([], true, true, [ { header: 'JSON File Schema', content: [ diff --git a/src/cli/config.js b/src/cli/config.js index 844bc64e5..18917c9b5 100644 --- a/src/cli/config.js +++ b/src/cli/config.js @@ -101,7 +101,7 @@ class Config extends BaseCLIHandler { const command = configCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_ADD: @@ -121,7 +121,7 @@ class Config extends BaseCLIHandler { return this.help([], true, false) } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } } diff --git a/src/cli/connector.js b/src/cli/connector.js index 0839fd3ba..fef0cb588 100644 --- a/src/cli/connector.js +++ b/src/cli/connector.js @@ -84,7 +84,7 @@ class Connector extends BaseCLIHandler { const command = connectorCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_ADD: @@ -104,7 +104,7 @@ class Connector extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } diff --git a/src/cli/controller.js b/src/cli/controller.js index a1dce0e08..412c833a4 100644 --- a/src/cli/controller.js +++ b/src/cli/controller.js @@ -46,7 +46,7 @@ class Controller extends BaseCLIHandler { const command = controllerCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_STATUS: @@ -66,7 +66,7 @@ class Controller extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } diff --git a/src/cli/diagnostics.js b/src/cli/diagnostics.js index fe7eb4bdb..98c39f438 100644 --- a/src/cli/diagnostics.js +++ b/src/cli/diagnostics.js @@ -83,7 +83,7 @@ class Diagnostics extends BaseCLIHandler { const command = diagnosticCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_STRACE_UPDATE: @@ -106,7 +106,7 @@ class Diagnostics extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } } diff --git a/src/cli/flow.js b/src/cli/flow.js index 9f3803181..e79d06575 100644 --- a/src/cli/flow.js +++ b/src/cli/flow.js @@ -87,7 +87,7 @@ class Flow extends BaseCLIHandler { const command = flowCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_ADD: @@ -110,12 +110,12 @@ class Flow extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } help() { - super.help([constants.CMD_LIST], true, true, [ + super.help([], true, true, [ { header: 'JSON File Schema', content: [ diff --git a/src/cli/iofog.js b/src/cli/iofog.js index f02edbddb..014d967fa 100644 --- a/src/cli/iofog.js +++ b/src/cli/iofog.js @@ -215,7 +215,7 @@ class IOFog extends BaseCLIHandler { const command = iofogCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_ADD: @@ -253,12 +253,12 @@ class IOFog extends BaseCLIHandler { return this.help() } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } help() { - super.help([constants.CMD_LIST], true, true, [ + super.help([], true, true, [ { header: 'JSON File Schema', content: [ diff --git a/src/cli/microservice.js b/src/cli/microservice.js index ab21361f3..d81d0283d 100644 --- a/src/cli/microservice.js +++ b/src/cli/microservice.js @@ -186,7 +186,7 @@ class Microservice extends BaseCLIHandler { const command = microserviceCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_ADD: @@ -233,12 +233,12 @@ class Microservice extends BaseCLIHandler { return this.help() } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } help() { - super.help([constants.CMD_LIST], true, true, [ + super.help([], true, true, [ { header: 'JSON ADD File Schema', content: [ diff --git a/src/cli/registry.js b/src/cli/registry.js index 4cfdde316..1b8193db6 100644 --- a/src/cli/registry.js +++ b/src/cli/registry.js @@ -94,7 +94,7 @@ class Registry extends BaseCLIHandler { const command = registryCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_ADD: @@ -114,7 +114,7 @@ class Registry extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } diff --git a/src/cli/tunnel.js b/src/cli/tunnel.js index 79501b189..7785f9c5d 100644 --- a/src/cli/tunnel.js +++ b/src/cli/tunnel.js @@ -81,7 +81,7 @@ class Tunnel extends BaseCLIHandler { const command = tunnelCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_UPDATE: @@ -94,7 +94,7 @@ class Tunnel extends BaseCLIHandler { return this.help([constants.CMD_HELP]) } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } } diff --git a/src/cli/user.js b/src/cli/user.js index ad885d416..cb24cc95b 100644 --- a/src/cli/user.js +++ b/src/cli/user.js @@ -75,7 +75,7 @@ class User extends BaseCLIHandler { const command = userCommand.command.command; - AppHelper.validateParameters(command, this.commandDefinitions, args.argv); + this.validateParameters(command, this.commandDefinitions, args.argv); switch (command) { case constants.CMD_ADD: @@ -104,7 +104,7 @@ class User extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - AppHelper.handleCLIError(error); + this.handleCLIError(error); } } diff --git a/src/helpers/app-helper.js b/src/helpers/app-helper.js index 1a70210f2..9ff6b6924 100644 --- a/src/helpers/app-helper.js +++ b/src/helpers/app-helper.js @@ -160,180 +160,12 @@ function stringifyCliJsonSchema(json) { .replace(/}/g, "\\}"); } -function handleCLIError(error) { - switch (error.name) { - case "UNKNOWN_OPTION": - console.log("Invalid argument '" + error.optionName.split('-').join('') + "'"); - break; - case "UNKNOWN_VALUE": - console.log("Invalid value " + error.value); - break; - case "InvalidArgumentError": - console.log(error.message); - break; - case "InvalidArgumentTypeError": - console.log(error.message); - break; - case "ALREADY_SET": - console.log("Parameter '" + error.optionName + "' is used multiple times"); - break; - default: - console.log(JSON.stringify(error)); - break; - } -} - function trimCertificate(cert) { let result = cert.replace(/(^[\s\S]*-{3,}BEGIN CERTIFICATE-{3,}[\s]*)/, ""); result = result.replace(/([\s]*-{3,}END CERTIFICATE-{3,}[\s\S]*$)/, ""); return result; } -function argsArrayAsMap(args) { - let argsVars = args.join(' ').split(/(?= -{1,2}[^-]+)/); - const argsMap = new Map(); - argsVars - .map(pair => pair.trim()) - .map(pair => { - const spaceIndex = pair.indexOf(' '); - let key, values; - if (spaceIndex !== -1) { - key = pair.substr(0, pair.indexOf(' ')); - values = pair.substr(pair.indexOf(' ')+1).split(' '); - argsMap.set(key, values); - } else { - key = pair; - values = []; - } - argsMap.set(key, values); - - }); - return argsMap; -} - -function validateParameters(command, commandDefinitions, args) { - // 1st argument = command - args.shift(); - - const possibleAliasesList = _getPossibleAliasesList(command, commandDefinitions); - const possibleArgsList = _getPossibleArgsList(command, commandDefinitions); - - let expectedValueType; - let currentArgName; - - if (args.length === 0) { - return - } - const argsMap = argsArrayAsMap(args); - - argsMap.forEach((values, key) => { - if (key.startsWith("--")) { // argument - // '--ssl-cert' format -> 'ssl-cert' format - const argument = key.substr(2); - _validateArg(argument, possibleArgsList); - currentArgName = argument; - expectedValueType = _getValType(argument, commandDefinitions); - } else if (key.startsWith("-")) { // alias - // '-q' format -> 'q' format - const alias = key.substr(1); - _validateArg(alias, possibleAliasesList); - currentArgName = alias; - expectedValueType = _getValType(alias, commandDefinitions); - } - - let valType; - if (values.length === 0) { - valType = 'boolean'; - } else if (values.length === 1) { - const firstVal = Number(values[0]); - if (Number.isNaN(firstVal.valueOf())) { - valType = 'string'; - } else if (Number.isInteger(firstVal.valueOf())) { - valType = 'integer'; - } else { - valType = 'float' - } - } - //TODO else validate multiply parameters. Add after multiply parameters will be used in cli api - - let isValidType = true; - if (expectedValueType === 'string' && valType === 'boolean') { - isValidType = false; - } else if ((expectedValueType === 'float' || expectedValueType === 'number') - && (valType !== 'float' && valType !== 'number' && valType !== 'integer')) { - isValidType = false; - } else if (expectedValueType === 'integer' && valType !== 'integer') { - isValidType = false; - } else if (expectedValueType === 'boolean' && valType !== 'boolean') { - isValidType = false; - } - - if (!isValidType) { - throw new Errors.InvalidArgumentTypeError(formatMessage(ErrorMessages.INVALID_CLI_ARGUMENT_TYPE, currentArgName, expectedValueType)); - } - }) -} - -function _validateArg(arg, aliasesList) { - const valid = aliasesList.includes(arg); - if (!valid) { - throw new Errors.InvalidArgumentError("Invalid argument '" + arg + "'"); - } -} - - -function _getPossibleAliasesList(command, commandDefinitions) { - const possibleAliasesList = []; - - for (const definition of commandDefinitions) { - const group = definition.group; - const isGroupArray = group.constructor === Array; - if (isGroupArray) { - for (const gr of group) { - if (gr === command) { - possibleAliasesList.push(definition.alias); - break; - } - } - } else { - if (group === command) { - possibleAliasesList.push(definition.alias); - } - } - } - - return possibleAliasesList; -} - -function _getPossibleArgsList(command, commandDefinitions) { - const possibleArgsList = []; - - for (const definition of commandDefinitions) { - const group = definition.group; - const isGroupArray = group.constructor === Array; - if (isGroupArray) { - for (const gr of group) { - if (gr === command) { - possibleArgsList.push(definition.name); - break; - } - } - } else { - if (group === command) { - possibleArgsList.push(definition.name); - } - } - } - - return possibleArgsList; -} - -function _getValType(arg, commandDefinitions) { - const command = commandDefinitions - .filter(def => def.name === arg || def.alias === arg)[0]; - return command.type.name.toLowerCase(); -} - function isTest() { return process.env.NODE_ENV === 'test' } @@ -369,9 +201,7 @@ module.exports = { findAvailablePort, stringifyCliJsonSchema, isValidPublicIP, - handleCLIError, trimCertificate, - validateParameters, isTest, isEmpty, isOnline From 71efb9ac3e0a454e18a3a1277d4628183b04698b Mon Sep 17 00:00:00 2001 From: maksimchepelev Date: Fri, 15 Feb 2019 17:32:18 +0300 Subject: [PATCH 2/5] feat(cli): help improvements + help output for `category command` and `category command help` Closes ENG-556 --- src/cli/base-cli-handler.js | 19 ++++++++++++++++--- src/cli/catalog.js | 2 +- src/cli/config.js | 2 +- src/cli/connector.js | 2 +- src/cli/controller.js | 2 +- src/cli/diagnostics.js | 2 +- src/cli/flow.js | 2 +- src/cli/iofog.js | 2 +- src/cli/microservice.js | 2 +- src/cli/registry.js | 2 +- src/cli/tunnel.js | 2 +- src/cli/user.js | 2 +- src/helpers/errors.js | 12 ++++++++++-- 13 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/cli/base-cli-handler.js b/src/cli/base-cli-handler.js index 713470dcf..941d59b72 100644 --- a/src/cli/base-cli-handler.js +++ b/src/cli/base-cli-handler.js @@ -16,6 +16,7 @@ const commandLineUsage = require('command-line-usage'); const AppHelper = require('../helpers/app-helper'); const Errors = require('../helpers/errors'); const ErrorMessages = require('../helpers/error-messages'); +const constants = require('../helpers/constants'); class CLIHandler { constructor() { @@ -101,12 +102,15 @@ class CLIHandler { console.log(commandLineUsage(usage)) } - handleCLIError(error) { + handleCLIError(error, args) { switch (error.name) { case "UNKNOWN_OPTION": console.log("Invalid argument '" + error.optionName.split('-').join('') + "'"); break; case "UNKNOWN_VALUE": + if (this.commands[args[0]] && args[1] === 'help') { + return this.helpSome([args[0]]); + } console.log("Invalid value " + error.value); break; case "InvalidArgumentError": @@ -118,14 +122,23 @@ class CLIHandler { case "ALREADY_SET": console.log("Parameter '" + error.optionName + "' is used multiple times"); break; + case 'CliAgrsNotProvidedError': + if (this.commands[args[0]]) { + return this.helpSome([args[0]]); + } + break; default: console.log(JSON.stringify(error)); break; } } - validateParameters(command, commandDefinitions, args) { + validateParameters(command, commandDefinitions, pArgs) { // 1st argument = command + let args = pArgs.slice(); + if (args[0] === constants.CMD_HELP || args[0] === constants.CMD_LIST) { + return + } args.shift(); const possibleAliasesList = _getPossibleAliasesList(command, commandDefinitions); @@ -135,7 +148,7 @@ class CLIHandler { let currentArgName; if (args.length === 0) { - return + throw new Errors.CliAgrsNotProvidedError(); } const argsMap = argsArrayAsMap(args); diff --git a/src/cli/catalog.js b/src/cli/catalog.js index 013eb3941..60014a779 100644 --- a/src/cli/catalog.js +++ b/src/cli/catalog.js @@ -181,7 +181,7 @@ class Catalog extends BaseCLIHandler { return this.help() } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } diff --git a/src/cli/config.js b/src/cli/config.js index 18917c9b5..f347d2de9 100644 --- a/src/cli/config.js +++ b/src/cli/config.js @@ -121,7 +121,7 @@ class Config extends BaseCLIHandler { return this.help([], true, false) } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } } diff --git a/src/cli/connector.js b/src/cli/connector.js index fef0cb588..d7b75c2da 100644 --- a/src/cli/connector.js +++ b/src/cli/connector.js @@ -104,7 +104,7 @@ class Connector extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } diff --git a/src/cli/controller.js b/src/cli/controller.js index 412c833a4..7cefaf655 100644 --- a/src/cli/controller.js +++ b/src/cli/controller.js @@ -66,7 +66,7 @@ class Controller extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } diff --git a/src/cli/diagnostics.js b/src/cli/diagnostics.js index 98c39f438..902a25e34 100644 --- a/src/cli/diagnostics.js +++ b/src/cli/diagnostics.js @@ -106,7 +106,7 @@ class Diagnostics extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } } diff --git a/src/cli/flow.js b/src/cli/flow.js index e79d06575..ae169a8e6 100644 --- a/src/cli/flow.js +++ b/src/cli/flow.js @@ -110,7 +110,7 @@ class Flow extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } diff --git a/src/cli/iofog.js b/src/cli/iofog.js index 014d967fa..efbdba472 100644 --- a/src/cli/iofog.js +++ b/src/cli/iofog.js @@ -253,7 +253,7 @@ class IOFog extends BaseCLIHandler { return this.help() } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } diff --git a/src/cli/microservice.js b/src/cli/microservice.js index d81d0283d..7169a6e00 100644 --- a/src/cli/microservice.js +++ b/src/cli/microservice.js @@ -233,7 +233,7 @@ class Microservice extends BaseCLIHandler { return this.help() } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } diff --git a/src/cli/registry.js b/src/cli/registry.js index 1b8193db6..10208ab38 100644 --- a/src/cli/registry.js +++ b/src/cli/registry.js @@ -114,7 +114,7 @@ class Registry extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } diff --git a/src/cli/tunnel.js b/src/cli/tunnel.js index 7785f9c5d..f2c0d397a 100644 --- a/src/cli/tunnel.js +++ b/src/cli/tunnel.js @@ -94,7 +94,7 @@ class Tunnel extends BaseCLIHandler { return this.help([constants.CMD_HELP]) } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } } diff --git a/src/cli/user.js b/src/cli/user.js index cb24cc95b..a45a0acd2 100644 --- a/src/cli/user.js +++ b/src/cli/user.js @@ -104,7 +104,7 @@ class User extends BaseCLIHandler { return this.help([constants.CMD_LIST]) } } catch (error) { - this.handleCLIError(error); + this.handleCLIError(error, args.argv); } } diff --git a/src/helpers/errors.js b/src/helpers/errors.js index 1fc6b7cac..542df6fbc 100644 --- a/src/helpers/errors.js +++ b/src/helpers/errors.js @@ -103,6 +103,14 @@ class InvalidArgumentTypeError extends Error { } } +class CliAgrsNotProvidedError extends Error { + constructor() { + super('Empty args'); + this.message = 'Empty args'; + this.name = 'CliAgrsNotProvidedError'; + } +} + module.exports = { AuthenticationError: AuthenticationError, TransactionError: TransactionError, @@ -114,6 +122,6 @@ module.exports = { FtpError: FtpError, EmailActivationSetupError: EmailActivationSetupError, InvalidArgumentError: InvalidArgumentError, - InvalidArgumentTypeError: InvalidArgumentTypeError - + InvalidArgumentTypeError: InvalidArgumentTypeError, + CliAgrsNotProvidedError: CliAgrsNotProvidedError }; \ No newline at end of file From a9c64eb951a691f2278040013ef00642e4e277d2 Mon Sep 17 00:00:00 2001 From: maksimchepelev Date: Fri, 15 Feb 2019 17:34:07 +0300 Subject: [PATCH 3/5] feat(cli): help improvements + fix test Closes ENG-556 --- test/src/helpers/app-helpers.test.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/test/src/helpers/app-helpers.test.js b/test/src/helpers/app-helpers.test.js index 96a349a20..0a14acf05 100644 --- a/test/src/helpers/app-helpers.test.js +++ b/test/src/helpers/app-helpers.test.js @@ -354,25 +354,6 @@ describe('App Helpers', () => { }); - describe('.handleCLIError()', () => { - def('error', () => ({ - id: 15, - name: 'UNKNOWN_OPTION', - optionName: 'testOption', - value: 'testValue', - message: 'Test error occurred' - })); - def('errorMessage', () => "Unknown parameter " + $error.optionName); - def('subject', () => $subject.handleCLIError($error)); - - context('when error received', () => { - it('displays error message', () => { - expect($subject).to.be.equal(undefined); - }) - }); - - }); - describe('.trimCertificate()', () => { def('certificate', () => '-----BEGIN CERTIFICATE-----\n' + 'testttt' + From 5938a6a404060a83ab0de67ceafbef5ebe1c6725 Mon Sep 17 00:00:00 2001 From: maksimchepelev Date: Fri, 15 Feb 2019 17:50:11 +0300 Subject: [PATCH 4/5] feat(cli): help improvements + fix bug with commands that haven't args Closes ENG-556 --- src/cli/base-cli-handler.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/cli/base-cli-handler.js b/src/cli/base-cli-handler.js index 941d59b72..1b6c9e490 100644 --- a/src/cli/base-cli-handler.js +++ b/src/cli/base-cli-handler.js @@ -136,13 +136,13 @@ class CLIHandler { validateParameters(command, commandDefinitions, pArgs) { // 1st argument = command let args = pArgs.slice(); - if (args[0] === constants.CMD_HELP || args[0] === constants.CMD_LIST) { - return - } args.shift(); const possibleAliasesList = _getPossibleAliasesList(command, commandDefinitions); const possibleArgsList = _getPossibleArgsList(command, commandDefinitions); + if (possibleAliasesList.length === 0 && possibleArgsList.length === 0) { + return + } let expectedValueType; let currentArgName; From 948ae8497a347548b020d0376242e1bfb383322a Mon Sep 17 00:00:00 2001 From: maksimchepelev Date: Mon, 18 Feb 2019 14:18:51 +0300 Subject: [PATCH 5/5] feat(cli): help improvements + fix comments (refactoring) Closes ENG-556 --- src/cli/base-cli-handler.js | 62 +++++++++++++++++++++---------------- src/helpers/errors.js | 6 ++-- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/src/cli/base-cli-handler.js b/src/cli/base-cli-handler.js index 1b6c9e490..45cabca57 100644 --- a/src/cli/base-cli-handler.js +++ b/src/cli/base-cli-handler.js @@ -122,7 +122,7 @@ class CLIHandler { case "ALREADY_SET": console.log("Parameter '" + error.optionName + "' is used multiple times"); break; - case 'CliAgrsNotProvidedError': + case 'CLIArgsNotProvidedError': if (this.commands[args[0]]) { return this.helpSome([args[0]]); } @@ -148,7 +148,7 @@ class CLIHandler { let currentArgName; if (args.length === 0) { - throw new Errors.CliAgrsNotProvidedError(); + throw new Errors.CLIArgsNotProvidedError(); } const argsMap = argsArrayAsMap(args); @@ -167,32 +167,10 @@ class CLIHandler { expectedValueType = _getValType(alias, commandDefinitions); } - let valType; - if (values.length === 0) { - valType = 'boolean'; - } else if (values.length === 1) { - const firstVal = Number(values[0]); - if (Number.isNaN(firstVal.valueOf())) { - valType = 'string'; - } else if (Number.isInteger(firstVal.valueOf())) { - valType = 'integer'; - } else { - valType = 'float' - } - } + const valType = _getCurrentValType(values); //TODO else validate multiply parameters. Add after multiply parameters will be used in cli api - let isValidType = true; - if (expectedValueType === 'string' && valType === 'boolean') { - isValidType = false; - } else if ((expectedValueType === 'float' || expectedValueType === 'number') - && (valType !== 'float' && valType !== 'number' && valType !== 'integer')) { - isValidType = false; - } else if (expectedValueType === 'integer' && valType !== 'integer') { - isValidType = false; - } else if (expectedValueType === 'boolean' && valType !== 'boolean') { - isValidType = false; - } + let isValidType = _validateType(expectedValueType, valType); if (!isValidType) { throw new Errors.InvalidArgumentTypeError(AppHelper.formatMessage(ErrorMessages.INVALID_CLI_ARGUMENT_TYPE, currentArgName, expectedValueType)); @@ -282,4 +260,36 @@ function _getValType(arg, commandDefinitions) { return command.type.name.toLowerCase(); } +function _getCurrentValType(values) { + let valType; + if (values.length === 0) { + valType = 'boolean'; + } else if (values.length === 1) { + const firstVal = Number(values[0]); + if (Number.isNaN(firstVal.valueOf())) { + valType = 'string'; + } else if (Number.isInteger(firstVal.valueOf())) { + valType = 'integer'; + } else { + valType = 'float' + } + } + return valType; +} + +function _validateType(expectedValueType, valType) { + let isValidType = true; + if (expectedValueType === 'string' && valType === 'boolean') { + isValidType = false; + } else if ((expectedValueType === 'float' || expectedValueType === 'number') + && (valType !== 'float' && valType !== 'number' && valType !== 'integer')) { + isValidType = false; + } else if (expectedValueType === 'integer' && valType !== 'integer') { + isValidType = false; + } else if (expectedValueType === 'boolean' && valType !== 'boolean') { + isValidType = false; + } + return isValidType; +} + module.exports = CLIHandler; \ No newline at end of file diff --git a/src/helpers/errors.js b/src/helpers/errors.js index 542df6fbc..9a0aa9980 100644 --- a/src/helpers/errors.js +++ b/src/helpers/errors.js @@ -103,11 +103,11 @@ class InvalidArgumentTypeError extends Error { } } -class CliAgrsNotProvidedError extends Error { +class CLIArgsNotProvidedError extends Error { constructor() { super('Empty args'); this.message = 'Empty args'; - this.name = 'CliAgrsNotProvidedError'; + this.name = 'CLIArgsNotProvidedError'; } } @@ -123,5 +123,5 @@ module.exports = { EmailActivationSetupError: EmailActivationSetupError, InvalidArgumentError: InvalidArgumentError, InvalidArgumentTypeError: InvalidArgumentTypeError, - CliAgrsNotProvidedError: CliAgrsNotProvidedError + CLIArgsNotProvidedError: CLIArgsNotProvidedError }; \ No newline at end of file