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

UiPath / uipathcli / 15180300709

22 May 2025 07:04AM UTC coverage: 90.76% (-0.05%) from 90.808%
15180300709

push

github

thschmitt
Improve configure command by providing tenant list

410 of 448 new or added lines in 17 files covered. (91.52%)

14 existing lines in 3 files now uncovered.

6915 of 7619 relevant lines covered (90.76%)

1.01 hits per line

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

95.22
/commandline/command_builder.go
1
package commandline
2

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

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

24
// The CommandBuilder is creating all available operations and arguments for the CLI.
25
type CommandBuilder struct {
26
        Input              stream.Stream
27
        StdIn              io.Reader
28
        StdOut             io.Writer
29
        StdErr             io.Writer
30
        ConfigProvider     config.ConfigProvider
31
        Executor           executor.Executor
32
        PluginExecutor     executor.Executor
33
        DefinitionProvider DefinitionProvider
34
        Authenticators     []auth.Authenticator
35
}
36

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

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

59
func (b CommandBuilder) createExecutionParameter(context *CommandExecContext, config *config.Config, param parser.Parameter) (*executor.ExecutionParameter, error) {
1✔
60
        typeConverter := newTypeConverter()
1✔
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
                return executor.NewExecutionParameter(param.FieldName, value, param.In), nil
1✔
67
        } else if context.IsSet(param.Name) {
2✔
68
                value, err := typeConverter.Convert(context.String(param.Name), param)
1✔
69
                if err != nil {
2✔
70
                        return nil, err
1✔
71
                }
1✔
72
                return executor.NewExecutionParameter(param.FieldName, value, param.In), nil
1✔
73
        } else if configValue, ok := config.Parameter[param.Name]; ok {
2✔
74
                value, err := typeConverter.Convert(configValue, param)
1✔
75
                if err != nil {
1✔
76
                        return nil, err
×
77
                }
×
78
                return executor.NewExecutionParameter(param.FieldName, value, param.In), nil
1✔
79
        } else if param.Required && param.DefaultValue != nil {
2✔
80
                return executor.NewExecutionParameter(param.FieldName, param.DefaultValue, param.In), nil
1✔
81
        }
1✔
82
        return nil, nil
1✔
83
}
84

85
func (b CommandBuilder) createExecutionParameters(context *CommandExecContext, config *config.Config, operation parser.Operation) (executor.ExecutionParameters, error) {
1✔
86
        parameters := []executor.ExecutionParameter{}
1✔
87
        for _, param := range operation.Parameters {
2✔
88
                parameter, err := b.createExecutionParameter(context, config, param)
1✔
89
                if err != nil {
2✔
90
                        return nil, err
1✔
91
                }
1✔
92
                if parameter != nil {
2✔
93
                        parameters = append(parameters, *parameter)
1✔
94
                }
1✔
95
        }
96
        return parameters, nil
1✔
97
}
98

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

109
func (b CommandBuilder) createFlags(parameters []parser.Parameter) []*FlagDefinition {
1✔
110
        flags := []*FlagDefinition{}
1✔
111
        for _, parameter := range parameters {
2✔
112
                formatter := newParameterFormatter(parameter)
1✔
113
                flagType := FlagTypeString
1✔
114
                if parameter.IsArray() {
2✔
115
                        flagType = FlagTypeStringArray
1✔
116
                }
1✔
117
                flag := NewFlag(parameter.Name, formatter.Description(), flagType).
1✔
118
                        WithHidden(parameter.Hidden)
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✔
145
                return "", fmt.Errorf("Invalid output format '%s', allowed values: %s, %s", outputFormat, FlagValueOutputFormatJson, FlagValueOutputFormatText)
×
146
        }
×
147
        return outputFormat, nil
1✔
148
}
149

150
func (b CommandBuilder) createOperationBaseUri(operation parser.Operation, context *CommandExecContext, config *config.Config) (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) createBaseUri(context *CommandExecContext, config *config.Config) (url.URL, error) {
1✔
163
        defaultUri, _ := url.Parse(parser.DefaultServerBaseUrl)
1✔
164

1✔
165
        uriArgument, err := b.parseUriArgument(context)
1✔
166
        if err != nil {
1✔
NEW
167
                return *defaultUri, err
×
NEW
168
        }
×
169

170
        builder := NewUriBuilder(*defaultUri)
1✔
171
        if config != nil {
2✔
172
                builder.OverrideUri(config.Uri)
1✔
173
        }
1✔
174
        builder.OverrideUri(uriArgument)
1✔
175
        return builder.Uri(), nil
1✔
176
}
177

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

188
        if config != nil {
2✔
189
                value := config.Auth.Config["uri"]
1✔
190
                uri, valid := value.(string)
1✔
191
                if valid && uri != "" {
2✔
192
                        identityUri, err := url.Parse(uri)
1✔
193
                        if err != nil {
2✔
194
                                return nil, fmt.Errorf("Error parsing identity uri config: %w", err)
1✔
195
                        }
1✔
NEW
196
                        return identityUri, nil
×
197
                }
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✔
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
        if parameter.DefaultValue != nil {
2✔
228
                return fmt.Sprint(parameter.DefaultValue)
1✔
229
        }
1✔
230
        return ""
1✔
231
}
232

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

263
func (b CommandBuilder) logger(debug bool, writer io.Writer) log.Logger {
1✔
264
        if debug {
2✔
265
                return log.NewDebugLogger(writer)
1✔
266
        }
1✔
267
        return log.NewDefaultLogger(writer)
1✔
268
}
269

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

281
func (b CommandBuilder) executeCommand(ctx executor.ExecutionContext, writer output.OutputWriter, logger log.Logger) error {
1✔
282
        if ctx.Plugin != nil {
2✔
283
                return b.PluginExecutor.Call(ctx, writer, logger)
1✔
284
        }
1✔
285
        return b.Executor.Call(ctx, writer, logger)
1✔
286
}
287

288
func (b CommandBuilder) operationId() string {
1✔
289
        bytes := make([]byte, 16)
1✔
290
        _, _ = rand.Read(bytes)
1✔
291
        return fmt.Sprintf("%x%x%x%x%x", bytes[0:4], bytes[4:6], bytes[6:8], bytes[8:10], bytes[10:])
1✔
292
}
1✔
293

294
func (b CommandBuilder) createOperationCommand(operation parser.Operation) *CommandDefinition {
1✔
295
        parameters := operation.Parameters
1✔
296
        b.sortParameters(parameters)
1✔
297

1✔
298
        flags := NewFlagBuilder().
1✔
299
                AddFlags(b.createFlags(parameters)).
1✔
300
                AddDefaultFlags(true).
1✔
301
                AddHelpFlag().
1✔
302
                Build()
1✔
303

1✔
304
        return NewCommand(operation.Name, operation.Summary, operation.Description).
1✔
305
                WithFlags(flags).
1✔
306
                WithHelpTemplate(OperationCommandHelpTemplate).
1✔
307
                WithHidden(operation.Hidden).
1✔
308
                WithAction(func(context *CommandExecContext) error {
2✔
309
                        profileName := context.String(FlagNameProfile)
1✔
310
                        config := b.ConfigProvider.Config(profileName)
1✔
311
                        if config == nil {
2✔
312
                                return fmt.Errorf("Could not find profile '%s'", profileName)
1✔
313
                        }
1✔
314
                        outputFormat, err := b.outputFormat(*config, context)
1✔
315
                        if err != nil {
1✔
316
                                return err
×
317
                        }
×
318
                        query := context.String(FlagNameQuery)
1✔
319
                        wait := context.String(FlagNameWait)
1✔
320
                        waitTimeout := context.Int(FlagNameWaitTimeout)
1✔
321

1✔
322
                        baseUri, err := b.createOperationBaseUri(operation, context, config)
1✔
323
                        if err != nil {
1✔
324
                                return err
×
325
                        }
×
326

327
                        input := b.fileInput(context, operation.Parameters)
1✔
328
                        if input == nil {
2✔
329
                                err = b.validateArguments(context, operation.Parameters, *config)
1✔
330
                                if err != nil {
2✔
331
                                        return err
1✔
332
                                }
1✔
333
                        }
334

335
                        parameters, err := b.createExecutionParameters(context, config, operation)
1✔
336
                        if err != nil {
2✔
337
                                return err
1✔
338
                        }
1✔
339

340
                        organization := context.String(FlagNameOrganization)
1✔
341
                        if organization == "" {
2✔
342
                                organization = config.Organization
1✔
343
                        }
1✔
344
                        tenant := context.String(FlagNameTenant)
1✔
345
                        if tenant == "" {
2✔
346
                                tenant = config.Tenant
1✔
347
                        }
1✔
348
                        timeout := time.Duration(context.Int(FlagNameCallTimeout)) * time.Second
1✔
349
                        if timeout < 0 {
2✔
350
                                return fmt.Errorf("Invalid value for '%s'", FlagNameCallTimeout)
1✔
351
                        }
1✔
352
                        maxAttempts := context.Int(FlagNameMaxAttempts)
1✔
353
                        if maxAttempts < 1 {
2✔
354
                                return fmt.Errorf("Invalid value for '%s'", FlagNameMaxAttempts)
1✔
355
                        }
1✔
356
                        identityUri, err := b.createIdentityUri(context, config, baseUri)
1✔
357
                        if err != nil {
2✔
358
                                return err
1✔
359
                        }
1✔
360

361
                        debug := b.debug(context, config)
1✔
362
                        operationId := b.operationId()
1✔
363
                        insecure := b.insecure(context, config)
1✔
364

1✔
365
                        executionContext := executor.NewExecutionContext(
1✔
366
                                organization,
1✔
367
                                tenant,
1✔
368
                                operation.Method,
1✔
369
                                baseUri,
1✔
370
                                operation.Route,
1✔
371
                                operation.ContentType,
1✔
372
                                input,
1✔
373
                                parameters,
1✔
374
                                config.Auth,
1✔
375
                                *identityUri,
1✔
376
                                operation.Plugin,
1✔
377
                                debug,
1✔
378
                                *executor.NewExecutionSettings(operationId, config.Header, timeout, maxAttempts, insecure),
1✔
379
                        )
1✔
380

1✔
381
                        if wait != "" {
2✔
382
                                return b.executeWait(*executionContext, outputFormat, query, wait, waitTimeout)
1✔
383
                        }
1✔
384
                        return b.execute(*executionContext, outputFormat, query, nil)
1✔
385
                })
386
}
387

388
func (b CommandBuilder) executeWait(ctx executor.ExecutionContext, outputFormat string, query string, wait string, waitTimeout int) error {
1✔
389
        logger := log.NewDefaultLogger(b.StdErr)
1✔
390
        outputWriter := output.NewMemoryOutputWriter()
1✔
391
        for start := time.Now(); time.Since(start) < time.Duration(waitTimeout)*time.Second; {
2✔
392
                err := b.execute(ctx, "json", "", outputWriter)
1✔
393
                result, evaluationErr := b.evaluateWaitCondition(outputWriter.Response(), wait)
1✔
394
                if evaluationErr != nil {
2✔
395
                        return evaluationErr
1✔
396
                }
1✔
397
                if result {
2✔
398
                        resultWriter := b.outputWriter(b.StdOut, outputFormat, query)
1✔
399
                        _ = resultWriter.WriteResponse(outputWriter.Response())
1✔
400
                        return err
1✔
401
                }
1✔
402
                logger.LogError("Condition is not met yet. Waiting...\n")
1✔
403
                time.Sleep(1 * time.Second)
1✔
404
        }
405
        return errors.New("Timed out waiting for condition")
1✔
406
}
407

408
func (b CommandBuilder) evaluateWaitCondition(response output.ResponseInfo, wait string) (bool, error) {
1✔
409
        body, err := io.ReadAll(response.Body)
1✔
410
        if err != nil {
1✔
411
                return false, nil
×
412
        }
×
413
        var data interface{}
1✔
414
        err = json.Unmarshal(body, &data)
1✔
415
        if err != nil {
1✔
416
                return false, nil
×
417
        }
×
418
        transformer := output.NewJmesPathTransformer(wait)
1✔
419
        result, err := transformer.Execute(data)
1✔
420
        if err != nil {
2✔
421
                return false, err
1✔
422
        }
1✔
423
        value, ok := result.(bool)
1✔
424
        if !ok {
2✔
425
                return false, errors.New("Error in wait condition: JMESPath expression needs to return boolean")
1✔
426
        }
1✔
427
        return value, nil
1✔
428
}
429

430
func (b CommandBuilder) execute(ctx executor.ExecutionContext, outputFormat string, query string, outputWriter output.OutputWriter) error {
1✔
431
        var wg sync.WaitGroup
1✔
432
        wg.Add(3)
1✔
433
        reader, writer := io.Pipe()
1✔
434
        go func() {
2✔
435
                defer wg.Done()
1✔
436
                defer func() { _ = reader.Close() }()
2✔
437
                _, _ = io.Copy(b.StdOut, reader)
1✔
438
        }()
439
        errorReader, errorWriter := io.Pipe()
1✔
440
        go func() {
2✔
441
                defer wg.Done()
1✔
442
                defer func() { _ = errorReader.Close() }()
2✔
443
                _, _ = io.Copy(b.StdErr, errorReader)
1✔
444
        }()
445

446
        var err error
1✔
447
        go func() {
2✔
448
                defer wg.Done()
1✔
449
                defer func() { _ = writer.Close() }()
2✔
450
                defer func() { _ = errorWriter.Close() }()
2✔
451
                if outputWriter == nil {
2✔
452
                        outputWriter = b.outputWriter(writer, outputFormat, query)
1✔
453
                }
1✔
454
                logger := b.logger(ctx.Debug, errorWriter)
1✔
455
                err = b.executeCommand(ctx, outputWriter, logger)
1✔
456
        }()
457

458
        wg.Wait()
1✔
459
        return err
1✔
460
}
461

462
func (b CommandBuilder) createCategoryCommand(operation parser.Operation) *CommandDefinition {
1✔
463
        flags := NewFlagBuilder().
1✔
464
                AddHelpFlag().
1✔
465
                AddServiceVersionFlag(true).
1✔
466
                Build()
1✔
467

1✔
468
        return NewCommand(operation.Category.Name, operation.Category.Summary, operation.Category.Description).
1✔
469
                WithFlags(flags)
1✔
470
}
1✔
471

472
func (b CommandBuilder) createServiceCommandCategory(operation parser.Operation, categories map[string]*CommandDefinition) (bool, *CommandDefinition) {
1✔
473
        isNewCategory := false
1✔
474
        operationCommand := b.createOperationCommand(operation)
1✔
475
        command, found := categories[operation.Category.Name]
1✔
476
        if !found {
2✔
477
                command = b.createCategoryCommand(operation)
1✔
478
                categories[operation.Category.Name] = command
1✔
479
                isNewCategory = true
1✔
480
        }
1✔
481
        command.Subcommands = append(command.Subcommands, operationCommand)
1✔
482
        return isNewCategory, command
1✔
483
}
484

485
func (b CommandBuilder) createServiceCommand(definition parser.Definition) *CommandDefinition {
1✔
486
        categories := map[string]*CommandDefinition{}
1✔
487
        commands := []*CommandDefinition{}
1✔
488
        for _, operation := range definition.Operations {
2✔
489
                if operation.Category == nil {
2✔
490
                        command := b.createOperationCommand(operation)
1✔
491
                        commands = append(commands, command)
1✔
492
                        continue
1✔
493
                }
494
                isNewCategory, command := b.createServiceCommandCategory(operation, categories)
1✔
495
                if isNewCategory {
2✔
496
                        commands = append(commands, command)
1✔
497
                }
1✔
498
        }
499
        b.sort(commands)
1✔
500
        for _, command := range commands {
2✔
501
                b.sort(command.Subcommands)
1✔
502
        }
1✔
503

504
        flags := NewFlagBuilder().
1✔
505
                AddHelpFlag().
1✔
506
                AddServiceVersionFlag(true).
1✔
507
                Build()
1✔
508

1✔
509
        return NewCommand(definition.Name, definition.Summary, definition.Description).
1✔
510
                WithFlags(flags).
1✔
511
                WithSubcommands(commands)
1✔
512
}
513

514
func (b CommandBuilder) createAutoCompleteEnableCommand() *CommandDefinition {
1✔
515
        const shellFlagName = "shell"
1✔
516
        const fileFlagName = "file"
1✔
517

1✔
518
        flags := NewFlagBuilder().
1✔
519
                AddFlag(NewFlag(shellFlagName, fmt.Sprintf("%s, %s", AutocompletePowershell, AutocompleteBash), FlagTypeString).
1✔
520
                        WithRequired(true)).
1✔
521
                AddFlag(NewFlag(fileFlagName, "The profile file path", FlagTypeString).
1✔
522
                        WithHidden(true)).
1✔
523
                AddHelpFlag().
1✔
524
                Build()
1✔
525

1✔
526
        return NewCommand("enable", "Enable auto complete", "Enables auto complete in your shell").
1✔
527
                WithFlags(flags).
1✔
528
                WithAction(func(context *CommandExecContext) error {
2✔
529
                        shell := context.String(shellFlagName)
1✔
530
                        filePath := context.String(fileFlagName)
1✔
531
                        handler := newAutoCompleteHandler()
1✔
532
                        output, err := handler.EnableCompleter(shell, filePath)
1✔
533
                        if err != nil {
2✔
534
                                return err
1✔
535
                        }
1✔
536
                        _, err = fmt.Fprintln(b.StdOut, output)
1✔
537
                        return err
1✔
538
                })
539
}
540

541
func (b CommandBuilder) createAutoCompleteCompleteCommand(serviceVersion string) *CommandDefinition {
1✔
542
        const commandFlagName = "command"
1✔
543

1✔
544
        flags := NewFlagBuilder().
1✔
545
                AddFlag(NewFlag(commandFlagName, "The command to autocomplete", FlagTypeString).
1✔
546
                        WithRequired(true)).
1✔
547
                AddHelpFlag().
1✔
548
                Build()
1✔
549

1✔
550
        return NewCommand("complete", "Autocomplete suggestions", "Returns the autocomplete suggestions").
1✔
551
                WithFlags(flags).
1✔
552
                WithAction(func(context *CommandExecContext) error {
2✔
553
                        commandText := context.String(commandFlagName)
1✔
554
                        exclude := []string{}
1✔
555
                        for _, flagName := range FlagNamesPredefined {
2✔
556
                                exclude = append(exclude, "--"+flagName)
1✔
557
                        }
1✔
558
                        args := strings.Split(commandText, " ")
1✔
559
                        definitions, err := b.loadAutocompleteDefinitions(args, serviceVersion)
1✔
560
                        if err != nil {
1✔
561
                                return err
×
562
                        }
×
563
                        commands := b.createServiceCommands(definitions)
1✔
564
                        command := NewCommand("uipath", "", "").
1✔
565
                                WithSubcommands(commands)
1✔
566
                        handler := newAutoCompleteHandler()
1✔
567
                        words := handler.Find(commandText, command, exclude)
1✔
568
                        for _, word := range words {
2✔
569
                                _, _ = fmt.Fprintln(b.StdOut, word)
1✔
570
                        }
1✔
571
                        return nil
1✔
572
                })
573
}
574

575
func (b CommandBuilder) createAutoCompleteCommand(serviceVersion string) *CommandDefinition {
1✔
576
        flags := NewFlagBuilder().
1✔
577
                AddHelpFlag().
1✔
578
                Build()
1✔
579

1✔
580
        subcommands := []*CommandDefinition{
1✔
581
                b.createAutoCompleteEnableCommand(),
1✔
582
                b.createAutoCompleteCompleteCommand(serviceVersion),
1✔
583
        }
1✔
584

1✔
585
        return NewCommand("autocomplete", "Autocompletion", "Commands for autocompletion").
1✔
586
                WithFlags(flags).
1✔
587
                WithSubcommands(subcommands)
1✔
588
}
1✔
589

590
func (b CommandBuilder) createConfigCommand() *CommandDefinition {
1✔
591
        const flagNameAuth = "auth"
1✔
592

1✔
593
        flags := NewFlagBuilder().
1✔
594
                AddFlag(NewFlag(flagNameAuth, fmt.Sprintf("Authorization type: %s, %s, %s", config.AuthTypeCredentials, config.AuthTypeLogin, config.AuthTypePat), FlagTypeString)).
1✔
595
                AddProfileFlag().
1✔
596
                AddUriFlag().
1✔
597
                AddDebugFlag().
1✔
598
                AddInsecureFlag().
1✔
599
                AddIdentityUriFlag().
1✔
600
                AddHelpFlag().
1✔
601
                Build()
1✔
602

1✔
603
        subcommands := []*CommandDefinition{
1✔
604
                b.createConfigSetCommand(),
1✔
605
                b.createCacheCommand(),
1✔
606
                b.createOfflineCommand(),
1✔
607
        }
1✔
608

1✔
609
        return NewCommand("config", "Interactive Configuration", "Interactive command to configure the CLI").
1✔
610
                WithFlags(flags).
1✔
611
                WithSubcommands(subcommands).
1✔
612
                WithAction(func(context *CommandExecContext) error {
2✔
613
                        auth := context.String(flagNameAuth)
1✔
614
                        profileName := context.String(FlagNameProfile)
1✔
615
                        config := b.ConfigProvider.Config(profileName)
1✔
616

1✔
617
                        baseUri, err := b.createBaseUri(context, config)
1✔
618
                        if err != nil {
1✔
NEW
619
                                return err
×
NEW
620
                        }
×
621
                        identityUri, err := b.createIdentityUri(context, config, baseUri)
1✔
622
                        if err != nil {
1✔
NEW
623
                                return err
×
NEW
624
                        }
×
625

626
                        debug := b.debug(context, config)
1✔
627
                        operationId := b.operationId()
1✔
628
                        insecure := b.insecure(context, config)
1✔
629

1✔
630
                        logger := b.logger(debug, b.StdErr)
1✔
631
                        handler := newConfigCommandHandler(
1✔
632
                                b.StdIn,
1✔
633
                                b.StdOut,
1✔
634
                                logger,
1✔
635
                                b.ConfigProvider,
1✔
636
                                b.Authenticators)
1✔
637
                        input := newConfigCommandInput(
1✔
638
                                auth,
1✔
639
                                profileName,
1✔
640
                                debug,
1✔
641
                                operationId,
1✔
642
                                insecure,
1✔
643
                                baseUri,
1✔
644
                                *identityUri,
1✔
645
                        )
1✔
646
                        return handler.Configure(*input)
1✔
647
                })
648
}
649

650
func (b CommandBuilder) createConfigSetCommand() *CommandDefinition {
1✔
651
        const flagNameKey = "key"
1✔
652
        const flagNameValue = "value"
1✔
653

1✔
654
        flags := NewFlagBuilder().
1✔
655
                AddFlag(NewFlag(flagNameKey, "The key", FlagTypeString).
1✔
656
                        WithRequired(true)).
1✔
657
                AddFlag(NewFlag(flagNameValue, "The value to set", FlagTypeString).
1✔
658
                        WithRequired(true)).
1✔
659
                AddProfileFlag().
1✔
660
                AddHelpFlag().
1✔
661
                Build()
1✔
662

1✔
663
        return NewCommand("set", "Set config parameters", "Set config parameters").
1✔
664
                WithFlags(flags).
1✔
665
                WithAction(func(context *CommandExecContext) error {
2✔
666
                        profileName := context.String(FlagNameProfile)
1✔
667
                        key := context.String(flagNameKey)
1✔
668
                        value := context.String(flagNameValue)
1✔
669
                        handler := newConfigSetCommandHandler(b.StdOut, b.ConfigProvider)
1✔
670
                        return handler.Set(key, value, profileName)
1✔
671
                })
1✔
672
}
673

674
func (b CommandBuilder) debug(context *CommandExecContext, config *config.Config) bool {
1✔
675
        debug := context.Bool(FlagNameDebug)
1✔
676
        if !debug && config != nil {
2✔
677
                return config.Debug
1✔
678
        }
1✔
679
        return debug
1✔
680
}
681

682
func (b CommandBuilder) insecure(context *CommandExecContext, config *config.Config) bool {
1✔
683
        insecure := context.Bool(FlagNameInsecure)
1✔
684
        if !insecure && config != nil {
2✔
685
                return config.Insecure
1✔
686
        }
1✔
687
        return insecure
1✔
688
}
689

690
func (b CommandBuilder) createCacheClearCommand() *CommandDefinition {
1✔
691
        flags := NewFlagBuilder().
1✔
692
                AddHelpFlag().
1✔
693
                Build()
1✔
694

1✔
695
        return NewCommand("clear", "Clears the cache", "Clears the cache").
1✔
696
                WithFlags(flags).
1✔
697
                WithAction(func(context *CommandExecContext) error {
2✔
698
                        handler := newCacheClearCommandHandler(b.StdOut)
1✔
699
                        return handler.Clear()
1✔
700
                })
1✔
701
}
702

703
func (b CommandBuilder) createCacheCommand() *CommandDefinition {
1✔
704
        flags := NewFlagBuilder().
1✔
705
                AddHelpFlag().
1✔
706
                Build()
1✔
707

1✔
708
        subcommands := []*CommandDefinition{
1✔
709
                b.createCacheClearCommand(),
1✔
710
        }
1✔
711

1✔
712
        return NewCommand("cache", "Caching-related commands", "Caching-related commands").
1✔
713
                WithFlags(flags).
1✔
714
                WithSubcommands(subcommands)
1✔
715
}
1✔
716

717
func (b CommandBuilder) createOfflineCommand() *CommandDefinition {
1✔
718
        flags := NewFlagBuilder().
1✔
719
                AddHelpFlag().
1✔
720
                Build()
1✔
721

1✔
722
        return NewCommand("offline", "Downloads external dependencies", "Downloads external dependencies for offline mode").
1✔
723
                WithFlags(flags).
1✔
724
                WithAction(func(context *CommandExecContext) error {
2✔
725
                        logger := b.logger(false, b.StdErr)
1✔
726
                        handler := newOfflineCommandHandler(b.StdOut, logger)
1✔
727
                        return handler.Execute()
1✔
728
                })
1✔
729
}
730

731
func (b CommandBuilder) loadDefinitions(args []string, serviceVersion string) ([]parser.Definition, error) {
1✔
732
        if len(args) <= 1 || strings.HasPrefix(args[1], "-") {
2✔
733
                return b.DefinitionProvider.Index(serviceVersion)
1✔
734
        }
1✔
735
        if len(args) > 1 && args[1] == "commands" {
2✔
736
                return b.loadAllDefinitions(serviceVersion)
1✔
737
        }
1✔
738
        definition, err := b.DefinitionProvider.Load(args[1], serviceVersion)
1✔
739
        if definition == nil {
2✔
740
                return nil, err
1✔
741
        }
1✔
742
        return []parser.Definition{*definition}, err
1✔
743
}
744

745
func (b CommandBuilder) loadAllDefinitions(serviceVersion string) ([]parser.Definition, error) {
1✔
746
        all, err := b.DefinitionProvider.Index(serviceVersion)
1✔
747
        if err != nil {
1✔
748
                return nil, err
×
749
        }
×
750
        definitions := []parser.Definition{}
1✔
751
        for _, d := range all {
2✔
752
                definition, err := b.DefinitionProvider.Load(d.Name, serviceVersion)
1✔
753
                if err != nil {
1✔
754
                        return nil, err
×
755
                }
×
756
                if definition != nil {
2✔
757
                        definitions = append(definitions, *definition)
1✔
758
                }
1✔
759
        }
760
        return definitions, nil
1✔
761
}
762

763
func (b CommandBuilder) loadAutocompleteDefinitions(args []string, serviceVersion string) ([]parser.Definition, error) {
1✔
764
        if len(args) <= 2 {
2✔
765
                return b.DefinitionProvider.Index(serviceVersion)
1✔
766
        }
1✔
767
        return b.loadDefinitions(args, serviceVersion)
1✔
768
}
769

770
func (b CommandBuilder) createShowCommand(definitions []parser.Definition) *CommandDefinition {
1✔
771
        flags := NewFlagBuilder().
1✔
772
                AddHelpFlag().
1✔
773
                Build()
1✔
774

1✔
775
        return NewCommand("show", "Print CLI commands", "Print available uipath CLI commands").
1✔
776
                WithFlags(flags).
1✔
777
                WithHidden(true).
1✔
778
                WithAction(func(context *CommandExecContext) error {
2✔
779
                        defaultFlags := NewFlagBuilder().
1✔
780
                                AddDefaultFlags(false).
1✔
781
                                AddHelpFlag().
1✔
782
                                Build()
1✔
783

1✔
784
                        handler := newShowCommandHandler()
1✔
785
                        output, err := handler.Execute(definitions, defaultFlags)
1✔
786
                        if err != nil {
1✔
787
                                return err
×
788
                        }
×
789
                        _, err = fmt.Fprintln(b.StdOut, output)
1✔
790
                        return err
1✔
791
                })
792
}
793

794
func (b CommandBuilder) createInspectCommand(definitions []parser.Definition) *CommandDefinition {
1✔
795
        flags := NewFlagBuilder().
1✔
796
                AddHelpFlag().
1✔
797
                Build()
1✔
798

1✔
799
        subcommands := []*CommandDefinition{
1✔
800
                b.createShowCommand(definitions),
1✔
801
        }
1✔
802

1✔
803
        return NewCommand("commands", "Inspect available CLI operations", "Command to inspect available uipath CLI operations").
1✔
804
                WithFlags(flags).
1✔
805
                WithSubcommands(subcommands).
1✔
806
                WithHidden(true)
1✔
807
}
1✔
808

809
func (b CommandBuilder) createServiceCommands(definitions []parser.Definition) []*CommandDefinition {
1✔
810
        commands := []*CommandDefinition{}
1✔
811
        for _, e := range definitions {
2✔
812
                command := b.createServiceCommand(e)
1✔
813
                commands = append(commands, command)
1✔
814
        }
1✔
815
        return commands
1✔
816
}
817

818
func (b CommandBuilder) parseArgument(args []string, name string) string {
1✔
819
        for i, arg := range args {
2✔
820
                if strings.TrimSpace(arg) == "--"+name {
2✔
821
                        if len(args) > i+1 {
2✔
822
                                return strings.TrimSpace(args[i+1])
1✔
823
                        }
1✔
824
                }
825
        }
826
        return ""
1✔
827
}
828

829
func (b CommandBuilder) serviceVersionFromProfile(profile string) string {
1✔
830
        config := b.ConfigProvider.Config(profile)
1✔
831
        if config == nil {
2✔
832
                return ""
1✔
833
        }
1✔
834
        return config.ServiceVersion
1✔
835
}
836

837
func (b CommandBuilder) Create(args []string) ([]*CommandDefinition, error) {
1✔
838
        serviceVersion := b.parseArgument(args, FlagNameServiceVersion)
1✔
839
        profile := b.parseArgument(args, FlagNameProfile)
1✔
840
        if serviceVersion == "" && profile != "" {
2✔
841
                serviceVersion = b.serviceVersionFromProfile(profile)
1✔
842
        }
1✔
843
        definitions, err := b.loadDefinitions(args, serviceVersion)
1✔
844
        if err != nil {
2✔
845
                return nil, err
1✔
846
        }
1✔
847
        servicesCommands := b.createServiceCommands(definitions)
1✔
848
        autocompleteCommand := b.createAutoCompleteCommand(serviceVersion)
1✔
849
        configCommand := b.createConfigCommand()
1✔
850
        inspectCommand := b.createInspectCommand(definitions)
1✔
851
        commands := append(servicesCommands, autocompleteCommand, configCommand, inspectCommand)
1✔
852
        return commands, nil
1✔
853
}
854

855
func NewCommandBuilder(
856
        input stream.Stream,
857
        stdIn io.Reader,
858
        stdOut io.Writer,
859
        stdErr io.Writer,
860
        configProvider config.ConfigProvider,
861
        executor executor.Executor,
862
        pluginExecutor executor.Executor,
863
        definitionProvider DefinitionProvider,
864
        authenticators []auth.Authenticator,
865
) *CommandBuilder {
1✔
866
        return &CommandBuilder{
1✔
867
                input,
1✔
868
                stdIn,
1✔
869
                stdOut,
1✔
870
                stdErr,
1✔
871
                configProvider,
1✔
872
                executor,
1✔
873
                pluginExecutor,
1✔
874
                definitionProvider,
1✔
875
                authenticators,
1✔
876
        }
1✔
877
}
1✔
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

© 2026 Coveralls, Inc