From de5c9a43400a22085865bbc94fc103b404c89eda Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 1 Oct 2024 12:18:43 +0300 Subject: [PATCH] Create command abstraction and split up command builder Added command and flag definition structures to separate building the command metadata and actually rendering the CLI commands. Moved all the interaction with the cli/v2 module in the cli.go source file which simplifies the interactive with the module and abstracts the details away. The change also moves out some parts from the command_builder which grew in complexity. --- commandline/autocomplete_handler.go | 43 +- commandline/cli.go | 135 +++++- commandline/command_builder.go | 625 ++++++++++------------------ commandline/command_definition.go | 62 +++ commandline/flag_builder.go | 140 ++++++- commandline/flag_definition.go | 47 +++ commandline/flag_type.go | 27 ++ commandline/help_templates.go | 19 + commandline/show_command_handler.go | 38 +- 9 files changed, 648 insertions(+), 488 deletions(-) create mode 100644 commandline/command_definition.go create mode 100644 commandline/flag_definition.go create mode 100644 commandline/flag_type.go create mode 100644 commandline/help_templates.go diff --git a/commandline/autocomplete_handler.go b/commandline/autocomplete_handler.go index 953971b..7327102 100644 --- a/commandline/autocomplete_handler.go +++ b/commandline/autocomplete_handler.go @@ -6,16 +6,14 @@ import ( "os" "path/filepath" "strings" - - "github.com/urfave/cli/v2" ) +const AutocompletePowershell = "powershell" +const AutocompleteBash = "bash" + const directoryPermissions = 0755 const filePermissions = 0644 -const Powershell = "powershell" -const Bash = "bash" - const completeHandlerEnabledCheck = "uipath_auto_complete" const powershellCompleteHandler = ` @@ -55,8 +53,8 @@ type autoCompleteHandler struct { } func (a autoCompleteHandler) EnableCompleter(shell string, filePath string) (string, error) { - if shell != Powershell && shell != Bash { - return "", fmt.Errorf("Invalid shell, supported values: %s, %s", Powershell, Bash) + if shell != AutocompletePowershell && shell != AutocompleteBash { + return "", fmt.Errorf("Invalid shell, supported values: %s, %s", AutocompletePowershell, AutocompleteBash) } profileFilePath, err := a.profileFilePath(shell, filePath) @@ -71,14 +69,14 @@ func (a autoCompleteHandler) profileFilePath(shell string, filePath string) (str if filePath != "" { return filePath, nil } - if shell == Powershell { + if shell == AutocompletePowershell { return PowershellProfilePath() } return BashrcPath() } func (a autoCompleteHandler) completeHandler(shell string) string { - if shell == Powershell { + if shell == AutocompletePowershell { return powershellCompleteHandler } return bashCompleteHandler @@ -136,17 +134,12 @@ func (a autoCompleteHandler) writeCompleterHandler(filePath string, completerHan return nil } -func (a autoCompleteHandler) Find(commandText string, commands []*cli.Command, exclude []string) []string { +func (a autoCompleteHandler) Find(commandText string, command *CommandDefinition, exclude []string) []string { words := strings.Split(commandText, " ") if len(words) < 2 { return []string{} } - command := &cli.Command{ - Name: "uipath", - Subcommands: commands, - } - for _, word := range words[1 : len(words)-1] { if strings.HasPrefix(word, "-") { break @@ -164,7 +157,7 @@ func (a autoCompleteHandler) Find(commandText string, commands []*cli.Command, e return a.searchCommands(lastWord, command.Subcommands, exclude) } -func (a autoCompleteHandler) findCommand(name string, commands []*cli.Command) *cli.Command { +func (a autoCompleteHandler) findCommand(name string, commands []*CommandDefinition) *CommandDefinition { for _, command := range commands { if command.Name == name { return command @@ -173,7 +166,7 @@ func (a autoCompleteHandler) findCommand(name string, commands []*cli.Command) * return nil } -func (a autoCompleteHandler) searchCommands(word string, commands []*cli.Command, exclude []string) []string { +func (a autoCompleteHandler) searchCommands(word string, commands []*CommandDefinition, exclude []string) []string { result := []string{} for _, command := range commands { if strings.HasPrefix(command.Name, word) { @@ -188,22 +181,16 @@ func (a autoCompleteHandler) searchCommands(word string, commands []*cli.Command return a.removeDuplicates(a.removeExcluded(result, exclude)) } -func (a autoCompleteHandler) searchFlags(word string, command *cli.Command, exclude []string) []string { +func (a autoCompleteHandler) searchFlags(word string, command *CommandDefinition, exclude []string) []string { result := []string{} for _, flag := range command.Flags { - flagNames := flag.Names() - for _, flagName := range flagNames { - if strings.HasPrefix(flagName, word) { - result = append(result, "--"+flagName) - } + if strings.HasPrefix(flag.Name, word) { + result = append(result, "--"+flag.Name) } } for _, flag := range command.Flags { - flagNames := flag.Names() - for _, flagName := range flagNames { - if strings.Contains(flagName, word) { - result = append(result, "--"+flagName) - } + if strings.Contains(flag.Name, word) { + result = append(result, "--"+flag.Name) } } return a.removeDuplicates(a.removeExcluded(result, exclude)) diff --git a/commandline/cli.go b/commandline/cli.go index 018d45b..01878cd 100644 --- a/commandline/cli.go +++ b/commandline/cli.go @@ -40,7 +40,11 @@ func (c Cli) run(args []string, input utils.Stream) error { PluginExecutor: c.pluginExecutor, DefinitionProvider: c.definitionProvider, } - flags := CommandBuilder.CreateDefaultFlags(false) + + flags := NewFlagBuilder(). + AddDefaultFlags(false). + Build() + commands, err := CommandBuilder.Create(args) if err != nil { return err @@ -51,8 +55,8 @@ func (c Cli) run(args []string, input utils.Stream) error { Usage: "Command-Line Interface for UiPath Services", UsageText: "uipath --parameter", Version: "1.0", - Flags: flags, - Commands: commands, + Flags: c.convertFlags(flags...), + Commands: c.convertCommands(commands...), Writer: c.stdOut, ErrWriter: c.stdErr, HideVersion: true, @@ -89,3 +93,128 @@ func NewCli( ) *Cli { return &Cli{stdIn, stdOut, stdErr, colors, definitionProvider, configProvider, executor, pluginExecutor} } + +func (c Cli) convertCommand(command *CommandDefinition) *cli.Command { + result := cli.Command{ + Name: command.Name, + Usage: command.Summary, + Description: command.Description, + Flags: c.convertFlags(command.Flags...), + Subcommands: c.convertCommands(command.Subcommands...), + CustomHelpTemplate: command.HelpTemplate, + Hidden: command.Hidden, + HideHelp: true, + } + if command.Action != nil { + result.Action = func(context *cli.Context) error { + return command.Action(&CommandExecContext{context}) + } + } + return &result +} + +func (c Cli) convertCommands(commands ...*CommandDefinition) []*cli.Command { + result := []*cli.Command{} + for _, command := range commands { + result = append(result, c.convertCommand(command)) + } + return result +} + +func (c Cli) convertStringSliceFlag(flag *FlagDefinition) *cli.StringSliceFlag { + envVars := []string{} + if flag.EnvVarName != "" { + envVars = append(envVars, flag.EnvVarName) + } + var value *cli.StringSlice + if flag.DefaultValue != nil { + value = cli.NewStringSlice(flag.DefaultValue.([]string)...) + } + return &cli.StringSliceFlag{ + Name: flag.Name, + Usage: flag.Summary, + EnvVars: envVars, + Required: flag.Required, + Hidden: flag.Hidden, + Value: value, + } +} + +func (c Cli) convertIntFlag(flag *FlagDefinition) *cli.IntFlag { + envVars := []string{} + if flag.EnvVarName != "" { + envVars = append(envVars, flag.EnvVarName) + } + var value int + if flag.DefaultValue != nil { + value = flag.DefaultValue.(int) + } + return &cli.IntFlag{ + Name: flag.Name, + Usage: flag.Summary, + EnvVars: envVars, + Required: flag.Required, + Hidden: flag.Hidden, + Value: value, + } +} + +func (c Cli) convertBoolFlag(flag *FlagDefinition) *cli.BoolFlag { + envVars := []string{} + if flag.EnvVarName != "" { + envVars = append(envVars, flag.EnvVarName) + } + var value bool + if flag.DefaultValue != nil { + value = flag.DefaultValue.(bool) + } + return &cli.BoolFlag{ + Name: flag.Name, + Usage: flag.Summary, + EnvVars: envVars, + Required: flag.Required, + Hidden: flag.Hidden, + Value: value, + } +} + +func (c Cli) convertStringFlag(flag *FlagDefinition) *cli.StringFlag { + envVars := []string{} + if flag.EnvVarName != "" { + envVars = append(envVars, flag.EnvVarName) + } + var value string + if flag.DefaultValue != nil { + value = flag.DefaultValue.(string) + } + return &cli.StringFlag{ + Name: flag.Name, + Usage: flag.Summary, + EnvVars: envVars, + Required: flag.Required, + Hidden: flag.Hidden, + Value: value, + } +} + +func (c Cli) convertFlag(flag *FlagDefinition) cli.Flag { + switch flag.Type { + case FlagTypeStringArray: + return c.convertStringSliceFlag(flag) + case FlagTypeInteger: + return c.convertIntFlag(flag) + case FlagTypeBoolean: + return c.convertBoolFlag(flag) + case FlagTypeString: + return c.convertStringFlag(flag) + } + panic(fmt.Sprintf("Unknown flag type: %s", flag.Type.String())) +} + +func (c Cli) convertFlags(flags ...*FlagDefinition) []cli.Flag { + result := []cli.Flag{} + for _, flag := range flags { + result = append(result, c.convertFlag(flag)) + } + return result +} diff --git a/commandline/command_builder.go b/commandline/command_builder.go index 9bbd149..8ab903b 100644 --- a/commandline/command_builder.go +++ b/commandline/command_builder.go @@ -17,64 +17,8 @@ import ( "github.com/UiPath/uipathcli/output" "github.com/UiPath/uipathcli/parser" "github.com/UiPath/uipathcli/utils" - "github.com/urfave/cli/v2" ) -const FromStdIn = "-" - -const insecureFlagName = "insecure" -const debugFlagName = "debug" -const profileFlagName = "profile" -const uriFlagName = "uri" -const identityUriFlagName = "identity-uri" -const organizationFlagName = "organization" -const tenantFlagName = "tenant" -const helpFlagName = "help" -const outputFormatFlagName = "output" -const queryFlagName = "query" -const waitFlagName = "wait" -const waitTimeoutFlagName = "wait-timeout" -const versionFlagName = "version" -const fileFlagName = "file" - -var predefinedFlags = []string{ - insecureFlagName, - debugFlagName, - profileFlagName, - uriFlagName, - identityUriFlagName, - organizationFlagName, - tenantFlagName, - helpFlagName, - outputFormatFlagName, - queryFlagName, - waitFlagName, - waitTimeoutFlagName, - versionFlagName, - fileFlagName, -} - -const outputFormatJson = "json" -const outputFormatText = "text" - -const subcommandHelpTemplate = `NAME: - {{template "helpNameTemplate" .}} - -USAGE: - {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}}{{if .ArgsUsage}}{{.ArgsUsage}}{{else}} [arguments...]{{end}}{{end}}{{if .Description}} - -DESCRIPTION: - {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}} - -COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategories}} - -OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}} - -OPTIONS:{{range $i, $e := .VisibleFlags}} - --{{$e.Name}} {{wrap $e.Usage 6}} -{{end}}{{end}} -` - // The CommandBuilder is creating all available operations and arguments for the CLI. type CommandBuilder struct { Input utils.Stream @@ -87,29 +31,29 @@ type CommandBuilder struct { DefinitionProvider DefinitionProvider } -func (b CommandBuilder) sort(commands []*cli.Command) { +func (b CommandBuilder) sort(commands []*CommandDefinition) { sort.Slice(commands, func(i, j int) bool { return commands[i].Name < commands[j].Name }) } -func (b CommandBuilder) fileInput(context *cli.Context, parameters []parser.Parameter) utils.Stream { - value := context.String(fileFlagName) +func (b CommandBuilder) fileInput(context *CommandExecContext, parameters []parser.Parameter) utils.Stream { + value := context.String(FlagNameFile) if value == "" { return nil } - if value == FromStdIn { + if value == FlagValueFromStdIn { return b.Input } for _, param := range parameters { - if strings.EqualFold(param.FieldName, fileFlagName) { + if strings.EqualFold(param.FieldName, FlagNameFile) { return nil } } return utils.NewFileStream(value) } -func (b CommandBuilder) createExecutionParameters(context *cli.Context, config *config.Config, operation parser.Operation) (executor.ExecutionParameters, error) { +func (b CommandBuilder) createExecutionParameters(context *CommandExecContext, config *config.Config, operation parser.Operation) (executor.ExecutionParameters, error) { typeConverter := newTypeConverter() parameters := []executor.ExecutionParameter{} @@ -163,23 +107,16 @@ func (b CommandBuilder) formatAllowedValues(values []interface{}) string { return result } -func (b CommandBuilder) createFlags(parameters []parser.Parameter) []cli.Flag { - flags := []cli.Flag{} +func (b CommandBuilder) createFlags(parameters []parser.Parameter) []*FlagDefinition { + flags := []*FlagDefinition{} for _, parameter := range parameters { formatter := newParameterFormatter(parameter) + flagType := FlagTypeString if parameter.IsArray() { - flag := cli.StringSliceFlag{ - Name: parameter.Name, - Usage: formatter.Description(), - } - flags = append(flags, &flag) - } else { - flag := cli.StringFlag{ - Name: parameter.Name, - Usage: formatter.Description(), - } - flags = append(flags, &flag) + flagType = FlagTypeStringArray } + flag := NewFlag(parameter.Name, formatter.Description(), flagType) + flags = append(flags, flag) } return flags } @@ -196,21 +133,21 @@ func (b CommandBuilder) sortParameters(parameters []parser.Parameter) { }) } -func (b CommandBuilder) outputFormat(config config.Config, context *cli.Context) (string, error) { - outputFormat := context.String(outputFormatFlagName) +func (b CommandBuilder) outputFormat(config config.Config, context *CommandExecContext) (string, error) { + outputFormat := context.String(FlagNameOutputFormat) if outputFormat == "" { outputFormat = config.Output } if outputFormat == "" { - outputFormat = outputFormatJson + outputFormat = FlagValueOutputFormatJson } - if outputFormat != outputFormatJson && outputFormat != outputFormatText { - return "", fmt.Errorf("Invalid output format '%s', allowed values: %s, %s", outputFormat, outputFormatJson, outputFormatText) + if outputFormat != FlagValueOutputFormatJson && outputFormat != FlagValueOutputFormatText { + return "", fmt.Errorf("Invalid output format '%s', allowed values: %s, %s", outputFormat, FlagValueOutputFormatJson, FlagValueOutputFormatText) } return outputFormat, nil } -func (b CommandBuilder) createBaseUri(operation parser.Operation, config config.Config, context *cli.Context) (url.URL, error) { +func (b CommandBuilder) createBaseUri(operation parser.Operation, config config.Config, context *CommandExecContext) (url.URL, error) { uriArgument, err := b.parseUriArgument(context) if err != nil { return operation.BaseUri, err @@ -222,12 +159,12 @@ func (b CommandBuilder) createBaseUri(operation parser.Operation, config config. return builder.Uri(), nil } -func (b CommandBuilder) createIdentityUri(context *cli.Context, config config.Config, baseUri url.URL) (*url.URL, error) { - uri := context.String(identityUriFlagName) +func (b CommandBuilder) createIdentityUri(context *CommandExecContext, config config.Config, baseUri url.URL) (*url.URL, error) { + uri := context.String(FlagNameIdentityUri) if uri != "" { identityUri, err := url.Parse(uri) if err != nil { - return nil, fmt.Errorf("Error parsing %s argument: %w", identityUriFlagName, err) + return nil, fmt.Errorf("Error parsing %s argument: %w", FlagNameIdentityUri, err) } return identityUri, nil } @@ -248,19 +185,19 @@ func (b CommandBuilder) createIdentityUri(context *cli.Context, config config.Co return identityUri, nil } -func (b CommandBuilder) parseUriArgument(context *cli.Context) (*url.URL, error) { - uriFlag := context.String(uriFlagName) +func (b CommandBuilder) parseUriArgument(context *CommandExecContext) (*url.URL, error) { + uriFlag := context.String(FlagNameUri) if uriFlag == "" { return nil, nil } uriArgument, err := url.Parse(uriFlag) if err != nil { - return nil, fmt.Errorf("Error parsing %s argument: %w", uriFlagName, err) + return nil, fmt.Errorf("Error parsing %s argument: %w", FlagNameUri, err) } return uriArgument, nil } -func (b CommandBuilder) getValue(parameter parser.Parameter, context *cli.Context, config config.Config) string { +func (b CommandBuilder) getValue(parameter parser.Parameter, context *CommandExecContext, config config.Config) string { value := context.String(parameter.Name) if value != "" { return value @@ -279,7 +216,7 @@ func (b CommandBuilder) getValue(parameter parser.Parameter, context *cli.Contex return "" } -func (b CommandBuilder) validateArguments(context *cli.Context, parameters []parser.Parameter, config config.Config) error { +func (b CommandBuilder) validateArguments(context *CommandExecContext, parameters []parser.Parameter, config config.Config) error { err := errors.New("Invalid arguments:") result := true for _, parameter := range parameters { @@ -321,7 +258,7 @@ func (b CommandBuilder) outputWriter(writer io.Writer, format string, query stri if query != "" { transformer = output.NewJmesPathTransformer(query) } - if format == outputFormatText { + if format == FlagValueOutputFormatText { return output.NewTextOutputWriter(writer, transformer) } return output.NewJsonOutputWriter(writer, transformer) @@ -334,23 +271,22 @@ func (b CommandBuilder) executeCommand(context executor.ExecutionContext, writer return b.Executor.Call(context, writer, logger) } -func (b CommandBuilder) createOperationCommand(operation parser.Operation) *cli.Command { +func (b CommandBuilder) createOperationCommand(operation parser.Operation) *CommandDefinition { parameters := operation.Parameters b.sortParameters(parameters) - flagBuilder := newFlagBuilder() - flagBuilder.AddFlags(b.createFlags(parameters)) - flagBuilder.AddFlags(b.CreateDefaultFlags(true)) - flagBuilder.AddFlag(b.HelpFlag()) - - return &cli.Command{ - Name: operation.Name, - Usage: operation.Summary, - Description: operation.Description, - Flags: flagBuilder.ToList(), - CustomHelpTemplate: subcommandHelpTemplate, - Action: func(context *cli.Context) error { - profileName := context.String(profileFlagName) + flags := NewFlagBuilder(). + AddFlags(b.createFlags(parameters)). + AddDefaultFlags(true). + AddHelpFlag(). + Build() + + return NewCommand(operation.Name, operation.Summary, operation.Description). + WithFlags(flags). + WithHelpTemplate(OperationCommandHelpTemplate). + WithHidden(operation.Hidden). + WithAction(func(context *CommandExecContext) error { + profileName := context.String(FlagNameProfile) config := b.ConfigProvider.Config(profileName) if config == nil { return fmt.Errorf("Could not find profile '%s'", profileName) @@ -359,9 +295,9 @@ func (b CommandBuilder) createOperationCommand(operation parser.Operation) *cli. if err != nil { return err } - query := context.String(queryFlagName) - wait := context.String(waitFlagName) - waitTimeout := context.Int(waitTimeoutFlagName) + query := context.String(FlagNameQuery) + wait := context.String(FlagNameWait) + waitTimeout := context.Int(FlagNameWaitTimeout) baseUri, err := b.createBaseUri(operation, *config, context) if err != nil { @@ -381,16 +317,16 @@ func (b CommandBuilder) createOperationCommand(operation parser.Operation) *cli. return err } - organization := context.String(organizationFlagName) + organization := context.String(FlagNameOrganization) if organization == "" { organization = config.Organization } - tenant := context.String(tenantFlagName) + tenant := context.String(FlagNameTenant) if tenant == "" { tenant = config.Tenant } - insecure := context.Bool(insecureFlagName) || config.Insecure - debug := context.Bool(debugFlagName) || config.Debug + insecure := context.Bool(FlagNameInsecure) || config.Insecure + debug := context.Bool(FlagNameDebug) || config.Debug identityUri, err := b.createIdentityUri(context, *config, baseUri) if err != nil { return err @@ -415,10 +351,7 @@ func (b CommandBuilder) createOperationCommand(operation parser.Operation) *cli. return b.executeWait(*executionContext, outputFormat, query, wait, waitTimeout) } return b.execute(*executionContext, outputFormat, query, nil) - }, - HideHelp: true, - Hidden: operation.Hidden, - } + }) } func (b CommandBuilder) executeWait(executionContext executor.ExecutionContext, outputFormat string, query string, wait string, waitTimeout int) error { @@ -495,20 +428,17 @@ func (b CommandBuilder) execute(executionContext executor.ExecutionContext, outp return err } -func (b CommandBuilder) createCategoryCommand(operation parser.Operation) *cli.Command { - return &cli.Command{ - Name: operation.Category.Name, - Usage: operation.Category.Summary, - Description: operation.Category.Description, - Flags: []cli.Flag{ - b.HelpFlag(), - b.VersionFlag(true), - }, - HideHelp: true, - } +func (b CommandBuilder) createCategoryCommand(operation parser.Operation) *CommandDefinition { + flags := NewFlagBuilder(). + AddHelpFlag(). + AddVersionFlag(true). + Build() + + return NewCommand(operation.Category.Name, operation.Category.Summary, operation.Category.Description). + WithFlags(flags) } -func (b CommandBuilder) createServiceCommandCategory(operation parser.Operation, categories map[string]*cli.Command) (bool, *cli.Command) { +func (b CommandBuilder) createServiceCommandCategory(operation parser.Operation, categories map[string]*CommandDefinition) (bool, *CommandDefinition) { isNewCategory := false operationCommand := b.createOperationCommand(operation) command, found := categories[operation.Category.Name] @@ -521,9 +451,9 @@ func (b CommandBuilder) createServiceCommandCategory(operation parser.Operation, return isNewCategory, command } -func (b CommandBuilder) createServiceCommand(definition parser.Definition) *cli.Command { - categories := map[string]*cli.Command{} - commands := []*cli.Command{} +func (b CommandBuilder) createServiceCommand(definition parser.Definition) *CommandDefinition { + categories := map[string]*CommandDefinition{} + commands := []*CommandDefinition{} for _, operation := range definition.Operations { if operation.Category == nil { command := b.createOperationCommand(operation) @@ -540,42 +470,31 @@ func (b CommandBuilder) createServiceCommand(definition parser.Definition) *cli. b.sort(command.Subcommands) } - return &cli.Command{ - Name: definition.Name, - Usage: definition.Summary, - Description: definition.Description, - Flags: []cli.Flag{ - b.HelpFlag(), - b.VersionFlag(true), - }, - Subcommands: commands, - HideHelp: true, - } + flags := NewFlagBuilder(). + AddHelpFlag(). + AddVersionFlag(true). + Build() + + return NewCommand(definition.Name, definition.Summary, definition.Description). + WithFlags(flags). + WithSubcommands(commands) } -func (b CommandBuilder) createAutoCompleteEnableCommand() *cli.Command { +func (b CommandBuilder) createAutoCompleteEnableCommand() *CommandDefinition { const shellFlagName = "shell" - const powershellFlagValue = "powershell" - const bashFlagValue = "bash" const fileFlagName = "file" - return &cli.Command{ - Name: "enable", - Usage: "Enable auto complete", - Description: "Enables auto complete in your shell", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: shellFlagName, - Usage: fmt.Sprintf("%s, %s", powershellFlagValue, bashFlagValue), - Required: true, - }, - &cli.StringFlag{ - Name: fileFlagName, - Hidden: true, - }, - b.HelpFlag(), - }, - Action: func(context *cli.Context) error { + flags := NewFlagBuilder(). + AddFlag(NewFlag(shellFlagName, fmt.Sprintf("%s, %s", AutocompletePowershell, AutocompleteBash), FlagTypeString). + WithRequired(true)). + AddFlag(NewFlag(fileFlagName, "The profile file path", FlagTypeString). + WithHidden(true)). + AddHelpFlag(). + Build() + + return NewCommand("enable", "Enable auto complete", "Enables auto complete in your shell"). + WithFlags(flags). + WithAction(func(context *CommandExecContext) error { shell := context.String(shellFlagName) filePath := context.String(fileFlagName) handler := newAutoCompleteHandler() @@ -585,28 +504,24 @@ func (b CommandBuilder) createAutoCompleteEnableCommand() *cli.Command { } fmt.Fprintln(b.StdOut, output) return nil - }, - HideHelp: true, - } -} - -func (b CommandBuilder) createAutoCompleteCompleteCommand(version string) *cli.Command { - return &cli.Command{ - Name: "complete", - Usage: "Autocomplete suggestions", - Description: "Returns the autocomplete suggestions", - Flags: []cli.Flag{ - &cli.StringFlag{ - Name: "command", - Usage: "The command to autocomplete", - Required: true, - }, - b.HelpFlag(), - }, - Action: func(context *cli.Context) error { + }) +} + +func (b CommandBuilder) createAutoCompleteCompleteCommand(version string) *CommandDefinition { + const commandFlagName = "command" + + flags := NewFlagBuilder(). + AddFlag(NewFlag(commandFlagName, "The command to autocomplete", FlagTypeString). + WithRequired(true)). + AddHelpFlag(). + Build() + + return NewCommand("complete", "Autocomplete suggestions", "Returns the autocomplete suggestions"). + WithFlags(flags). + WithAction(func(context *CommandExecContext) error { commandText := context.String("command") exclude := []string{} - for _, flagName := range predefinedFlags { + for _, flagName := range FlagNamesPredefined { exclude = append(exclude, "--"+flagName) } args := strings.Split(commandText, " ") @@ -615,103 +530,82 @@ func (b CommandBuilder) createAutoCompleteCompleteCommand(version string) *cli.C return err } commands := b.createServiceCommands(definitions) + command := NewCommand("uipath", "", ""). + WithSubcommands(commands) handler := newAutoCompleteHandler() - words := handler.Find(commandText, commands, exclude) + words := handler.Find(commandText, command, exclude) for _, word := range words { fmt.Fprintln(b.StdOut, word) } return nil - }, - HideHelp: true, - } -} - -func (b CommandBuilder) createAutoCompleteCommand(version string) *cli.Command { - return &cli.Command{ - Name: "autocomplete", - Usage: "Autocompletion", - Description: "Commands for autocompletion", - Flags: []cli.Flag{ - b.HelpFlag(), - }, - Subcommands: []*cli.Command{ - b.createAutoCompleteEnableCommand(), - b.createAutoCompleteCompleteCommand(version), - }, - HideHelp: true, - } -} - -func (b CommandBuilder) createConfigCommand() *cli.Command { - authFlagName := "auth" - flags := []cli.Flag{ - &cli.StringFlag{ - Name: authFlagName, - Usage: fmt.Sprintf("Authorization type: %s, %s, %s", CredentialsAuth, LoginAuth, PatAuth), - }, - &cli.StringFlag{ - Name: profileFlagName, - Usage: "Profile to configure", - EnvVars: []string{"UIPATH_PROFILE"}, - Value: config.DefaultProfile, - }, - b.HelpFlag(), - } - - return &cli.Command{ - Name: "config", - Usage: "Interactive Configuration", - Description: "Interactive command to configure the CLI", - Flags: flags, - Subcommands: []*cli.Command{ - b.createConfigSetCommand(), - }, - Action: func(context *cli.Context) error { - auth := context.String(authFlagName) - profileName := context.String(profileFlagName) + }) +} + +func (b CommandBuilder) createAutoCompleteCommand(version string) *CommandDefinition { + flags := NewFlagBuilder(). + AddHelpFlag(). + Build() + + subcommands := []*CommandDefinition{ + b.createAutoCompleteEnableCommand(), + b.createAutoCompleteCompleteCommand(version), + } + + return NewCommand("autocomplete", "Autocompletion", "Commands for autocompletion"). + WithFlags(flags). + WithSubcommands(subcommands) +} + +func (b CommandBuilder) createConfigCommand() *CommandDefinition { + const flagNameAuth = "auth" + + flags := NewFlagBuilder(). + AddFlag(NewFlag(flagNameAuth, fmt.Sprintf("Authorization type: %s, %s, %s", CredentialsAuth, LoginAuth, PatAuth), FlagTypeString)). + AddFlag(NewFlag(FlagNameProfile, "Profile to configure", FlagTypeString). + WithEnvVarName("UIPATH_PROFILE"). + WithDefaultValue(config.DefaultProfile)). + AddHelpFlag(). + Build() + + subcommands := []*CommandDefinition{ + b.createConfigSetCommand(), + } + + return NewCommand("config", "Interactive Configuration", "Interactive command to configure the CLI"). + WithFlags(flags). + WithSubcommands(subcommands). + WithAction(func(context *CommandExecContext) error { + auth := context.String(flagNameAuth) + profileName := context.String(FlagNameProfile) handler := newConfigCommandHandler(b.StdIn, b.StdOut, b.ConfigProvider) return handler.Configure(auth, profileName) - }, - HideHelp: true, - } -} - -func (b CommandBuilder) createConfigSetCommand() *cli.Command { - keyFlagName := "key" - valueFlagName := "value" - flags := []cli.Flag{ - &cli.StringFlag{ - Name: keyFlagName, - Usage: "The key", - Required: true, - }, - &cli.StringFlag{ - Name: valueFlagName, - Usage: "The value to set", - Required: true, - }, - &cli.StringFlag{ - Name: profileFlagName, - Usage: "Profile to configure", - EnvVars: []string{"UIPATH_PROFILE"}, - Value: config.DefaultProfile, - }, - b.HelpFlag(), - } - return &cli.Command{ - Name: "set", - Usage: "Set config parameters", - Description: "Set config parameters", - Flags: flags, - Action: func(context *cli.Context) error { - profileName := context.String(profileFlagName) - key := context.String(keyFlagName) - value := context.String(valueFlagName) + }) +} + +func (b CommandBuilder) createConfigSetCommand() *CommandDefinition { + const flagNameKey = "key" + const flagNameValue = "value" + + flags := NewFlagBuilder(). + AddFlag(NewFlag(flagNameKey, "The key", FlagTypeString). + WithRequired(true)). + AddFlag(NewFlag(flagNameValue, "The value to set", FlagTypeString). + WithRequired(true)). + AddFlag(NewFlag(FlagNameProfile, "Profile to configure", FlagTypeString). + WithEnvVarName("UIPATH_PROFILE"). + WithDefaultValue(config.DefaultProfile)). + AddHelpFlag(). + Build() + + return NewCommand("set", "Set config parameters", "Set config parameters"). + WithFlags(flags). + WithAction(func(context *CommandExecContext) error { + profileName := context.String(FlagNameProfile) + key := context.String(flagNameKey) + value := context.String(flagNameValue) handler := newConfigCommandHandler(b.StdIn, b.StdOut, b.ConfigProvider) return handler.Set(key, value, profileName) - }, - HideHelp: true, - } + }) } func (b CommandBuilder) loadDefinitions(args []string, version string) ([]parser.Definition, error) { @@ -753,47 +647,47 @@ func (b CommandBuilder) loadAutocompleteDefinitions(args []string, version strin return b.loadDefinitions(args, version) } -func (b CommandBuilder) createShowCommand(definitions []parser.Definition) *cli.Command { - return &cli.Command{ - Name: "commands", - Usage: "Inspect available CLI operations", - Description: "Command to inspect available uipath CLI operations", - Flags: []cli.Flag{ - b.HelpFlag(), - }, - Subcommands: []*cli.Command{ - { - Name: "show", - Usage: "Print CLI commands", - Description: "Print available uipath CLI commands", - Flags: []cli.Flag{ - b.HelpFlag(), - }, - Action: func(context *cli.Context) error { - flagBuilder := newFlagBuilder() - flagBuilder.AddFlags(b.CreateDefaultFlags(false)) - flagBuilder.AddFlag(b.HelpFlag()) - flags := flagBuilder.ToList() - - handler := newShowCommandHandler() - output, err := handler.Execute(definitions, flags) - if err != nil { - return err - } - fmt.Fprintln(b.StdOut, output) - return nil - }, - HideHelp: true, - Hidden: true, - }, - }, - HideHelp: true, - Hidden: true, - } -} - -func (b CommandBuilder) createServiceCommands(definitions []parser.Definition) []*cli.Command { - commands := []*cli.Command{} +func (b CommandBuilder) createShowCommand(definitions []parser.Definition) *CommandDefinition { + flags := NewFlagBuilder(). + AddHelpFlag(). + Build() + + return NewCommand("show", "Print CLI commands", "Print available uipath CLI commands"). + WithFlags(flags). + WithHidden(true). + WithAction(func(context *CommandExecContext) error { + defaultFlags := NewFlagBuilder(). + AddDefaultFlags(false). + AddHelpFlag(). + Build() + + handler := newShowCommandHandler() + output, err := handler.Execute(definitions, defaultFlags) + if err != nil { + return err + } + fmt.Fprintln(b.StdOut, output) + return nil + }) +} + +func (b CommandBuilder) createInspectCommand(definitions []parser.Definition) *CommandDefinition { + flags := NewFlagBuilder(). + AddHelpFlag(). + Build() + + subcommands := []*CommandDefinition{ + b.createShowCommand(definitions), + } + + return NewCommand("commands", "Inspect available CLI operations", "Command to inspect available uipath CLI operations"). + WithFlags(flags). + WithSubcommands(subcommands). + WithHidden(true) +} + +func (b CommandBuilder) createServiceCommands(definitions []parser.Definition) []*CommandDefinition { + commands := []*CommandDefinition{} for _, e := range definitions { command := b.createServiceCommand(e) commands = append(commands, command) @@ -820,9 +714,9 @@ func (b CommandBuilder) versionFromProfile(profile string) string { return config.Version } -func (b CommandBuilder) Create(args []string) ([]*cli.Command, error) { - version := b.parseArgument(args, versionFlagName) - profile := b.parseArgument(args, profileFlagName) +func (b CommandBuilder) Create(args []string) ([]*CommandDefinition, error) { + version := b.parseArgument(args, FlagNameVersion) + profile := b.parseArgument(args, FlagNameProfile) if version == "" && profile != "" { version = b.versionFromProfile(profile) } @@ -833,108 +727,7 @@ func (b CommandBuilder) Create(args []string) ([]*cli.Command, error) { servicesCommands := b.createServiceCommands(definitions) autocompleteCommand := b.createAutoCompleteCommand(version) configCommand := b.createConfigCommand() - showCommand := b.createShowCommand(definitions) - commands := append(servicesCommands, autocompleteCommand, configCommand, showCommand) + inspectCommand := b.createInspectCommand(definitions) + commands := append(servicesCommands, autocompleteCommand, configCommand, inspectCommand) return commands, nil } - -func (b CommandBuilder) CreateDefaultFlags(hidden bool) []cli.Flag { - return []cli.Flag{ - &cli.BoolFlag{ - Name: debugFlagName, - Usage: "Enable debug output", - EnvVars: []string{"UIPATH_DEBUG"}, - Value: false, - Hidden: hidden, - }, - &cli.StringFlag{ - Name: profileFlagName, - Usage: "Config profile to use", - EnvVars: []string{"UIPATH_PROFILE"}, - Value: config.DefaultProfile, - Hidden: hidden, - }, - &cli.StringFlag{ - Name: uriFlagName, - Usage: "Server Base-URI", - EnvVars: []string{"UIPATH_URI"}, - Hidden: hidden, - }, - &cli.StringFlag{ - Name: organizationFlagName, - Usage: "Organization name", - EnvVars: []string{"UIPATH_ORGANIZATION"}, - Hidden: hidden, - }, - &cli.StringFlag{ - Name: tenantFlagName, - Usage: "Tenant name", - EnvVars: []string{"UIPATH_TENANT"}, - Hidden: hidden, - }, - &cli.BoolFlag{ - Name: insecureFlagName, - Usage: "Disable HTTPS certificate check", - EnvVars: []string{"UIPATH_INSECURE"}, - Value: false, - Hidden: hidden, - }, - &cli.StringFlag{ - Name: outputFormatFlagName, - Usage: fmt.Sprintf("Set output format: %s (default), %s", outputFormatJson, outputFormatText), - EnvVars: []string{"UIPATH_OUTPUT"}, - Value: "", - Hidden: hidden, - }, - &cli.StringFlag{ - Name: queryFlagName, - Usage: "Perform JMESPath query on output", - Value: "", - Hidden: hidden, - }, - &cli.StringFlag{ - Name: waitFlagName, - Usage: "Waits for the provided condition (JMESPath expression)", - Value: "", - Hidden: hidden, - }, - &cli.IntFlag{ - Name: waitTimeoutFlagName, - Usage: "Time to wait in seconds for condition", - Value: 30, - Hidden: hidden, - }, - &cli.StringFlag{ - Name: fileFlagName, - Usage: "Provide input from file (use - for stdin)", - Value: "", - Hidden: hidden, - }, - &cli.StringFlag{ - Name: identityUriFlagName, - Usage: "Identity Server URI", - EnvVars: []string{"UIPATH_IDENTITY_URI"}, - Hidden: hidden, - }, - b.VersionFlag(hidden), - } -} - -func (b CommandBuilder) VersionFlag(hidden bool) cli.Flag { - return &cli.StringFlag{ - Name: versionFlagName, - Usage: "Specific service version", - EnvVars: []string{"UIPATH_VERSION"}, - Value: "", - Hidden: hidden, - } -} - -func (b CommandBuilder) HelpFlag() cli.Flag { - return &cli.BoolFlag{ - Name: helpFlagName, - Usage: "Show help", - Value: false, - Hidden: true, - } -} diff --git a/commandline/command_definition.go b/commandline/command_definition.go new file mode 100644 index 0000000..330e3a9 --- /dev/null +++ b/commandline/command_definition.go @@ -0,0 +1,62 @@ +package commandline + +import "github.com/urfave/cli/v2" + +// The CommandExecContext contains the flag values provided by the user. +type CommandExecContext struct { + *cli.Context +} + +// The CommandExecFunc is the function definition for executing a command action. +type CommandExecFunc func(*CommandExecContext) error + +// The CommandDefinition contains the metadata and builder methods for creating +// CLI commands. +type CommandDefinition struct { + Name string + Summary string + Description string + Flags []*FlagDefinition + Subcommands []*CommandDefinition + HelpTemplate string + Hidden bool + Action CommandExecFunc +} + +func (c *CommandDefinition) WithFlags(flags []*FlagDefinition) *CommandDefinition { + c.Flags = flags + return c +} + +func (c *CommandDefinition) WithSubcommands(subcommands []*CommandDefinition) *CommandDefinition { + c.Subcommands = subcommands + return c +} + +func (c *CommandDefinition) WithHidden(hidden bool) *CommandDefinition { + c.Hidden = hidden + return c +} + +func (c *CommandDefinition) WithHelpTemplate(helpTemplate string) *CommandDefinition { + c.HelpTemplate = helpTemplate + return c +} + +func (c *CommandDefinition) WithAction(action CommandExecFunc) *CommandDefinition { + c.Action = action + return c +} + +func NewCommand(name string, summary string, description string) *CommandDefinition { + return &CommandDefinition{ + name, + summary, + description, + nil, + nil, + "", + false, + nil, + } +} diff --git a/commandline/flag_builder.go b/commandline/flag_builder.go index bca3eb3..cd761a6 100644 --- a/commandline/flag_builder.go +++ b/commandline/flag_builder.go @@ -1,36 +1,156 @@ package commandline import ( - "github.com/urfave/cli/v2" + "fmt" + + "github.com/UiPath/uipathcli/config" ) -type flagBuilder struct { - flags map[string]cli.Flag +const FlagNameDebug = "debug" +const FlagNameProfile = "profile" +const FlagNameUri = "uri" +const FlagNameOrganization = "organization" +const FlagNameTenant = "tenant" +const FlagNameInsecure = "insecure" +const FlagNameOutputFormat = "output" +const FlagNameQuery = "query" +const FlagNameWait = "wait" +const FlagNameWaitTimeout = "wait-timeout" +const FlagNameFile = "file" +const FlagNameIdentityUri = "identity-uri" +const FlagNameVersion = "version" +const FlagNameHelp = "help" + +const FlagValueFromStdIn = "-" +const FlagValueOutputFormatJson = "json" +const FlagValueOutputFormatText = "text" + +var FlagNamesPredefined = []string{ + FlagNameDebug, + FlagNameProfile, + FlagNameUri, + FlagNameOrganization, + FlagNameTenant, + FlagNameInsecure, + FlagNameOutputFormat, + FlagNameQuery, + FlagNameWait, + FlagNameWaitTimeout, + FlagNameFile, + FlagNameIdentityUri, + FlagNameVersion, + FlagNameHelp, +} + +// The FlagBuilder can be used to prepare a list of flags for a CLI command. +// The builder takes care that flags with the same name are deduped. +type FlagBuilder struct { + flags map[string]*FlagDefinition order []string } -func (b *flagBuilder) AddFlag(flag cli.Flag) { - name := flag.Names()[0] +func (b *FlagBuilder) AddFlag(flag *FlagDefinition) *FlagBuilder { + name := flag.Name if _, found := b.flags[name]; !found { b.flags[name] = flag b.order = append(b.order, name) } + return b } -func (b *flagBuilder) AddFlags(flags []cli.Flag) { +func (b *FlagBuilder) AddFlags(flags []*FlagDefinition) *FlagBuilder { for _, flag := range flags { b.AddFlag(flag) } + return b +} + +func (b *FlagBuilder) AddDefaultFlags(hidden bool) *FlagBuilder { + b.AddFlags(b.defaultFlags(hidden)) + return b +} + +func (b *FlagBuilder) AddHelpFlag() *FlagBuilder { + b.AddFlag(b.helpFlag()) + return b } -func (b flagBuilder) ToList() []cli.Flag { - flags := []cli.Flag{} +func (b *FlagBuilder) AddVersionFlag(hidden bool) *FlagBuilder { + b.AddFlag(b.versionFlag(hidden)) + return b +} + +func (b FlagBuilder) Build() []*FlagDefinition { + flags := []*FlagDefinition{} for _, name := range b.order { flags = append(flags, b.flags[name]) } return flags } -func newFlagBuilder() *flagBuilder { - return &flagBuilder{map[string]cli.Flag{}, []string{}} +func (b FlagBuilder) defaultFlags(hidden bool) []*FlagDefinition { + return []*FlagDefinition{ + NewFlag(FlagNameDebug, "Enable debug output", FlagTypeBoolean). + WithEnvVarName("UIPATH_DEBUG"). + WithDefaultValue(false). + WithHidden(hidden), + NewFlag(FlagNameProfile, "Config profile to use", FlagTypeString). + WithEnvVarName("UIPATH_PROFILE"). + WithDefaultValue(config.DefaultProfile). + WithHidden(hidden), + NewFlag(FlagNameUri, "Server Base-URI", FlagTypeString). + WithEnvVarName("UIPATH_URI"). + WithDefaultValue(""). + WithHidden(hidden), + NewFlag(FlagNameOrganization, "Organization name", FlagTypeString). + WithEnvVarName("UIPATH_ORGANIZATION"). + WithDefaultValue(""). + WithHidden(hidden), + NewFlag(FlagNameTenant, "Tenant name", FlagTypeString). + WithEnvVarName("UIPATH_TENANT"). + WithDefaultValue(""). + WithHidden(hidden), + NewFlag(FlagNameInsecure, "Disable HTTPS certificate check", FlagTypeBoolean). + WithEnvVarName("UIPATH_INSECURE"). + WithDefaultValue(false). + WithHidden(hidden), + NewFlag(FlagNameOutputFormat, fmt.Sprintf("Set output format: %s (default), %s", FlagValueOutputFormatJson, FlagValueOutputFormatText), FlagTypeString). + WithEnvVarName("UIPATH_OUTPUT"). + WithDefaultValue(""). + WithHidden(hidden), + NewFlag(FlagNameQuery, "Perform JMESPath query on output", FlagTypeString). + WithDefaultValue(""). + WithHidden(hidden), + NewFlag(FlagNameWait, "Waits for the provided condition (JMESPath expression)", FlagTypeString). + WithDefaultValue(""). + WithHidden(hidden), + NewFlag(FlagNameWaitTimeout, "Time to wait in seconds for condition", FlagTypeInteger). + WithDefaultValue(30). + WithHidden(hidden), + NewFlag(FlagNameFile, "Provide input from file (use - for stdin)", FlagTypeString). + WithDefaultValue(""). + WithHidden(hidden), + NewFlag(FlagNameIdentityUri, "Identity Server URI", FlagTypeString). + WithEnvVarName("UIPATH_IDENTITY_URI"). + WithDefaultValue(""). + WithHidden(hidden), + b.versionFlag(hidden), + } +} + +func (b FlagBuilder) versionFlag(hidden bool) *FlagDefinition { + return NewFlag(FlagNameVersion, "Specific service version", FlagTypeString). + WithEnvVarName("UIPATH_VERSION"). + WithDefaultValue(""). + WithHidden(hidden) +} + +func (b FlagBuilder) helpFlag() *FlagDefinition { + return NewFlag(FlagNameHelp, "Show help", FlagTypeBoolean). + WithDefaultValue(false). + WithHidden(true) +} + +func NewFlagBuilder() *FlagBuilder { + return &FlagBuilder{map[string]*FlagDefinition{}, []string{}} } diff --git a/commandline/flag_definition.go b/commandline/flag_definition.go new file mode 100644 index 0000000..6bb7ae4 --- /dev/null +++ b/commandline/flag_definition.go @@ -0,0 +1,47 @@ +package commandline + +type FlagOptionFunc func(*FlagDefinition) + +// The FlagDefinition contains the metadata and builder methods for creating +// command line flags. +type FlagDefinition struct { + Name string + Summary string + Type FlagType + EnvVarName string + DefaultValue interface{} + Hidden bool + Required bool +} + +func (f *FlagDefinition) WithDefaultValue(value interface{}) *FlagDefinition { + f.DefaultValue = value + return f +} + +func (f *FlagDefinition) WithEnvVarName(envVarName string) *FlagDefinition { + f.EnvVarName = envVarName + return f +} + +func (f *FlagDefinition) WithHidden(hidden bool) *FlagDefinition { + f.Hidden = hidden + return f +} + +func (f *FlagDefinition) WithRequired(required bool) *FlagDefinition { + f.Required = required + return f +} + +func NewFlag(name string, summary string, flagType FlagType) *FlagDefinition { + return &FlagDefinition{ + name, + summary, + flagType, + "", + nil, + false, + false, + } +} diff --git a/commandline/flag_type.go b/commandline/flag_type.go new file mode 100644 index 0000000..63e3ed3 --- /dev/null +++ b/commandline/flag_type.go @@ -0,0 +1,27 @@ +package commandline + +import "fmt" + +// The FlagType is an enum of the supported flag definition types. +type FlagType int + +const ( + FlagTypeString FlagType = iota + 1 + FlagTypeInteger + FlagTypeBoolean + FlagTypeStringArray +) + +func (t FlagType) String() string { + switch t { + case FlagTypeString: + return "string" + case FlagTypeInteger: + return "integer" + case FlagTypeBoolean: + return "boolean" + case FlagTypeStringArray: + return "stringArray" + } + panic(fmt.Sprintf("Unknown flag type: %d", int(t))) +} diff --git a/commandline/help_templates.go b/commandline/help_templates.go new file mode 100644 index 0000000..566b6bc --- /dev/null +++ b/commandline/help_templates.go @@ -0,0 +1,19 @@ +package commandline + +const OperationCommandHelpTemplate = `NAME: + {{template "helpNameTemplate" .}} + +USAGE: + {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}}{{if .ArgsUsage}}{{.ArgsUsage}}{{else}} [arguments...]{{end}}{{end}}{{if .Description}} + +DESCRIPTION: + {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}} + +COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategories}} + +OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}} + +OPTIONS:{{range $i, $e := .VisibleFlags}} + --{{$e.Name}} {{wrap $e.Usage 6}} +{{end}}{{end}} +` diff --git a/commandline/show_command_handler.go b/commandline/show_command_handler.go index ec26b86..ce7e3ca 100644 --- a/commandline/show_command_handler.go +++ b/commandline/show_command_handler.go @@ -5,7 +5,6 @@ import ( "sort" "github.com/UiPath/uipathcli/parser" - "github.com/urfave/cli/v2" ) // showCommandHandler prints all available uipathcli commands @@ -29,7 +28,7 @@ type commandJson struct { Subcommands []commandJson `json:"subcommands"` } -func (h showCommandHandler) Execute(definitions []parser.Definition, globalFlags []cli.Flag) (string, error) { +func (h showCommandHandler) Execute(definitions []parser.Definition, globalFlags []*FlagDefinition) (string, error) { result := commandJson{ Name: "uipath", Description: "Command line interface to simplify, script and automate API calls for UiPath services", @@ -104,7 +103,7 @@ func (h showCommandHandler) convertOperationToCommand(operation parser.Operation } } -func (h showCommandHandler) convertFlagsToCommandParameters(flags []cli.Flag) []parameterJson { +func (h showCommandHandler) convertFlagsToCommandParameters(flags []*FlagDefinition) []parameterJson { result := []parameterJson{} for _, f := range flags { result = append(result, h.convertFlagToCommandParameter(f)) @@ -120,37 +119,14 @@ func (h showCommandHandler) convertParametersToCommandParameters(parameters []pa return result } -func (h showCommandHandler) convertFlagToCommandParameter(flag cli.Flag) parameterJson { - intFlag, ok := flag.(*cli.IntFlag) - if ok { - return parameterJson{ - Name: intFlag.Name, - Description: intFlag.Usage, - Type: "integer", - Required: false, - AllowedValues: []interface{}{}, - DefaultValue: intFlag.Value, - } - } - boolFlag, ok := flag.(*cli.BoolFlag) - if ok { - return parameterJson{ - Name: boolFlag.Name, - Description: boolFlag.Usage, - Type: "boolean", - Required: false, - AllowedValues: []interface{}{}, - DefaultValue: boolFlag.Value, - } - } - stringFlag := flag.(*cli.StringFlag) +func (h showCommandHandler) convertFlagToCommandParameter(flag *FlagDefinition) parameterJson { return parameterJson{ - Name: stringFlag.Name, - Description: stringFlag.Usage, - Type: "string", + Name: flag.Name, + Description: flag.Summary, + Type: flag.Type.String(), Required: false, AllowedValues: []interface{}{}, - DefaultValue: stringFlag.Value, + DefaultValue: flag.DefaultValue, } }