• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

UiPath / uipathcli / 11162363984

03 Oct 2024 12:53PM UTC coverage: 90.424% (-0.02%) from 90.447%
11162363984

push

github

thschmitt
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.

463 of 478 new or added lines in 8 files covered. (96.86%)

1 existing line in 1 file now uncovered.

4268 of 4720 relevant lines covered (90.42%)

1.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.99
/commandline/cli.go
1
// Package commandline is responsible for creating, parsing and validating
2
// command line arguments.
3
package commandline
4

5
import (
6
        "fmt"
7
        "io"
8

9
        "github.com/UiPath/uipathcli/config"
10
        "github.com/UiPath/uipathcli/executor"
11
        "github.com/UiPath/uipathcli/utils"
12
        "github.com/urfave/cli/v2"
13
)
14

15
// Cli is a wrapper for building the CLI commands.
16
type Cli struct {
17
        stdIn              io.Reader
18
        stdOut             io.Writer
19
        stdErr             io.Writer
20
        coloredOutput      bool
21
        definitionProvider DefinitionProvider
22
        configProvider     config.ConfigProvider
23
        executor           executor.Executor
24
        pluginExecutor     executor.Executor
25
}
26

27
func (c Cli) run(args []string, input utils.Stream) error {
1✔
28
        err := c.configProvider.Load()
1✔
29
        if err != nil {
1✔
30
                return err
×
31
        }
×
32

33
        CommandBuilder := CommandBuilder{
1✔
34
                Input:              input,
1✔
35
                StdIn:              c.stdIn,
1✔
36
                StdOut:             c.stdOut,
1✔
37
                StdErr:             c.stdErr,
1✔
38
                ConfigProvider:     c.configProvider,
1✔
39
                Executor:           c.executor,
1✔
40
                PluginExecutor:     c.pluginExecutor,
1✔
41
                DefinitionProvider: c.definitionProvider,
1✔
42
        }
1✔
43

1✔
44
        flags := NewFlagBuilder().
1✔
45
                AddDefaultFlags(false).
1✔
46
                Build()
1✔
47

1✔
48
        commands, err := CommandBuilder.Create(args)
1✔
49
        if err != nil {
2✔
50
                return err
1✔
51
        }
1✔
52

53
        app := &cli.App{
1✔
54
                Name:                      "uipath",
1✔
55
                Usage:                     "Command-Line Interface for UiPath Services",
1✔
56
                UsageText:                 "uipath <service> <operation> --parameter",
1✔
57
                Version:                   "1.0",
1✔
58
                Flags:                     c.convertFlags(flags...),
1✔
59
                Commands:                  c.convertCommands(commands...),
1✔
60
                Writer:                    c.stdOut,
1✔
61
                ErrWriter:                 c.stdErr,
1✔
62
                HideVersion:               true,
1✔
63
                HideHelpCommand:           true,
1✔
64
                DisableSliceFlagSeparator: true,
1✔
65
        }
1✔
66
        return app.Run(args)
1✔
67
}
68

69
const colorRed = "\033[31m"
70
const colorReset = "\033[0m"
71

72
func (c Cli) Run(args []string, input utils.Stream) error {
1✔
73
        err := c.run(args, input)
1✔
74
        if err != nil {
2✔
75
                message := err.Error()
1✔
76
                if c.coloredOutput {
1✔
77
                        message = colorRed + err.Error() + colorReset
×
78
                }
×
79
                fmt.Fprintln(c.stdErr, message)
1✔
80
        }
81
        return err
1✔
82
}
83

84
func NewCli(
85
        stdIn io.Reader,
86
        stdOut io.Writer,
87
        stdErr io.Writer,
88
        colors bool,
89
        definitionProvider DefinitionProvider,
90
        configProvider config.ConfigProvider,
91
        executor executor.Executor,
92
        pluginExecutor executor.Executor,
93
) *Cli {
1✔
94
        return &Cli{stdIn, stdOut, stdErr, colors, definitionProvider, configProvider, executor, pluginExecutor}
1✔
95
}
1✔
96

97
func (c Cli) convertCommand(command *CommandDefinition) *cli.Command {
1✔
98
        result := cli.Command{
1✔
99
                Name:               command.Name,
1✔
100
                Usage:              command.Summary,
1✔
101
                Description:        command.Description,
1✔
102
                Flags:              c.convertFlags(command.Flags...),
1✔
103
                Subcommands:        c.convertCommands(command.Subcommands...),
1✔
104
                CustomHelpTemplate: command.HelpTemplate,
1✔
105
                Hidden:             command.Hidden,
1✔
106
                HideHelp:           true,
1✔
107
        }
1✔
108
        if command.Action != nil {
2✔
109
                result.Action = func(context *cli.Context) error {
2✔
110
                        return command.Action(&CommandExecContext{context})
1✔
111
                }
1✔
112
        }
113
        return &result
1✔
114
}
115

116
func (c Cli) convertCommands(commands ...*CommandDefinition) []*cli.Command {
1✔
117
        result := []*cli.Command{}
1✔
118
        for _, command := range commands {
2✔
119
                result = append(result, c.convertCommand(command))
1✔
120
        }
1✔
121
        return result
1✔
122
}
123

124
func (c Cli) convertStringSliceFlag(flag *FlagDefinition) *cli.StringSliceFlag {
1✔
125
        envVars := []string{}
1✔
126
        if flag.EnvVarName != "" {
1✔
NEW
127
                envVars = append(envVars, flag.EnvVarName)
×
NEW
128
        }
×
129
        var value *cli.StringSlice
1✔
130
        if flag.DefaultValue != nil {
1✔
NEW
131
                value = cli.NewStringSlice(flag.DefaultValue.([]string)...)
×
NEW
132
        }
×
133
        return &cli.StringSliceFlag{
1✔
134
                Name:     flag.Name,
1✔
135
                Usage:    flag.Summary,
1✔
136
                EnvVars:  envVars,
1✔
137
                Required: flag.Required,
1✔
138
                Hidden:   flag.Hidden,
1✔
139
                Value:    value,
1✔
140
        }
1✔
141
}
142

143
func (c Cli) convertIntFlag(flag *FlagDefinition) *cli.IntFlag {
1✔
144
        envVars := []string{}
1✔
145
        if flag.EnvVarName != "" {
1✔
NEW
146
                envVars = append(envVars, flag.EnvVarName)
×
NEW
147
        }
×
148
        var value int
1✔
149
        if flag.DefaultValue != nil {
2✔
150
                value = flag.DefaultValue.(int)
1✔
151
        }
1✔
152
        return &cli.IntFlag{
1✔
153
                Name:     flag.Name,
1✔
154
                Usage:    flag.Summary,
1✔
155
                EnvVars:  envVars,
1✔
156
                Required: flag.Required,
1✔
157
                Hidden:   flag.Hidden,
1✔
158
                Value:    value,
1✔
159
        }
1✔
160
}
161

162
func (c Cli) convertBoolFlag(flag *FlagDefinition) *cli.BoolFlag {
1✔
163
        envVars := []string{}
1✔
164
        if flag.EnvVarName != "" {
2✔
165
                envVars = append(envVars, flag.EnvVarName)
1✔
166
        }
1✔
167
        var value bool
1✔
168
        if flag.DefaultValue != nil {
2✔
169
                value = flag.DefaultValue.(bool)
1✔
170
        }
1✔
171
        return &cli.BoolFlag{
1✔
172
                Name:     flag.Name,
1✔
173
                Usage:    flag.Summary,
1✔
174
                EnvVars:  envVars,
1✔
175
                Required: flag.Required,
1✔
176
                Hidden:   flag.Hidden,
1✔
177
                Value:    value,
1✔
178
        }
1✔
179
}
180

181
func (c Cli) convertStringFlag(flag *FlagDefinition) *cli.StringFlag {
1✔
182
        envVars := []string{}
1✔
183
        if flag.EnvVarName != "" {
2✔
184
                envVars = append(envVars, flag.EnvVarName)
1✔
185
        }
1✔
186
        var value string
1✔
187
        if flag.DefaultValue != nil {
2✔
188
                value = flag.DefaultValue.(string)
1✔
189
        }
1✔
190
        return &cli.StringFlag{
1✔
191
                Name:     flag.Name,
1✔
192
                Usage:    flag.Summary,
1✔
193
                EnvVars:  envVars,
1✔
194
                Required: flag.Required,
1✔
195
                Hidden:   flag.Hidden,
1✔
196
                Value:    value,
1✔
197
        }
1✔
198
}
199

200
func (c Cli) convertFlag(flag *FlagDefinition) cli.Flag {
1✔
201
        switch flag.Type {
1✔
202
        case FlagTypeStringArray:
1✔
203
                return c.convertStringSliceFlag(flag)
1✔
204
        case FlagTypeInteger:
1✔
205
                return c.convertIntFlag(flag)
1✔
206
        case FlagTypeBoolean:
1✔
207
                return c.convertBoolFlag(flag)
1✔
208
        case FlagTypeString:
1✔
209
                return c.convertStringFlag(flag)
1✔
210
        }
NEW
211
        panic(fmt.Sprintf("Unknown flag type: %s", flag.Type.String()))
×
212
}
213

214
func (c Cli) convertFlags(flags ...*FlagDefinition) []cli.Flag {
1✔
215
        result := []cli.Flag{}
1✔
216
        for _, flag := range flags {
2✔
217
                result = append(result, c.convertFlag(flag))
1✔
218
        }
1✔
219
        return result
1✔
220
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc