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

UiPath / uipathcli / 11124812873

01 Oct 2024 11:58AM UTC coverage: 90.145% (-0.2%) from 90.362%
11124812873

push

github

thschmitt
Create command abstraction and split up command builder

416 of 437 new or added lines in 8 files covered. (95.19%)

1 existing line in 1 file now uncovered.

4116 of 4566 relevant lines covered (90.14%)

1.02 hits per line

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

94.66
/commandline/command_builder.go
1
package commandline
2

3
import (
4
        "encoding/json"
5
        "errors"
6
        "fmt"
7
        "io"
8
        "net/url"
9
        "sort"
10
        "strings"
11
        "sync"
12
        "time"
13

14
        "github.com/UiPath/uipathcli/config"
15
        "github.com/UiPath/uipathcli/executor"
16
        "github.com/UiPath/uipathcli/log"
17
        "github.com/UiPath/uipathcli/output"
18
        "github.com/UiPath/uipathcli/parser"
19
        "github.com/UiPath/uipathcli/utils"
20
)
21

22
const subcommandHelpTemplate = `NAME:
23
   {{template "helpNameTemplate" .}}
24

25
USAGE:
26
   {{if .UsageText}}{{wrap .UsageText 3}}{{else}}{{.HelpName}}{{if .VisibleFlags}} [command options]{{end}}{{if .ArgsUsage}}{{.ArgsUsage}}{{else}} [arguments...]{{end}}{{end}}{{if .Description}}
27

28
DESCRIPTION:
29
   {{template "descriptionTemplate" .}}{{end}}{{if .VisibleCommands}}
30

31
COMMANDS:{{template "visibleCommandTemplate" .}}{{end}}{{if .VisibleFlagCategories}}
32

33
OPTIONS:{{template "visibleFlagCategoryTemplate" .}}{{else if .VisibleFlags}}
34

35
OPTIONS:{{range $i, $e := .VisibleFlags}}
36
   --{{$e.Name}} {{wrap $e.Usage 6}}
37
{{end}}{{end}}
38
`
39

40
// The CommandBuilder is creating all available operations and arguments for the CLI.
41
type CommandBuilder struct {
42
        Input              utils.Stream
43
        StdIn              io.Reader
44
        StdOut             io.Writer
45
        StdErr             io.Writer
46
        ConfigProvider     config.ConfigProvider
47
        Executor           executor.Executor
48
        PluginExecutor     executor.Executor
49
        DefinitionProvider DefinitionProvider
50
}
51

52
func (b CommandBuilder) sort(commands []*commandDefinition) {
1✔
53
        sort.Slice(commands, func(i, j int) bool {
2✔
54
                return commands[i].Name < commands[j].Name
1✔
55
        })
1✔
56
}
57

58
func (b CommandBuilder) fileInput(context *CommandExecContext, parameters []parser.Parameter) utils.Stream {
1✔
59
        value := context.String(FlagNameFile)
1✔
60
        if value == "" {
2✔
61
                return nil
1✔
62
        }
1✔
63
        if value == FlagValueFromStdIn {
2✔
64
                return b.Input
1✔
65
        }
1✔
66
        for _, param := range parameters {
2✔
67
                if strings.EqualFold(param.FieldName, FlagNameFile) {
2✔
68
                        return nil
1✔
69
                }
1✔
70
        }
71
        return utils.NewFileStream(value)
1✔
72
}
73

74
func (b CommandBuilder) createExecutionParameters(context *CommandExecContext, config *config.Config, operation parser.Operation) (executor.ExecutionParameters, error) {
1✔
75
        typeConverter := newTypeConverter()
1✔
76

1✔
77
        parameters := []executor.ExecutionParameter{}
1✔
78
        for _, param := range operation.Parameters {
2✔
79
                if context.IsSet(param.Name) && param.IsArray() {
2✔
80
                        value, err := typeConverter.ConvertArray(context.StringSlice(param.Name), param)
1✔
81
                        if err != nil {
2✔
82
                                return nil, err
1✔
83
                        }
1✔
84
                        parameter := executor.NewExecutionParameter(param.FieldName, value, param.In)
1✔
85
                        parameters = append(parameters, *parameter)
1✔
86
                } else if context.IsSet(param.Name) {
2✔
87
                        value, err := typeConverter.Convert(context.String(param.Name), param)
1✔
88
                        if err != nil {
2✔
89
                                return nil, err
1✔
90
                        }
1✔
91
                        parameter := executor.NewExecutionParameter(param.FieldName, value, param.In)
1✔
92
                        parameters = append(parameters, *parameter)
1✔
93
                } else if configValue, ok := config.Parameter[param.Name]; ok {
2✔
94
                        value, err := typeConverter.Convert(configValue, param)
1✔
95
                        if err != nil {
1✔
96
                                return nil, err
×
97
                        }
×
98
                        parameter := executor.NewExecutionParameter(param.FieldName, value, param.In)
1✔
99
                        parameters = append(parameters, *parameter)
1✔
100
                } else if param.Required && param.DefaultValue != nil {
2✔
101
                        parameter := executor.NewExecutionParameter(param.FieldName, param.DefaultValue, param.In)
1✔
102
                        parameters = append(parameters, *parameter)
1✔
103
                }
1✔
104
        }
105
        parameters = append(parameters, b.createExecutionParametersFromConfigMap(config.Header, parser.ParameterInHeader)...)
1✔
106
        return parameters, nil
1✔
107
}
108

109
func (b CommandBuilder) createExecutionParametersFromConfigMap(params map[string]string, in string) executor.ExecutionParameters {
1✔
110
        parameters := []executor.ExecutionParameter{}
1✔
111
        for key, value := range params {
2✔
112
                parameter := executor.NewExecutionParameter(key, value, in)
1✔
113
                parameters = append(parameters, *parameter)
1✔
114
        }
1✔
115
        return parameters
1✔
116
}
117

118
func (b CommandBuilder) formatAllowedValues(values []interface{}) string {
1✔
119
        result := ""
1✔
120
        separator := ""
1✔
121
        for _, value := range values {
2✔
122
                result += fmt.Sprintf("%s%v", separator, value)
1✔
123
                separator = ", "
1✔
124
        }
1✔
125
        return result
1✔
126
}
127

128
func (b CommandBuilder) createFlags(parameters []parser.Parameter) []*flagDefinition {
1✔
129
        flags := []*flagDefinition{}
1✔
130
        for _, parameter := range parameters {
2✔
131
                formatter := newParameterFormatter(parameter)
1✔
132
                flagType := FlagTypeString
1✔
133
                if parameter.IsArray() {
2✔
134
                        flagType = FlagTypeStringArray
1✔
135
                }
1✔
136
                flag := newFlagDefinition(parameter.Name, formatter.Description(), "", flagType, "", nil, false, false)
1✔
137
                flags = append(flags, flag)
1✔
138
        }
139
        return flags
1✔
140
}
141

142
func (b CommandBuilder) sortParameters(parameters []parser.Parameter) {
1✔
143
        sort.Slice(parameters, func(i, j int) bool {
2✔
144
                if parameters[i].Required && !parameters[j].Required {
2✔
145
                        return true
1✔
146
                }
1✔
147
                if !parameters[i].Required && parameters[j].Required {
2✔
148
                        return false
1✔
149
                }
1✔
150
                return parameters[i].Name < parameters[j].Name
1✔
151
        })
152
}
153

154
func (b CommandBuilder) outputFormat(config config.Config, context *CommandExecContext) (string, error) {
1✔
155
        outputFormat := context.String(FlagNameOutputFormat)
1✔
156
        if outputFormat == "" {
2✔
157
                outputFormat = config.Output
1✔
158
        }
1✔
159
        if outputFormat == "" {
2✔
160
                outputFormat = FlagValueOutputFormatJson
1✔
161
        }
1✔
162
        if outputFormat != FlagValueOutputFormatJson && outputFormat != FlagValueOutputFormatText {
1✔
NEW
163
                return "", fmt.Errorf("Invalid output format '%s', allowed values: %s, %s", outputFormat, FlagValueOutputFormatJson, FlagValueOutputFormatText)
×
UNCOV
164
        }
×
165
        return outputFormat, nil
1✔
166
}
167

168
func (b CommandBuilder) createBaseUri(operation parser.Operation, config config.Config, context *CommandExecContext) (url.URL, error) {
1✔
169
        uriArgument, err := b.parseUriArgument(context)
1✔
170
        if err != nil {
1✔
171
                return operation.BaseUri, err
×
172
        }
×
173

174
        builder := NewUriBuilder(operation.BaseUri)
1✔
175
        builder.OverrideUri(config.Uri)
1✔
176
        builder.OverrideUri(uriArgument)
1✔
177
        return builder.Uri(), nil
1✔
178
}
179

180
func (b CommandBuilder) createIdentityUri(context *CommandExecContext, config config.Config, baseUri url.URL) (*url.URL, error) {
1✔
181
        uri := context.String(FlagNameIdentityUri)
1✔
182
        if uri != "" {
2✔
183
                identityUri, err := url.Parse(uri)
1✔
184
                if err != nil {
2✔
185
                        return nil, fmt.Errorf("Error parsing %s argument: %w", FlagNameIdentityUri, err)
1✔
186
                }
1✔
187
                return identityUri, nil
×
188
        }
189

190
        value := config.Auth.Config["uri"]
1✔
191
        uri, valid := value.(string)
1✔
192
        if valid && uri != "" {
2✔
193
                identityUri, err := url.Parse(uri)
1✔
194
                if err != nil {
2✔
195
                        return nil, fmt.Errorf("Error parsing identity uri config: %w", err)
1✔
196
                }
1✔
197
                return identityUri, nil
×
198
        }
199
        identityUri, err := url.Parse(fmt.Sprintf("%s://%s/identity_", baseUri.Scheme, baseUri.Host))
1✔
200
        if err != nil {
1✔
201
                return nil, fmt.Errorf("Error parsing identity uri: %w", err)
×
202
        }
×
203
        return identityUri, nil
1✔
204
}
205

206
func (b CommandBuilder) parseUriArgument(context *CommandExecContext) (*url.URL, error) {
1✔
207
        uriFlag := context.String(FlagNameUri)
1✔
208
        if uriFlag == "" {
2✔
209
                return nil, nil
1✔
210
        }
1✔
211
        uriArgument, err := url.Parse(uriFlag)
1✔
212
        if err != nil {
1✔
NEW
213
                return nil, fmt.Errorf("Error parsing %s argument: %w", FlagNameUri, err)
×
214
        }
×
215
        return uriArgument, nil
1✔
216
}
217

218
func (b CommandBuilder) getValue(parameter parser.Parameter, context *CommandExecContext, config config.Config) string {
1✔
219
        value := context.String(parameter.Name)
1✔
220
        if value != "" {
2✔
221
                return value
1✔
222
        }
1✔
223
        value = config.Parameter[parameter.Name]
1✔
224
        if value != "" {
2✔
225
                return value
1✔
226
        }
1✔
227
        value = config.Header[parameter.Name]
1✔
228
        if value != "" {
1✔
229
                return value
×
230
        }
×
231
        if parameter.DefaultValue != nil {
2✔
232
                return fmt.Sprintf("%v", parameter.DefaultValue)
1✔
233
        }
1✔
234
        return ""
1✔
235
}
236

237
func (b CommandBuilder) validateArguments(context *CommandExecContext, parameters []parser.Parameter, config config.Config) error {
1✔
238
        err := errors.New("Invalid arguments:")
1✔
239
        result := true
1✔
240
        for _, parameter := range parameters {
2✔
241
                value := b.getValue(parameter, context, config)
1✔
242
                if parameter.Required && value == "" {
2✔
243
                        result = false
1✔
244
                        err = fmt.Errorf("%w\n  Argument --%s is missing", err, parameter.Name)
1✔
245
                }
1✔
246
                if value != "" && len(parameter.AllowedValues) > 0 {
2✔
247
                        valid := false
1✔
248
                        for _, allowedValue := range parameter.AllowedValues {
2✔
249
                                if fmt.Sprintf("%v", allowedValue) == value {
2✔
250
                                        valid = true
1✔
251
                                        break
1✔
252
                                }
253
                        }
254
                        if !valid {
2✔
255
                                allowedValues := b.formatAllowedValues(parameter.AllowedValues)
1✔
256
                                result = false
1✔
257
                                err = fmt.Errorf("%w\n  Argument value '%v' for --%s is invalid, allowed values: %s", err, value, parameter.Name, allowedValues)
1✔
258
                        }
1✔
259
                }
260
        }
261
        if result {
2✔
262
                return nil
1✔
263
        }
1✔
264
        return err
1✔
265
}
266

267
func (b CommandBuilder) logger(context executor.ExecutionContext, writer io.Writer) log.Logger {
1✔
268
        if context.Debug {
2✔
269
                return log.NewDebugLogger(writer)
1✔
270
        }
1✔
271
        return log.NewDefaultLogger(writer)
1✔
272
}
273

274
func (b CommandBuilder) outputWriter(writer io.Writer, format string, query string) output.OutputWriter {
1✔
275
        var transformer output.Transformer = output.NewDefaultTransformer()
1✔
276
        if query != "" {
2✔
277
                transformer = output.NewJmesPathTransformer(query)
1✔
278
        }
1✔
279
        if format == FlagValueOutputFormatText {
2✔
280
                return output.NewTextOutputWriter(writer, transformer)
1✔
281
        }
1✔
282
        return output.NewJsonOutputWriter(writer, transformer)
1✔
283
}
284

285
func (b CommandBuilder) executeCommand(context executor.ExecutionContext, writer output.OutputWriter, logger log.Logger) error {
1✔
286
        if context.Plugin != nil {
2✔
287
                return b.PluginExecutor.Call(context, writer, logger)
1✔
288
        }
1✔
289
        return b.Executor.Call(context, writer, logger)
1✔
290
}
291

292
func (b CommandBuilder) createOperationCommand(operation parser.Operation) *commandDefinition {
1✔
293
        parameters := operation.Parameters
1✔
294
        b.sortParameters(parameters)
1✔
295

1✔
296
        flagBuilder := newFlagBuilder()
1✔
297
        flagBuilder.AddFlags(b.createFlags(parameters))
1✔
298
        flagBuilder.AddDefaultFlags(true)
1✔
299
        flagBuilder.AddHelpFlag()
1✔
300

1✔
301
        return newCommandDefinition(operation.Name, operation.Summary, operation.Description, flagBuilder.ToList(), nil, subcommandHelpTemplate, operation.Hidden, func(context *CommandExecContext) error {
2✔
302
                profileName := context.String(FlagNameProfile)
1✔
303
                config := b.ConfigProvider.Config(profileName)
1✔
304
                if config == nil {
2✔
305
                        return fmt.Errorf("Could not find profile '%s'", profileName)
1✔
306
                }
1✔
307
                outputFormat, err := b.outputFormat(*config, context)
1✔
308
                if err != nil {
1✔
NEW
309
                        return err
×
NEW
310
                }
×
311
                query := context.String(FlagNameQuery)
1✔
312
                wait := context.String(FlagNameWait)
1✔
313
                waitTimeout := context.Int(FlagNameWaitTimeout)
1✔
314

1✔
315
                baseUri, err := b.createBaseUri(operation, *config, context)
1✔
316
                if err != nil {
1✔
NEW
317
                        return err
×
NEW
318
                }
×
319

320
                input := b.fileInput(context, operation.Parameters)
1✔
321
                if input == nil {
2✔
322
                        err = b.validateArguments(context, operation.Parameters, *config)
1✔
323
                        if err != nil {
2✔
324
                                return err
1✔
325
                        }
1✔
326
                }
327

328
                parameters, err := b.createExecutionParameters(context, config, operation)
1✔
329
                if err != nil {
2✔
330
                        return err
1✔
331
                }
1✔
332

333
                organization := context.String(FlagNameOrganization)
1✔
334
                if organization == "" {
2✔
335
                        organization = config.Organization
1✔
336
                }
1✔
337
                tenant := context.String(FlagNameTenant)
1✔
338
                if tenant == "" {
2✔
339
                        tenant = config.Tenant
1✔
340
                }
1✔
341
                insecure := context.Bool(FlagNameInsecure) || config.Insecure
1✔
342
                debug := context.Bool(FlagNameDebug) || config.Debug
1✔
343
                identityUri, err := b.createIdentityUri(context, *config, baseUri)
1✔
344
                if err != nil {
2✔
345
                        return err
1✔
346
                }
1✔
347

348
                executionContext := executor.NewExecutionContext(
1✔
349
                        organization,
1✔
350
                        tenant,
1✔
351
                        operation.Method,
1✔
352
                        baseUri,
1✔
353
                        operation.Route,
1✔
354
                        operation.ContentType,
1✔
355
                        input,
1✔
356
                        parameters,
1✔
357
                        config.Auth,
1✔
358
                        insecure,
1✔
359
                        debug,
1✔
360
                        *identityUri,
1✔
361
                        operation.Plugin)
1✔
362

1✔
363
                if wait != "" {
2✔
364
                        return b.executeWait(*executionContext, outputFormat, query, wait, waitTimeout)
1✔
365
                }
1✔
366
                return b.execute(*executionContext, outputFormat, query, nil)
1✔
367
        })
368
}
369

370
func (b CommandBuilder) executeWait(executionContext executor.ExecutionContext, outputFormat string, query string, wait string, waitTimeout int) error {
1✔
371
        logger := log.NewDefaultLogger(b.StdErr)
1✔
372
        outputWriter := output.NewMemoryOutputWriter()
1✔
373
        for start := time.Now(); time.Since(start) < time.Duration(waitTimeout)*time.Second; {
2✔
374
                err := b.execute(executionContext, "json", "", outputWriter)
1✔
375
                result, evaluationErr := b.evaluateWaitCondition(outputWriter.Response(), wait)
1✔
376
                if evaluationErr != nil {
2✔
377
                        return evaluationErr
1✔
378
                }
1✔
379
                if result {
2✔
380
                        resultWriter := b.outputWriter(b.StdOut, outputFormat, query)
1✔
381
                        _ = resultWriter.WriteResponse(outputWriter.Response())
1✔
382
                        return err
1✔
383
                }
1✔
384
                logger.LogError("Condition is not met yet. Waiting...\n")
1✔
385
                time.Sleep(1 * time.Second)
1✔
386
        }
387
        return errors.New("Timed out waiting for condition")
1✔
388
}
389

390
func (b CommandBuilder) evaluateWaitCondition(response output.ResponseInfo, wait string) (bool, error) {
1✔
391
        body, err := io.ReadAll(response.Body)
1✔
392
        if err != nil {
1✔
393
                return false, nil
×
394
        }
×
395
        var data interface{}
1✔
396
        err = json.Unmarshal(body, &data)
1✔
397
        if err != nil {
1✔
398
                return false, nil
×
399
        }
×
400
        transformer := output.NewJmesPathTransformer(wait)
1✔
401
        result, err := transformer.Execute(data)
1✔
402
        if err != nil {
2✔
403
                return false, err
1✔
404
        }
1✔
405
        value, ok := result.(bool)
1✔
406
        if !ok {
2✔
407
                return false, fmt.Errorf("Error in wait condition: JMESPath expression needs to return boolean")
1✔
408
        }
1✔
409
        return value, nil
1✔
410
}
411

412
func (b CommandBuilder) execute(executionContext executor.ExecutionContext, outputFormat string, query string, outputWriter output.OutputWriter) error {
1✔
413
        var wg sync.WaitGroup
1✔
414
        wg.Add(3)
1✔
415
        reader, writer := io.Pipe()
1✔
416
        go func() {
2✔
417
                defer wg.Done()
1✔
418
                defer reader.Close()
1✔
419
                _, _ = io.Copy(b.StdOut, reader)
1✔
420
        }()
1✔
421
        errorReader, errorWriter := io.Pipe()
1✔
422
        go func() {
2✔
423
                defer wg.Done()
1✔
424
                defer errorReader.Close()
1✔
425
                _, _ = io.Copy(b.StdErr, errorReader)
1✔
426
        }()
1✔
427

428
        var err error
1✔
429
        go func() {
2✔
430
                defer wg.Done()
1✔
431
                defer writer.Close()
1✔
432
                defer errorWriter.Close()
1✔
433
                if outputWriter == nil {
2✔
434
                        outputWriter = b.outputWriter(writer, outputFormat, query)
1✔
435
                }
1✔
436
                logger := b.logger(executionContext, errorWriter)
1✔
437
                err = b.executeCommand(executionContext, outputWriter, logger)
1✔
438
        }()
439

440
        wg.Wait()
1✔
441
        return err
1✔
442
}
443

444
func (b CommandBuilder) createCategoryCommand(operation parser.Operation) *commandDefinition {
1✔
445
        flagBuilder := newFlagBuilder()
1✔
446
        flagBuilder.AddHelpFlag()
1✔
447
        flagBuilder.AddVersionFlag(true)
1✔
448

1✔
449
        return newCommandDefinition(operation.Category.Name, "", operation.Category.Description, flagBuilder.ToList(), nil, "", false, nil)
1✔
450
}
1✔
451

452
func (b CommandBuilder) createServiceCommandCategory(operation parser.Operation, categories map[string]*commandDefinition) (bool, *commandDefinition) {
1✔
453
        isNewCategory := false
1✔
454
        operationCommand := b.createOperationCommand(operation)
1✔
455
        command, found := categories[operation.Category.Name]
1✔
456
        if !found {
2✔
457
                command = b.createCategoryCommand(operation)
1✔
458
                categories[operation.Category.Name] = command
1✔
459
                isNewCategory = true
1✔
460
        }
1✔
461
        command.Subcommands = append(command.Subcommands, operationCommand)
1✔
462
        return isNewCategory, command
1✔
463
}
464

465
func (b CommandBuilder) createServiceCommand(definition parser.Definition) *commandDefinition {
1✔
466
        categories := map[string]*commandDefinition{}
1✔
467
        commands := []*commandDefinition{}
1✔
468
        for _, operation := range definition.Operations {
2✔
469
                if operation.Category == nil {
2✔
470
                        command := b.createOperationCommand(operation)
1✔
471
                        commands = append(commands, command)
1✔
472
                        continue
1✔
473
                }
474
                isNewCategory, command := b.createServiceCommandCategory(operation, categories)
1✔
475
                if isNewCategory {
2✔
476
                        commands = append(commands, command)
1✔
477
                }
1✔
478
        }
479
        b.sort(commands)
1✔
480
        for _, command := range commands {
2✔
481
                b.sort(command.Subcommands)
1✔
482
        }
1✔
483

484
        flagBuilder := newFlagBuilder()
1✔
485
        flagBuilder.AddHelpFlag()
1✔
486
        flagBuilder.AddVersionFlag(true)
1✔
487

1✔
488
        return newCommandDefinition(definition.Name, "", definition.Description, flagBuilder.ToList(), commands, "", false, nil)
1✔
489
}
490

491
func (b CommandBuilder) createAutoCompleteEnableCommand() *commandDefinition {
1✔
492
        const shellFlagName = "shell"
1✔
493
        const fileFlagName = "file"
1✔
494

1✔
495
        flagBuilder := newFlagBuilder()
1✔
496
        flagBuilder.AddFlag(newFlagDefinition(shellFlagName, fmt.Sprintf("%s, %s", AutocompletePowershell, AutocompleteBash), "", FlagTypeString, "", nil, false, true))
1✔
497
        flagBuilder.AddFlag(newFlagDefinition(fileFlagName, "", "", FlagTypeString, "", nil, true, false))
1✔
498
        flagBuilder.AddHelpFlag()
1✔
499

1✔
500
        return newCommandDefinition("enable", "", "Enables auto complete in your shell", flagBuilder.ToList(), nil, "", false, func(context *CommandExecContext) error {
2✔
501
                shell := context.String(shellFlagName)
1✔
502
                filePath := context.String(fileFlagName)
1✔
503
                handler := newAutoCompleteHandler()
1✔
504
                output, err := handler.EnableCompleter(shell, filePath)
1✔
505
                if err != nil {
2✔
506
                        return err
1✔
507
                }
1✔
508
                fmt.Fprintln(b.StdOut, output)
1✔
509
                return nil
1✔
510
        })
511
}
512

513
func (b CommandBuilder) createAutoCompleteCompleteCommand(version string) *commandDefinition {
1✔
514
        const commandFlagName = "command"
1✔
515

1✔
516
        flagBuilder := newFlagBuilder()
1✔
517
        flagBuilder.AddFlag(newFlagDefinition(commandFlagName, "The command to autocomplete", "", FlagTypeString, "", nil, false, true))
1✔
518
        flagBuilder.AddHelpFlag()
1✔
519

1✔
520
        return newCommandDefinition("complete", "", "Returns the autocomplete suggestions", flagBuilder.ToList(), nil, "", false, func(context *CommandExecContext) error {
2✔
521
                commandText := context.String("command")
1✔
522
                exclude := []string{}
1✔
523
                for _, flagName := range FlagNamesPredefined {
2✔
524
                        exclude = append(exclude, "--"+flagName)
1✔
525
                }
1✔
526
                args := strings.Split(commandText, " ")
1✔
527
                definitions, err := b.loadAutocompleteDefinitions(args, version)
1✔
528
                if err != nil {
1✔
NEW
529
                        return err
×
NEW
530
                }
×
531
                commands := b.createServiceCommands(definitions)
1✔
532
                command := newCommandDefinition("uipath", "", "", nil, commands, "", false, nil)
1✔
533
                handler := newAutoCompleteHandler()
1✔
534
                words := handler.Find(commandText, command, exclude)
1✔
535
                for _, word := range words {
2✔
536
                        fmt.Fprintln(b.StdOut, word)
1✔
537
                }
1✔
538
                return nil
1✔
539
        })
540
}
541

542
func (b CommandBuilder) createAutoCompleteCommand(version string) *commandDefinition {
1✔
543
        flagBuilder := newFlagBuilder()
1✔
544
        flagBuilder.AddHelpFlag()
1✔
545

1✔
546
        subcommands := []*commandDefinition{
1✔
547
                b.createAutoCompleteEnableCommand(),
1✔
548
                b.createAutoCompleteCompleteCommand(version),
1✔
549
        }
1✔
550

1✔
551
        return newCommandDefinition("autocomplete", "", "Commands for autocompletion", flagBuilder.ToList(), subcommands, "", false, nil)
1✔
552
}
1✔
553

554
func (b CommandBuilder) createConfigCommand() *commandDefinition {
1✔
555
        const flagNameAuth = "auth"
1✔
556

1✔
557
        flagBuilder := newFlagBuilder()
1✔
558
        flagBuilder.AddFlag(newFlagDefinition(flagNameAuth, fmt.Sprintf("Authorization type: %s, %s, %s", CredentialsAuth, LoginAuth, PatAuth), "", FlagTypeString, "", nil, false, false))
1✔
559
        flagBuilder.AddFlag(newFlagDefinition(FlagNameProfile, "Profile to configure", "", FlagTypeString, "UIPATH_PROFILE", config.DefaultProfile, false, false))
1✔
560
        flagBuilder.AddHelpFlag()
1✔
561

1✔
562
        subcommands := []*commandDefinition{
1✔
563
                b.createConfigSetCommand(),
1✔
564
        }
1✔
565

1✔
566
        return newCommandDefinition("config", "", "Interactive command to configure the CLI", flagBuilder.ToList(), subcommands, "", false, func(context *CommandExecContext) error {
2✔
567
                auth := context.String(flagNameAuth)
1✔
568
                profileName := context.String(FlagNameProfile)
1✔
569
                handler := ConfigCommandHandler{
1✔
570
                        StdIn:          b.StdIn,
1✔
571
                        StdOut:         b.StdOut,
1✔
572
                        ConfigProvider: b.ConfigProvider,
1✔
573
                }
1✔
574
                return handler.Configure(auth, profileName)
1✔
575
        })
1✔
576
}
577

578
func (b CommandBuilder) createConfigSetCommand() *commandDefinition {
1✔
579
        const flagNameKey = "key"
1✔
580
        const flagNameValue = "value"
1✔
581

1✔
582
        flagBuilder := newFlagBuilder()
1✔
583
        flagBuilder.AddFlag(newFlagDefinition(flagNameKey, "The key", "", FlagTypeString, "", nil, false, true))
1✔
584
        flagBuilder.AddFlag(newFlagDefinition(flagNameValue, "The value to set", "", FlagTypeString, "", nil, false, true))
1✔
585
        flagBuilder.AddFlag(newFlagDefinition(FlagNameProfile, "Profile to configure", "", FlagTypeString, "UIPATH_PROFILE", config.DefaultProfile, false, false))
1✔
586
        flagBuilder.AddHelpFlag()
1✔
587

1✔
588
        return newCommandDefinition("set", "", "Set config parameters", flagBuilder.ToList(), nil, "", false, func(context *CommandExecContext) error {
2✔
589
                profileName := context.String(FlagNameProfile)
1✔
590
                key := context.String(flagNameKey)
1✔
591
                value := context.String(flagNameValue)
1✔
592
                handler := ConfigCommandHandler{
1✔
593
                        StdIn:          b.StdIn,
1✔
594
                        StdOut:         b.StdOut,
1✔
595
                        ConfigProvider: b.ConfigProvider,
1✔
596
                }
1✔
597
                return handler.Set(key, value, profileName)
1✔
598
        })
1✔
599
}
600

601
func (b CommandBuilder) loadDefinitions(args []string, version string) ([]parser.Definition, error) {
1✔
602
        if len(args) <= 1 || strings.HasPrefix(args[1], "-") {
2✔
603
                return b.DefinitionProvider.Index(version)
1✔
604
        }
1✔
605
        if len(args) > 1 && args[1] == "commands" {
2✔
606
                return b.loadAllDefinitions(version)
1✔
607
        }
1✔
608
        definition, err := b.DefinitionProvider.Load(args[1], version)
1✔
609
        if definition == nil {
2✔
610
                return nil, err
1✔
611
        }
1✔
612
        return []parser.Definition{*definition}, err
1✔
613
}
614

615
func (b CommandBuilder) loadAllDefinitions(version string) ([]parser.Definition, error) {
1✔
616
        all, err := b.DefinitionProvider.Index(version)
1✔
617
        if err != nil {
1✔
618
                return nil, err
×
619
        }
×
620
        definitions := []parser.Definition{}
1✔
621
        for _, d := range all {
2✔
622
                definition, err := b.DefinitionProvider.Load(d.Name, version)
1✔
623
                if err != nil {
1✔
624
                        return nil, err
×
625
                }
×
626
                if definition != nil {
2✔
627
                        definitions = append(definitions, *definition)
1✔
628
                }
1✔
629
        }
630
        return definitions, nil
1✔
631
}
632

633
func (b CommandBuilder) loadAutocompleteDefinitions(args []string, version string) ([]parser.Definition, error) {
1✔
634
        if len(args) <= 2 {
2✔
635
                return b.DefinitionProvider.Index(version)
1✔
636
        }
1✔
637
        return b.loadDefinitions(args, version)
1✔
638
}
639

640
func (b CommandBuilder) createShowCommand(definitions []parser.Definition) *commandDefinition {
1✔
641
        flagBuilder := newFlagBuilder()
1✔
642
        flagBuilder.AddHelpFlag()
1✔
643

1✔
644
        return newCommandDefinition("show", "", "Print available uipath CLI commands", flagBuilder.ToList(), nil, "", true, func(context *CommandExecContext) error {
2✔
645
                builder := newFlagBuilder()
1✔
646
                builder.AddDefaultFlags(false)
1✔
647
                builder.AddHelpFlag()
1✔
648

1✔
649
                handler := newShowCommandHandler()
1✔
650
                output, err := handler.Execute(definitions, builder.ToList())
1✔
651
                if err != nil {
1✔
NEW
652
                        return err
×
NEW
653
                }
×
654
                fmt.Fprintln(b.StdOut, output)
1✔
655
                return nil
1✔
656
        })
657
}
658

659
func (b CommandBuilder) createInspectCommand(definitions []parser.Definition) *commandDefinition {
1✔
660
        flagBuilder := newFlagBuilder()
1✔
661
        flagBuilder.AddHelpFlag()
1✔
662

1✔
663
        subcommands := []*commandDefinition{
1✔
664
                b.createShowCommand(definitions),
1✔
665
        }
1✔
666

1✔
667
        return newCommandDefinition("commands", "", "Command to inspect available uipath CLI operations", flagBuilder.ToList(), subcommands, "", true, nil)
1✔
668
}
1✔
669

670
func (b CommandBuilder) createServiceCommands(definitions []parser.Definition) []*commandDefinition {
1✔
671
        commands := []*commandDefinition{}
1✔
672
        for _, e := range definitions {
2✔
673
                command := b.createServiceCommand(e)
1✔
674
                commands = append(commands, command)
1✔
675
        }
1✔
676
        return commands
1✔
677
}
678

679
func (b CommandBuilder) parseArgument(args []string, name string) string {
1✔
680
        for i, arg := range args {
2✔
681
                if strings.TrimSpace(arg) == "--"+name {
2✔
682
                        if len(args) > i+1 {
2✔
683
                                return strings.TrimSpace(args[i+1])
1✔
684
                        }
1✔
685
                }
686
        }
687
        return ""
1✔
688
}
689

690
func (b CommandBuilder) versionFromProfile(profile string) string {
1✔
691
        config := b.ConfigProvider.Config(profile)
1✔
692
        if config == nil {
2✔
693
                return ""
1✔
694
        }
1✔
695
        return config.Version
1✔
696
}
697

698
func (b CommandBuilder) Create(args []string) ([]*commandDefinition, error) {
1✔
699
        version := b.parseArgument(args, FlagNameVersion)
1✔
700
        profile := b.parseArgument(args, FlagNameProfile)
1✔
701
        if version == "" && profile != "" {
2✔
702
                version = b.versionFromProfile(profile)
1✔
703
        }
1✔
704
        definitions, err := b.loadDefinitions(args, version)
1✔
705
        if err != nil {
2✔
706
                return nil, err
1✔
707
        }
1✔
708
        servicesCommands := b.createServiceCommands(definitions)
1✔
709
        autocompleteCommand := b.createAutoCompleteCommand(version)
1✔
710
        configCommand := b.createConfigCommand()
1✔
711
        inspectCommand := b.createInspectCommand(definitions)
1✔
712
        commands := append(servicesCommands, autocompleteCommand, configCommand, inspectCommand)
1✔
713
        return commands, nil
1✔
714
}
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