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

UiPath / uipathcli / 18678624158

21 Oct 2025 09:01AM UTC coverage: 90.797% (-0.08%) from 90.88%
18678624158

push

github

thschmitt
Improve configure command by providing tenant list

499 of 548 new or added lines in 18 files covered. (91.06%)

17 existing lines in 4 files now uncovered.

7044 of 7758 relevant lines covered (90.8%)

1.02 hits per line

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

95.29
/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
        StdOut             io.Writer
28
        StdErr             io.Writer
29
        ConfigProvider     config.ConfigProvider
30
        Executor           executor.Executor
31
        PluginExecutor     executor.Executor
32
        DefinitionProvider DefinitionProvider
33
        Authenticators     []auth.Authenticator
34
}
35

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

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

58
func (b CommandBuilder) createExecutionParameter(context *CommandExecContext, config *config.Config, param parser.Parameter) (*executor.ExecutionParameter, error) {
1✔
59
        typeConverter := newTypeConverter()
1✔
60
        if context.IsSet(param.Name) && param.IsArray() {
2✔
61
                value, err := typeConverter.ConvertArray(context.StringSlice(param.Name), param)
1✔
62
                if err != nil {
2✔
63
                        return nil, err
1✔
64
                }
1✔
65
                return executor.NewExecutionParameter(param.FieldName, value, param.In), nil
1✔
66
        } else if context.IsSet(param.Name) {
2✔
67
                value, err := typeConverter.Convert(context.String(param.Name), param)
1✔
68
                if err != nil {
2✔
69
                        return nil, err
1✔
70
                }
1✔
71
                return executor.NewExecutionParameter(param.FieldName, value, param.In), nil
1✔
72
        } else if configValue, ok := config.Parameter[param.Name]; ok {
2✔
73
                value, err := typeConverter.Convert(configValue, param)
1✔
74
                if err != nil {
1✔
75
                        return nil, err
×
76
                }
×
77
                return executor.NewExecutionParameter(param.FieldName, value, param.In), nil
1✔
78
        } else if param.Required && param.DefaultValue != nil {
2✔
79
                return executor.NewExecutionParameter(param.FieldName, param.DefaultValue, param.In), nil
1✔
80
        }
1✔
81
        return nil, nil
1✔
82
}
83

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

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

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

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

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

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

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

161
func (b CommandBuilder) createBaseUri(context *CommandExecContext, config *config.Config) (url.URL, error) {
1✔
162
        defaultUri, _ := url.Parse(parser.DefaultServerBaseUrl)
1✔
163

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

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

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

187
        if config != nil {
2✔
188
                uri = config.AuthUri()
1✔
189
        }
1✔
190
        if uri != "" {
2✔
191
                identityUri, err := url.Parse(uri)
1✔
192
                if err != nil {
2✔
193
                        return nil, fmt.Errorf("Error parsing identity uri config: %w", err)
1✔
194
                }
1✔
195
                return identityUri, nil
×
196
        }
197
        identityUri, err := url.Parse(fmt.Sprintf("%s://%s/identity_", baseUri.Scheme, baseUri.Host))
1✔
198
        if err != nil {
1✔
199
                return nil, fmt.Errorf("Error parsing identity uri: %w", err)
×
200
        }
×
201
        return identityUri, nil
1✔
202
}
203

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

216
func (b CommandBuilder) getValue(parameter parser.Parameter, context *CommandExecContext, config config.Config) string {
1✔
217
        value := context.String(parameter.Name)
1✔
218
        if value != "" {
2✔
219
                return value
1✔
220
        }
1✔
221
        value = config.Parameter[parameter.Name]
1✔
222
        if value != "" {
2✔
223
                return value
1✔
224
        }
1✔
225
        if parameter.DefaultValue != nil {
2✔
226
                return fmt.Sprint(parameter.DefaultValue)
1✔
227
        }
1✔
228
        return ""
1✔
229
}
230

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

456
        wg.Wait()
1✔
457
        return err
1✔
458
}
459

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1✔
652
        flags := NewFlagBuilder().
1✔
653
                AddFlag(NewFlag(flagNameKey, "The key\n\n"+b.configSetKeyAllowedValues(), FlagTypeString).
1✔
654
                        WithRequired(true)).
1✔
655
                AddFlag(NewFlag(flagNameValue, "The value to set", FlagTypeString).
1✔
656
                        WithRequired(true)).
1✔
657
                AddProfileFlag().
1✔
658
                AddHelpFlag().
1✔
659
                Build()
1✔
660

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

672
func (b CommandBuilder) configSetKeyAllowedValues() string {
1✔
673
        builder := strings.Builder{}
1✔
674
        builder.WriteString("Allowed values:")
1✔
675
        for _, value := range ConfigKeys {
2✔
676
                if strings.HasSuffix(value, ".") {
2✔
677
                        value = value + "<key>"
1✔
678
                }
1✔
679
                builder.WriteString("\n- " + value)
1✔
680
        }
681
        return builder.String()
1✔
682
}
683

684
func (b CommandBuilder) debug(context *CommandExecContext, config *config.Config) bool {
1✔
685
        debug := context.Bool(FlagNameDebug)
1✔
686
        if !debug && config != nil {
2✔
687
                return config.Debug
1✔
688
        }
1✔
689
        return debug
1✔
690
}
691

692
func (b CommandBuilder) insecure(context *CommandExecContext, config *config.Config) bool {
1✔
693
        insecure := context.Bool(FlagNameInsecure)
1✔
694
        if !insecure && config != nil {
2✔
695
                return config.Insecure
1✔
696
        }
1✔
697
        return insecure
1✔
698
}
699

700
func (b CommandBuilder) createCacheClearCommand() *CommandDefinition {
1✔
701
        flags := NewFlagBuilder().
1✔
702
                AddHelpFlag().
1✔
703
                Build()
1✔
704

1✔
705
        return NewCommand("clear", "Clears the cache", "Clears the cache").
1✔
706
                WithFlags(flags).
1✔
707
                WithAction(func(context *CommandExecContext) error {
2✔
708
                        handler := newCacheClearCommandHandler(b.StdOut)
1✔
709
                        return handler.Clear()
1✔
710
                })
1✔
711
}
712

713
func (b CommandBuilder) createCacheCommand() *CommandDefinition {
1✔
714
        flags := NewFlagBuilder().
1✔
715
                AddHelpFlag().
1✔
716
                Build()
1✔
717

1✔
718
        subcommands := []*CommandDefinition{
1✔
719
                b.createCacheClearCommand(),
1✔
720
        }
1✔
721

1✔
722
        return NewCommand("cache", "Caching-related commands", "Caching-related commands").
1✔
723
                WithFlags(flags).
1✔
724
                WithSubcommands(subcommands)
1✔
725
}
1✔
726

727
func (b CommandBuilder) createOfflineCommand() *CommandDefinition {
1✔
728
        flags := NewFlagBuilder().
1✔
729
                AddHelpFlag().
1✔
730
                Build()
1✔
731

1✔
732
        return NewCommand("offline", "Downloads external dependencies", "Downloads external dependencies for offline mode").
1✔
733
                WithFlags(flags).
1✔
734
                WithAction(func(context *CommandExecContext) error {
2✔
735
                        logger := b.logger(false, b.StdErr)
1✔
736
                        handler := newOfflineCommandHandler(b.StdOut, logger)
1✔
737
                        return handler.Execute()
1✔
738
                })
1✔
739
}
740

741
func (b CommandBuilder) loadDefinitions(args []string, serviceVersion string) ([]parser.Definition, error) {
1✔
742
        if len(args) <= 1 || strings.HasPrefix(args[1], "-") {
2✔
743
                return b.DefinitionProvider.Index(serviceVersion)
1✔
744
        }
1✔
745
        if len(args) > 1 && args[1] == "commands" {
2✔
746
                return b.loadAllDefinitions(serviceVersion)
1✔
747
        }
1✔
748
        definition, err := b.DefinitionProvider.Load(args[1], serviceVersion)
1✔
749
        if err != nil {
2✔
750
                return nil, err
1✔
751
        }
1✔
752
        if definition == nil {
2✔
753
                return b.DefinitionProvider.Index(serviceVersion)
1✔
754
        }
1✔
755
        return []parser.Definition{*definition}, err
1✔
756
}
757

758
func (b CommandBuilder) loadAllDefinitions(serviceVersion string) ([]parser.Definition, error) {
1✔
759
        all, err := b.DefinitionProvider.Index(serviceVersion)
1✔
760
        if err != nil {
1✔
761
                return nil, err
×
762
        }
×
763
        definitions := []parser.Definition{}
1✔
764
        for _, d := range all {
2✔
765
                definition, err := b.DefinitionProvider.Load(d.Name, serviceVersion)
1✔
766
                if err != nil {
1✔
767
                        return nil, err
×
768
                }
×
769
                if definition != nil {
2✔
770
                        definitions = append(definitions, *definition)
1✔
771
                }
1✔
772
        }
773
        return definitions, nil
1✔
774
}
775

776
func (b CommandBuilder) loadAutocompleteDefinitions(args []string, serviceVersion string) ([]parser.Definition, error) {
1✔
777
        if len(args) <= 2 {
2✔
778
                return b.DefinitionProvider.Index(serviceVersion)
1✔
779
        }
1✔
780
        return b.loadDefinitions(args, serviceVersion)
1✔
781
}
782

783
func (b CommandBuilder) createShowCommand(definitions []parser.Definition) *CommandDefinition {
1✔
784
        flags := NewFlagBuilder().
1✔
785
                AddHelpFlag().
1✔
786
                Build()
1✔
787

1✔
788
        return NewCommand("show", "Print CLI commands", "Print available uipath CLI commands").
1✔
789
                WithFlags(flags).
1✔
790
                WithHidden(true).
1✔
791
                WithAction(func(context *CommandExecContext) error {
2✔
792
                        defaultFlags := NewFlagBuilder().
1✔
793
                                AddDefaultFlags(false).
1✔
794
                                AddHelpFlag().
1✔
795
                                Build()
1✔
796

1✔
797
                        handler := newShowCommandHandler()
1✔
798
                        output, err := handler.Execute(definitions, defaultFlags)
1✔
799
                        if err != nil {
1✔
800
                                return err
×
801
                        }
×
802
                        _, err = fmt.Fprintln(b.StdOut, output)
1✔
803
                        return err
1✔
804
                })
805
}
806

807
func (b CommandBuilder) createInspectCommand(definitions []parser.Definition) *CommandDefinition {
1✔
808
        flags := NewFlagBuilder().
1✔
809
                AddHelpFlag().
1✔
810
                Build()
1✔
811

1✔
812
        subcommands := []*CommandDefinition{
1✔
813
                b.createShowCommand(definitions),
1✔
814
        }
1✔
815

1✔
816
        return NewCommand("commands", "Inspect available CLI operations", "Command to inspect available uipath CLI operations").
1✔
817
                WithFlags(flags).
1✔
818
                WithSubcommands(subcommands).
1✔
819
                WithHidden(true)
1✔
820
}
1✔
821

822
func (b CommandBuilder) createServiceCommands(definitions []parser.Definition) []*CommandDefinition {
1✔
823
        commands := []*CommandDefinition{}
1✔
824
        for _, e := range definitions {
2✔
825
                command := b.createServiceCommand(e)
1✔
826
                commands = append(commands, command)
1✔
827
        }
1✔
828
        return commands
1✔
829
}
830

831
func (b CommandBuilder) parseArgument(args []string, name string) string {
1✔
832
        for i, arg := range args {
2✔
833
                if strings.TrimSpace(arg) == "--"+name {
2✔
834
                        if len(args) > i+1 {
2✔
835
                                return strings.TrimSpace(args[i+1])
1✔
836
                        }
1✔
837
                }
838
        }
839
        return ""
1✔
840
}
841

842
func (b CommandBuilder) serviceVersionFromProfile(profile string) string {
1✔
843
        config := b.ConfigProvider.Config(profile)
1✔
844
        if config == nil {
2✔
845
                return ""
1✔
846
        }
1✔
847
        return config.ServiceVersion
1✔
848
}
849

850
func (b CommandBuilder) Create(args []string) ([]*CommandDefinition, error) {
1✔
851
        serviceVersion := b.parseArgument(args, FlagNameServiceVersion)
1✔
852
        profile := b.parseArgument(args, FlagNameProfile)
1✔
853
        if serviceVersion == "" && profile != "" {
2✔
854
                serviceVersion = b.serviceVersionFromProfile(profile)
1✔
855
        }
1✔
856
        definitions, err := b.loadDefinitions(args, serviceVersion)
1✔
857
        if err != nil {
2✔
858
                return nil, err
1✔
859
        }
1✔
860
        servicesCommands := b.createServiceCommands(definitions)
1✔
861
        autocompleteCommand := b.createAutoCompleteCommand(serviceVersion)
1✔
862
        configCommand := b.createConfigCommand()
1✔
863
        inspectCommand := b.createInspectCommand(definitions)
1✔
864
        commands := append(servicesCommands, autocompleteCommand, configCommand, inspectCommand)
1✔
865
        return commands, nil
1✔
866
}
867

868
func NewCommandBuilder(
869
        input stream.Stream,
870
        stdOut io.Writer,
871
        stdErr io.Writer,
872
        configProvider config.ConfigProvider,
873
        executor executor.Executor,
874
        pluginExecutor executor.Executor,
875
        definitionProvider DefinitionProvider,
876
        authenticators []auth.Authenticator,
877
) *CommandBuilder {
1✔
878
        return &CommandBuilder{
1✔
879
                input,
1✔
880
                stdOut,
1✔
881
                stdErr,
1✔
882
                configProvider,
1✔
883
                executor,
1✔
884
                pluginExecutor,
1✔
885
                definitionProvider,
1✔
886
                authenticators,
1✔
887
        }
1✔
888
}
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

© 2025 Coveralls, Inc