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

UiPath / uipathcli / 11216909938

07 Oct 2024 01:45PM UTC coverage: 90.416% (-0.03%) from 90.447%
11216909938

push

github

web-flow
Merge pull request #123 from UiPath/feature/command-builder

Create command abstraction and split up command builder

460 of 475 new or added lines in 8 files covered. (96.84%)

1 existing line in 1 file now uncovered.

4264 of 4716 relevant lines covered (90.42%)

1.02 hits per line

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

94.99
/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
// The CommandBuilder is creating all available operations and arguments for the CLI.
23
type CommandBuilder struct {
24
        Input              utils.Stream
25
        StdIn              io.Reader
26
        StdOut             io.Writer
27
        StdErr             io.Writer
28
        ConfigProvider     config.ConfigProvider
29
        Executor           executor.Executor
30
        PluginExecutor     executor.Executor
31
        DefinitionProvider DefinitionProvider
32
}
33

34
func (b CommandBuilder) sort(commands []*CommandDefinition) {
1✔
35
        sort.Slice(commands, func(i, j int) bool {
2✔
36
                return commands[i].Name < commands[j].Name
1✔
37
        })
1✔
38
}
39

40
func (b CommandBuilder) fileInput(context *CommandExecContext, parameters []parser.Parameter) utils.Stream {
1✔
41
        value := context.String(FlagNameFile)
1✔
42
        if value == "" {
2✔
43
                return nil
1✔
44
        }
1✔
45
        if value == FlagValueFromStdIn {
2✔
46
                return b.Input
1✔
47
        }
1✔
48
        for _, param := range parameters {
2✔
49
                if strings.EqualFold(param.FieldName, FlagNameFile) {
2✔
50
                        return nil
1✔
51
                }
1✔
52
        }
53
        return utils.NewFileStream(value)
1✔
54
}
55

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

1✔
59
        parameters := []executor.ExecutionParameter{}
1✔
60
        for _, param := range operation.Parameters {
2✔
61
                if context.IsSet(param.Name) && param.IsArray() {
2✔
62
                        value, err := typeConverter.ConvertArray(context.StringSlice(param.Name), param)
1✔
63
                        if err != nil {
2✔
64
                                return nil, err
1✔
65
                        }
1✔
66
                        parameter := executor.NewExecutionParameter(param.FieldName, value, param.In)
1✔
67
                        parameters = append(parameters, *parameter)
1✔
68
                } else if context.IsSet(param.Name) {
2✔
69
                        value, err := typeConverter.Convert(context.String(param.Name), param)
1✔
70
                        if err != nil {
2✔
71
                                return nil, err
1✔
72
                        }
1✔
73
                        parameter := executor.NewExecutionParameter(param.FieldName, value, param.In)
1✔
74
                        parameters = append(parameters, *parameter)
1✔
75
                } else if configValue, ok := config.Parameter[param.Name]; ok {
2✔
76
                        value, err := typeConverter.Convert(configValue, param)
1✔
77
                        if err != nil {
1✔
78
                                return nil, err
×
79
                        }
×
80
                        parameter := executor.NewExecutionParameter(param.FieldName, value, param.In)
1✔
81
                        parameters = append(parameters, *parameter)
1✔
82
                } else if param.Required && param.DefaultValue != nil {
2✔
83
                        parameter := executor.NewExecutionParameter(param.FieldName, param.DefaultValue, param.In)
1✔
84
                        parameters = append(parameters, *parameter)
1✔
85
                }
1✔
86
        }
87
        parameters = append(parameters, b.createExecutionParametersFromConfigMap(config.Header, parser.ParameterInHeader)...)
1✔
88
        return parameters, nil
1✔
89
}
90

91
func (b CommandBuilder) createExecutionParametersFromConfigMap(params map[string]string, in string) executor.ExecutionParameters {
1✔
92
        parameters := []executor.ExecutionParameter{}
1✔
93
        for key, value := range params {
2✔
94
                parameter := executor.NewExecutionParameter(key, value, in)
1✔
95
                parameters = append(parameters, *parameter)
1✔
96
        }
1✔
97
        return parameters
1✔
98
}
99

100
func (b CommandBuilder) formatAllowedValues(values []interface{}) string {
1✔
101
        result := ""
1✔
102
        separator := ""
1✔
103
        for _, value := range values {
2✔
104
                result += fmt.Sprintf("%s%v", separator, value)
1✔
105
                separator = ", "
1✔
106
        }
1✔
107
        return result
1✔
108
}
109

110
func (b CommandBuilder) createFlags(parameters []parser.Parameter) []*FlagDefinition {
1✔
111
        flags := []*FlagDefinition{}
1✔
112
        for _, parameter := range parameters {
2✔
113
                formatter := newParameterFormatter(parameter)
1✔
114
                flagType := FlagTypeString
1✔
115
                if parameter.IsArray() {
2✔
116
                        flagType = FlagTypeStringArray
1✔
117
                }
1✔
118
                flag := NewFlag(parameter.Name, formatter.Description(), flagType)
1✔
119
                flags = append(flags, flag)
1✔
120
        }
121
        return flags
1✔
122
}
123

124
func (b CommandBuilder) sortParameters(parameters []parser.Parameter) {
1✔
125
        sort.Slice(parameters, func(i, j int) bool {
2✔
126
                if parameters[i].Required && !parameters[j].Required {
2✔
127
                        return true
1✔
128
                }
1✔
129
                if !parameters[i].Required && parameters[j].Required {
2✔
130
                        return false
1✔
131
                }
1✔
132
                return parameters[i].Name < parameters[j].Name
1✔
133
        })
134
}
135

136
func (b CommandBuilder) outputFormat(config config.Config, context *CommandExecContext) (string, error) {
1✔
137
        outputFormat := context.String(FlagNameOutputFormat)
1✔
138
        if outputFormat == "" {
2✔
139
                outputFormat = config.Output
1✔
140
        }
1✔
141
        if outputFormat == "" {
2✔
142
                outputFormat = FlagValueOutputFormatJson
1✔
143
        }
1✔
144
        if outputFormat != FlagValueOutputFormatJson && outputFormat != FlagValueOutputFormatText {
1✔
NEW
145
                return "", fmt.Errorf("Invalid output format '%s', allowed values: %s, %s", outputFormat, FlagValueOutputFormatJson, FlagValueOutputFormatText)
×
UNCOV
146
        }
×
147
        return outputFormat, nil
1✔
148
}
149

150
func (b CommandBuilder) createBaseUri(operation parser.Operation, config config.Config, context *CommandExecContext) (url.URL, error) {
1✔
151
        uriArgument, err := b.parseUriArgument(context)
1✔
152
        if err != nil {
1✔
153
                return operation.BaseUri, err
×
154
        }
×
155

156
        builder := NewUriBuilder(operation.BaseUri)
1✔
157
        builder.OverrideUri(config.Uri)
1✔
158
        builder.OverrideUri(uriArgument)
1✔
159
        return builder.Uri(), nil
1✔
160
}
161

162
func (b CommandBuilder) createIdentityUri(context *CommandExecContext, config config.Config, baseUri url.URL) (*url.URL, error) {
1✔
163
        uri := context.String(FlagNameIdentityUri)
1✔
164
        if uri != "" {
2✔
165
                identityUri, err := url.Parse(uri)
1✔
166
                if err != nil {
2✔
167
                        return nil, fmt.Errorf("Error parsing %s argument: %w", FlagNameIdentityUri, err)
1✔
168
                }
1✔
169
                return identityUri, nil
×
170
        }
171

172
        value := config.Auth.Config["uri"]
1✔
173
        uri, valid := value.(string)
1✔
174
        if valid && uri != "" {
2✔
175
                identityUri, err := url.Parse(uri)
1✔
176
                if err != nil {
2✔
177
                        return nil, fmt.Errorf("Error parsing identity uri config: %w", err)
1✔
178
                }
1✔
179
                return identityUri, nil
×
180
        }
181
        identityUri, err := url.Parse(fmt.Sprintf("%s://%s/identity_", baseUri.Scheme, baseUri.Host))
1✔
182
        if err != nil {
1✔
183
                return nil, fmt.Errorf("Error parsing identity uri: %w", err)
×
184
        }
×
185
        return identityUri, nil
1✔
186
}
187

188
func (b CommandBuilder) parseUriArgument(context *CommandExecContext) (*url.URL, error) {
1✔
189
        uriFlag := context.String(FlagNameUri)
1✔
190
        if uriFlag == "" {
2✔
191
                return nil, nil
1✔
192
        }
1✔
193
        uriArgument, err := url.Parse(uriFlag)
1✔
194
        if err != nil {
1✔
NEW
195
                return nil, fmt.Errorf("Error parsing %s argument: %w", FlagNameUri, err)
×
196
        }
×
197
        return uriArgument, nil
1✔
198
}
199

200
func (b CommandBuilder) getValue(parameter parser.Parameter, context *CommandExecContext, config config.Config) string {
1✔
201
        value := context.String(parameter.Name)
1✔
202
        if value != "" {
2✔
203
                return value
1✔
204
        }
1✔
205
        value = config.Parameter[parameter.Name]
1✔
206
        if value != "" {
2✔
207
                return value
1✔
208
        }
1✔
209
        value = config.Header[parameter.Name]
1✔
210
        if value != "" {
1✔
211
                return value
×
212
        }
×
213
        if parameter.DefaultValue != nil {
2✔
214
                return fmt.Sprintf("%v", parameter.DefaultValue)
1✔
215
        }
1✔
216
        return ""
1✔
217
}
218

219
func (b CommandBuilder) validateArguments(context *CommandExecContext, parameters []parser.Parameter, config config.Config) error {
1✔
220
        err := errors.New("Invalid arguments:")
1✔
221
        result := true
1✔
222
        for _, parameter := range parameters {
2✔
223
                value := b.getValue(parameter, context, config)
1✔
224
                if parameter.Required && value == "" {
2✔
225
                        result = false
1✔
226
                        err = fmt.Errorf("%w\n  Argument --%s is missing", err, parameter.Name)
1✔
227
                }
1✔
228
                if value != "" && len(parameter.AllowedValues) > 0 {
2✔
229
                        valid := false
1✔
230
                        for _, allowedValue := range parameter.AllowedValues {
2✔
231
                                if fmt.Sprintf("%v", allowedValue) == value {
2✔
232
                                        valid = true
1✔
233
                                        break
1✔
234
                                }
235
                        }
236
                        if !valid {
2✔
237
                                allowedValues := b.formatAllowedValues(parameter.AllowedValues)
1✔
238
                                result = false
1✔
239
                                err = fmt.Errorf("%w\n  Argument value '%v' for --%s is invalid, allowed values: %s", err, value, parameter.Name, allowedValues)
1✔
240
                        }
1✔
241
                }
242
        }
243
        if result {
2✔
244
                return nil
1✔
245
        }
1✔
246
        return err
1✔
247
}
248

249
func (b CommandBuilder) logger(context executor.ExecutionContext, writer io.Writer) log.Logger {
1✔
250
        if context.Debug {
2✔
251
                return log.NewDebugLogger(writer)
1✔
252
        }
1✔
253
        return log.NewDefaultLogger(writer)
1✔
254
}
255

256
func (b CommandBuilder) outputWriter(writer io.Writer, format string, query string) output.OutputWriter {
1✔
257
        var transformer output.Transformer = output.NewDefaultTransformer()
1✔
258
        if query != "" {
2✔
259
                transformer = output.NewJmesPathTransformer(query)
1✔
260
        }
1✔
261
        if format == FlagValueOutputFormatText {
2✔
262
                return output.NewTextOutputWriter(writer, transformer)
1✔
263
        }
1✔
264
        return output.NewJsonOutputWriter(writer, transformer)
1✔
265
}
266

267
func (b CommandBuilder) executeCommand(context executor.ExecutionContext, writer output.OutputWriter, logger log.Logger) error {
1✔
268
        if context.Plugin != nil {
2✔
269
                return b.PluginExecutor.Call(context, writer, logger)
1✔
270
        }
1✔
271
        return b.Executor.Call(context, writer, logger)
1✔
272
}
273

274
func (b CommandBuilder) createOperationCommand(operation parser.Operation) *CommandDefinition {
1✔
275
        parameters := operation.Parameters
1✔
276
        b.sortParameters(parameters)
1✔
277

1✔
278
        flags := NewFlagBuilder().
1✔
279
                AddFlags(b.createFlags(parameters)).
1✔
280
                AddDefaultFlags(true).
1✔
281
                AddHelpFlag().
1✔
282
                Build()
1✔
283

1✔
284
        return NewCommand(operation.Name, operation.Summary, operation.Description).
1✔
285
                WithFlags(flags).
1✔
286
                WithHelpTemplate(OperationCommandHelpTemplate).
1✔
287
                WithHidden(operation.Hidden).
1✔
288
                WithAction(func(context *CommandExecContext) error {
2✔
289
                        profileName := context.String(FlagNameProfile)
1✔
290
                        config := b.ConfigProvider.Config(profileName)
1✔
291
                        if config == nil {
2✔
292
                                return fmt.Errorf("Could not find profile '%s'", profileName)
1✔
293
                        }
1✔
294
                        outputFormat, err := b.outputFormat(*config, context)
1✔
295
                        if err != nil {
1✔
296
                                return err
×
297
                        }
×
298
                        query := context.String(FlagNameQuery)
1✔
299
                        wait := context.String(FlagNameWait)
1✔
300
                        waitTimeout := context.Int(FlagNameWaitTimeout)
1✔
301

1✔
302
                        baseUri, err := b.createBaseUri(operation, *config, context)
1✔
303
                        if err != nil {
1✔
304
                                return err
×
305
                        }
×
306

307
                        input := b.fileInput(context, operation.Parameters)
1✔
308
                        if input == nil {
2✔
309
                                err = b.validateArguments(context, operation.Parameters, *config)
1✔
310
                                if err != nil {
2✔
311
                                        return err
1✔
312
                                }
1✔
313
                        }
314

315
                        parameters, err := b.createExecutionParameters(context, config, operation)
1✔
316
                        if err != nil {
2✔
317
                                return err
1✔
318
                        }
1✔
319

320
                        organization := context.String(FlagNameOrganization)
1✔
321
                        if organization == "" {
2✔
322
                                organization = config.Organization
1✔
323
                        }
1✔
324
                        tenant := context.String(FlagNameTenant)
1✔
325
                        if tenant == "" {
2✔
326
                                tenant = config.Tenant
1✔
327
                        }
1✔
328
                        insecure := context.Bool(FlagNameInsecure) || config.Insecure
1✔
329
                        debug := context.Bool(FlagNameDebug) || config.Debug
1✔
330
                        identityUri, err := b.createIdentityUri(context, *config, baseUri)
1✔
331
                        if err != nil {
2✔
332
                                return err
1✔
333
                        }
1✔
334

335
                        executionContext := executor.NewExecutionContext(
1✔
336
                                organization,
1✔
337
                                tenant,
1✔
338
                                operation.Method,
1✔
339
                                baseUri,
1✔
340
                                operation.Route,
1✔
341
                                operation.ContentType,
1✔
342
                                input,
1✔
343
                                parameters,
1✔
344
                                config.Auth,
1✔
345
                                insecure,
1✔
346
                                debug,
1✔
347
                                *identityUri,
1✔
348
                                operation.Plugin)
1✔
349

1✔
350
                        if wait != "" {
2✔
351
                                return b.executeWait(*executionContext, outputFormat, query, wait, waitTimeout)
1✔
352
                        }
1✔
353
                        return b.execute(*executionContext, outputFormat, query, nil)
1✔
354
                })
355
}
356

357
func (b CommandBuilder) executeWait(executionContext executor.ExecutionContext, outputFormat string, query string, wait string, waitTimeout int) error {
1✔
358
        logger := log.NewDefaultLogger(b.StdErr)
1✔
359
        outputWriter := output.NewMemoryOutputWriter()
1✔
360
        for start := time.Now(); time.Since(start) < time.Duration(waitTimeout)*time.Second; {
2✔
361
                err := b.execute(executionContext, "json", "", outputWriter)
1✔
362
                result, evaluationErr := b.evaluateWaitCondition(outputWriter.Response(), wait)
1✔
363
                if evaluationErr != nil {
2✔
364
                        return evaluationErr
1✔
365
                }
1✔
366
                if result {
2✔
367
                        resultWriter := b.outputWriter(b.StdOut, outputFormat, query)
1✔
368
                        _ = resultWriter.WriteResponse(outputWriter.Response())
1✔
369
                        return err
1✔
370
                }
1✔
371
                logger.LogError("Condition is not met yet. Waiting...\n")
1✔
372
                time.Sleep(1 * time.Second)
1✔
373
        }
374
        return errors.New("Timed out waiting for condition")
1✔
375
}
376

377
func (b CommandBuilder) evaluateWaitCondition(response output.ResponseInfo, wait string) (bool, error) {
1✔
378
        body, err := io.ReadAll(response.Body)
1✔
379
        if err != nil {
1✔
380
                return false, nil
×
381
        }
×
382
        var data interface{}
1✔
383
        err = json.Unmarshal(body, &data)
1✔
384
        if err != nil {
1✔
385
                return false, nil
×
386
        }
×
387
        transformer := output.NewJmesPathTransformer(wait)
1✔
388
        result, err := transformer.Execute(data)
1✔
389
        if err != nil {
2✔
390
                return false, err
1✔
391
        }
1✔
392
        value, ok := result.(bool)
1✔
393
        if !ok {
2✔
394
                return false, fmt.Errorf("Error in wait condition: JMESPath expression needs to return boolean")
1✔
395
        }
1✔
396
        return value, nil
1✔
397
}
398

399
func (b CommandBuilder) execute(executionContext executor.ExecutionContext, outputFormat string, query string, outputWriter output.OutputWriter) error {
1✔
400
        var wg sync.WaitGroup
1✔
401
        wg.Add(3)
1✔
402
        reader, writer := io.Pipe()
1✔
403
        go func() {
2✔
404
                defer wg.Done()
1✔
405
                defer reader.Close()
1✔
406
                _, _ = io.Copy(b.StdOut, reader)
1✔
407
        }()
1✔
408
        errorReader, errorWriter := io.Pipe()
1✔
409
        go func() {
2✔
410
                defer wg.Done()
1✔
411
                defer errorReader.Close()
1✔
412
                _, _ = io.Copy(b.StdErr, errorReader)
1✔
413
        }()
1✔
414

415
        var err error
1✔
416
        go func() {
2✔
417
                defer wg.Done()
1✔
418
                defer writer.Close()
1✔
419
                defer errorWriter.Close()
1✔
420
                if outputWriter == nil {
2✔
421
                        outputWriter = b.outputWriter(writer, outputFormat, query)
1✔
422
                }
1✔
423
                logger := b.logger(executionContext, errorWriter)
1✔
424
                err = b.executeCommand(executionContext, outputWriter, logger)
1✔
425
        }()
426

427
        wg.Wait()
1✔
428
        return err
1✔
429
}
430

431
func (b CommandBuilder) createCategoryCommand(operation parser.Operation) *CommandDefinition {
1✔
432
        flags := NewFlagBuilder().
1✔
433
                AddHelpFlag().
1✔
434
                AddVersionFlag(true).
1✔
435
                Build()
1✔
436

1✔
437
        return NewCommand(operation.Category.Name, operation.Category.Summary, operation.Category.Description).
1✔
438
                WithFlags(flags)
1✔
439
}
1✔
440

441
func (b CommandBuilder) createServiceCommandCategory(operation parser.Operation, categories map[string]*CommandDefinition) (bool, *CommandDefinition) {
1✔
442
        isNewCategory := false
1✔
443
        operationCommand := b.createOperationCommand(operation)
1✔
444
        command, found := categories[operation.Category.Name]
1✔
445
        if !found {
2✔
446
                command = b.createCategoryCommand(operation)
1✔
447
                categories[operation.Category.Name] = command
1✔
448
                isNewCategory = true
1✔
449
        }
1✔
450
        command.Subcommands = append(command.Subcommands, operationCommand)
1✔
451
        return isNewCategory, command
1✔
452
}
453

454
func (b CommandBuilder) createServiceCommand(definition parser.Definition) *CommandDefinition {
1✔
455
        categories := map[string]*CommandDefinition{}
1✔
456
        commands := []*CommandDefinition{}
1✔
457
        for _, operation := range definition.Operations {
2✔
458
                if operation.Category == nil {
2✔
459
                        command := b.createOperationCommand(operation)
1✔
460
                        commands = append(commands, command)
1✔
461
                        continue
1✔
462
                }
463
                isNewCategory, command := b.createServiceCommandCategory(operation, categories)
1✔
464
                if isNewCategory {
2✔
465
                        commands = append(commands, command)
1✔
466
                }
1✔
467
        }
468
        b.sort(commands)
1✔
469
        for _, command := range commands {
2✔
470
                b.sort(command.Subcommands)
1✔
471
        }
1✔
472

473
        flags := NewFlagBuilder().
1✔
474
                AddHelpFlag().
1✔
475
                AddVersionFlag(true).
1✔
476
                Build()
1✔
477

1✔
478
        return NewCommand(definition.Name, definition.Summary, definition.Description).
1✔
479
                WithFlags(flags).
1✔
480
                WithSubcommands(commands)
1✔
481
}
482

483
func (b CommandBuilder) createAutoCompleteEnableCommand() *CommandDefinition {
1✔
484
        const shellFlagName = "shell"
1✔
485
        const fileFlagName = "file"
1✔
486

1✔
487
        flags := NewFlagBuilder().
1✔
488
                AddFlag(NewFlag(shellFlagName, fmt.Sprintf("%s, %s", AutocompletePowershell, AutocompleteBash), FlagTypeString).
1✔
489
                        WithRequired(true)).
1✔
490
                AddFlag(NewFlag(fileFlagName, "The profile file path", FlagTypeString).
1✔
491
                        WithHidden(true)).
1✔
492
                AddHelpFlag().
1✔
493
                Build()
1✔
494

1✔
495
        return NewCommand("enable", "Enable auto complete", "Enables auto complete in your shell").
1✔
496
                WithFlags(flags).
1✔
497
                WithAction(func(context *CommandExecContext) error {
2✔
498
                        shell := context.String(shellFlagName)
1✔
499
                        filePath := context.String(fileFlagName)
1✔
500
                        handler := newAutoCompleteHandler()
1✔
501
                        output, err := handler.EnableCompleter(shell, filePath)
1✔
502
                        if err != nil {
2✔
503
                                return err
1✔
504
                        }
1✔
505
                        fmt.Fprintln(b.StdOut, output)
1✔
506
                        return nil
1✔
507
                })
508
}
509

510
func (b CommandBuilder) createAutoCompleteCompleteCommand(version string) *CommandDefinition {
1✔
511
        const commandFlagName = "command"
1✔
512

1✔
513
        flags := NewFlagBuilder().
1✔
514
                AddFlag(NewFlag(commandFlagName, "The command to autocomplete", FlagTypeString).
1✔
515
                        WithRequired(true)).
1✔
516
                AddHelpFlag().
1✔
517
                Build()
1✔
518

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

544
func (b CommandBuilder) createAutoCompleteCommand(version string) *CommandDefinition {
1✔
545
        flags := NewFlagBuilder().
1✔
546
                AddHelpFlag().
1✔
547
                Build()
1✔
548

1✔
549
        subcommands := []*CommandDefinition{
1✔
550
                b.createAutoCompleteEnableCommand(),
1✔
551
                b.createAutoCompleteCompleteCommand(version),
1✔
552
        }
1✔
553

1✔
554
        return NewCommand("autocomplete", "Autocompletion", "Commands for autocompletion").
1✔
555
                WithFlags(flags).
1✔
556
                WithSubcommands(subcommands)
1✔
557
}
1✔
558

559
func (b CommandBuilder) createConfigCommand() *CommandDefinition {
1✔
560
        const flagNameAuth = "auth"
1✔
561

1✔
562
        flags := NewFlagBuilder().
1✔
563
                AddFlag(NewFlag(flagNameAuth, fmt.Sprintf("Authorization type: %s, %s, %s", CredentialsAuth, LoginAuth, PatAuth), FlagTypeString)).
1✔
564
                AddFlag(NewFlag(FlagNameProfile, "Profile to configure", FlagTypeString).
1✔
565
                        WithEnvVarName("UIPATH_PROFILE").
1✔
566
                        WithDefaultValue(config.DefaultProfile)).
1✔
567
                AddHelpFlag().
1✔
568
                Build()
1✔
569

1✔
570
        subcommands := []*CommandDefinition{
1✔
571
                b.createConfigSetCommand(),
1✔
572
        }
1✔
573

1✔
574
        return NewCommand("config", "Interactive Configuration", "Interactive command to configure the CLI").
1✔
575
                WithFlags(flags).
1✔
576
                WithSubcommands(subcommands).
1✔
577
                WithAction(func(context *CommandExecContext) error {
2✔
578
                        auth := context.String(flagNameAuth)
1✔
579
                        profileName := context.String(FlagNameProfile)
1✔
580
                        handler := newConfigCommandHandler(b.StdIn, b.StdOut, b.ConfigProvider)
1✔
581
                        return handler.Configure(auth, profileName)
1✔
582
                })
1✔
583
}
584

585
func (b CommandBuilder) createConfigSetCommand() *CommandDefinition {
1✔
586
        const flagNameKey = "key"
1✔
587
        const flagNameValue = "value"
1✔
588

1✔
589
        flags := NewFlagBuilder().
1✔
590
                AddFlag(NewFlag(flagNameKey, "The key", FlagTypeString).
1✔
591
                        WithRequired(true)).
1✔
592
                AddFlag(NewFlag(flagNameValue, "The value to set", FlagTypeString).
1✔
593
                        WithRequired(true)).
1✔
594
                AddFlag(NewFlag(FlagNameProfile, "Profile to configure", FlagTypeString).
1✔
595
                        WithEnvVarName("UIPATH_PROFILE").
1✔
596
                        WithDefaultValue(config.DefaultProfile)).
1✔
597
                AddHelpFlag().
1✔
598
                Build()
1✔
599

1✔
600
        return NewCommand("set", "Set config parameters", "Set config parameters").
1✔
601
                WithFlags(flags).
1✔
602
                WithAction(func(context *CommandExecContext) error {
2✔
603
                        profileName := context.String(FlagNameProfile)
1✔
604
                        key := context.String(flagNameKey)
1✔
605
                        value := context.String(flagNameValue)
1✔
606
                        handler := newConfigCommandHandler(b.StdIn, b.StdOut, b.ConfigProvider)
1✔
607
                        return handler.Set(key, value, profileName)
1✔
608
                })
1✔
609
}
610

611
func (b CommandBuilder) loadDefinitions(args []string, version string) ([]parser.Definition, error) {
1✔
612
        if len(args) <= 1 || strings.HasPrefix(args[1], "-") {
2✔
613
                return b.DefinitionProvider.Index(version)
1✔
614
        }
1✔
615
        if len(args) > 1 && args[1] == "commands" {
2✔
616
                return b.loadAllDefinitions(version)
1✔
617
        }
1✔
618
        definition, err := b.DefinitionProvider.Load(args[1], version)
1✔
619
        if definition == nil {
2✔
620
                return nil, err
1✔
621
        }
1✔
622
        return []parser.Definition{*definition}, err
1✔
623
}
624

625
func (b CommandBuilder) loadAllDefinitions(version string) ([]parser.Definition, error) {
1✔
626
        all, err := b.DefinitionProvider.Index(version)
1✔
627
        if err != nil {
1✔
628
                return nil, err
×
629
        }
×
630
        definitions := []parser.Definition{}
1✔
631
        for _, d := range all {
2✔
632
                definition, err := b.DefinitionProvider.Load(d.Name, version)
1✔
633
                if err != nil {
1✔
634
                        return nil, err
×
635
                }
×
636
                if definition != nil {
2✔
637
                        definitions = append(definitions, *definition)
1✔
638
                }
1✔
639
        }
640
        return definitions, nil
1✔
641
}
642

643
func (b CommandBuilder) loadAutocompleteDefinitions(args []string, version string) ([]parser.Definition, error) {
1✔
644
        if len(args) <= 2 {
2✔
645
                return b.DefinitionProvider.Index(version)
1✔
646
        }
1✔
647
        return b.loadDefinitions(args, version)
1✔
648
}
649

650
func (b CommandBuilder) createShowCommand(definitions []parser.Definition) *CommandDefinition {
1✔
651
        flags := NewFlagBuilder().
1✔
652
                AddHelpFlag().
1✔
653
                Build()
1✔
654

1✔
655
        return NewCommand("show", "Print CLI commands", "Print available uipath CLI commands").
1✔
656
                WithFlags(flags).
1✔
657
                WithHidden(true).
1✔
658
                WithAction(func(context *CommandExecContext) error {
2✔
659
                        defaultFlags := NewFlagBuilder().
1✔
660
                                AddDefaultFlags(false).
1✔
661
                                AddHelpFlag().
1✔
662
                                Build()
1✔
663

1✔
664
                        handler := newShowCommandHandler()
1✔
665
                        output, err := handler.Execute(definitions, defaultFlags)
1✔
666
                        if err != nil {
1✔
NEW
667
                                return err
×
NEW
668
                        }
×
669
                        fmt.Fprintln(b.StdOut, output)
1✔
670
                        return nil
1✔
671
                })
672
}
673

674
func (b CommandBuilder) createInspectCommand(definitions []parser.Definition) *CommandDefinition {
1✔
675
        flags := NewFlagBuilder().
1✔
676
                AddHelpFlag().
1✔
677
                Build()
1✔
678

1✔
679
        subcommands := []*CommandDefinition{
1✔
680
                b.createShowCommand(definitions),
1✔
681
        }
1✔
682

1✔
683
        return NewCommand("commands", "Inspect available CLI operations", "Command to inspect available uipath CLI operations").
1✔
684
                WithFlags(flags).
1✔
685
                WithSubcommands(subcommands).
1✔
686
                WithHidden(true)
1✔
687
}
1✔
688

689
func (b CommandBuilder) createServiceCommands(definitions []parser.Definition) []*CommandDefinition {
1✔
690
        commands := []*CommandDefinition{}
1✔
691
        for _, e := range definitions {
2✔
692
                command := b.createServiceCommand(e)
1✔
693
                commands = append(commands, command)
1✔
694
        }
1✔
695
        return commands
1✔
696
}
697

698
func (b CommandBuilder) parseArgument(args []string, name string) string {
1✔
699
        for i, arg := range args {
2✔
700
                if strings.TrimSpace(arg) == "--"+name {
2✔
701
                        if len(args) > i+1 {
2✔
702
                                return strings.TrimSpace(args[i+1])
1✔
703
                        }
1✔
704
                }
705
        }
706
        return ""
1✔
707
}
708

709
func (b CommandBuilder) versionFromProfile(profile string) string {
1✔
710
        config := b.ConfigProvider.Config(profile)
1✔
711
        if config == nil {
2✔
712
                return ""
1✔
713
        }
1✔
714
        return config.Version
1✔
715
}
716

717
func (b CommandBuilder) Create(args []string) ([]*CommandDefinition, error) {
1✔
718
        version := b.parseArgument(args, FlagNameVersion)
1✔
719
        profile := b.parseArgument(args, FlagNameProfile)
1✔
720
        if version == "" && profile != "" {
2✔
721
                version = b.versionFromProfile(profile)
1✔
722
        }
1✔
723
        definitions, err := b.loadDefinitions(args, version)
1✔
724
        if err != nil {
2✔
725
                return nil, err
1✔
726
        }
1✔
727
        servicesCommands := b.createServiceCommands(definitions)
1✔
728
        autocompleteCommand := b.createAutoCompleteCommand(version)
1✔
729
        configCommand := b.createConfigCommand()
1✔
730
        inspectCommand := b.createInspectCommand(definitions)
1✔
731
        commands := append(servicesCommands, autocompleteCommand, configCommand, inspectCommand)
1✔
732
        return commands, nil
1✔
733
}
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