Skip to content

Commit

Permalink
Fix example usage for nested objects
Browse files Browse the repository at this point in the history
Currently, the example shows an unnecessary object assigment
for nested parameters, e.g.

```
--instances object (multiple)

   Example:
     config=object; config.memory=float; config.cpu=float;
```

With this fix, the `config=object;` assigment will no be shown anymore:

```
--instances object (multiple)

   Example:
     config.memory=float; config.cpu=float;
```
  • Loading branch information
thschmitt committed Feb 13, 2024
1 parent 3a5c30d commit 398b7c5
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 11 deletions.
26 changes: 15 additions & 11 deletions commandline/parameter_formatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package commandline

import (
"fmt"
"slices"
"strings"

"github.com/UiPath/uipathcli/parser"
Expand Down Expand Up @@ -66,28 +67,31 @@ func (f parameterFormatter) descriptionFields(parameter parser.Parameter) []inte
}

func (f parameterFormatter) usageExample(parameter parser.Parameter) string {
parameters := map[string]string{}
f.collectUsageParameters(parameter, "", parameters)
parameters := f.collectUsageParameters(parameter, "")
slices.Sort(parameters)

builder := strings.Builder{}
for key, value := range parameters {
for _, value := range parameters {
f.writeSeparator(&builder, "; ")
builder.WriteString(fmt.Sprintf("%s=%s", key, value))
builder.WriteString(value)
}
return builder.String()
}

func (f parameterFormatter) collectUsageParameters(parameter parser.Parameter, prefix string, result map[string]string) {
func (f parameterFormatter) collectUsageParameters(parameter parser.Parameter, prefix string) []string {
result := []string{}
for _, p := range parameter.Parameters {
if p.Type == parser.ParameterTypeObjectArray {
f.collectUsageParameters(p, prefix+p.FieldName+"[0].", result)
continue
result = append(result, f.collectUsageParameters(p, prefix+p.FieldName+"[0].")...)
} else if p.Type == parser.ParameterTypeObject {
result = append(result, f.collectUsageParameters(p, prefix+p.FieldName+".")...)
} else {
field := prefix + p.FieldName
fieldType := f.humanReadableType(p.Type)
result = append(result, fmt.Sprintf("%s=%s", field, fieldType))
}
if p.Type == parser.ParameterTypeObject {
f.collectUsageParameters(p, prefix+p.FieldName+".", result)
}
result[prefix+p.FieldName] = f.humanReadableType(p.Type)
}
return result
}

func (f parameterFormatter) commaSeparatedValues(values []interface{}) string {
Expand Down
100 changes: 100 additions & 0 deletions test/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1430,3 +1430,103 @@ paths:
t.Errorf("Should not parse versioned service operation, but got: %v", result.StdOut)
}
}

func TestShowsExampleOutputForObjects(t *testing.T) {
definition := `
paths:
/create:
post:
operationId: create
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CreateDeploymentRequest'
components:
schemas:
CreateDeploymentRequest:
type: object
properties:
config:
$ref: '#/components/schemas/DeploymentConfigModel'
DeploymentConfigModel:
type: object
properties:
cpu:
type: integer
format: int32
memory:
type: number
format: double
gpu:
type: boolean
`

context := NewContextBuilder().
WithDefinition("myservice", definition).
Build()

result := RunCli([]string{"myservice", "create", "--help"}, context)

if !strings.Contains(result.StdOut, "Example:") {
t.Errorf("Could not find example output, but got: %v", result.StdOut)
}
if !strings.Contains(result.StdOut, "cpu=integer; gpu=boolean; memory=float") {
t.Errorf("Could not find example command, but got: %v", result.StdOut)
}
}

func TestShowsExampleOutputForNestedObjects(t *testing.T) {
definition := `
paths:
/create:
post:
operationId: create
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CreateDeploymentRequest'
components:
schemas:
CreateDeploymentRequest:
type: object
properties:
instances:
type: array
items:
$ref: '#/components/schemas/DeploymentInstance'
DeploymentInstance:
type: object
properties:
config:
$ref: '#/components/schemas/DeploymentConfigModel'
DeploymentConfigModel:
type: object
properties:
cpu:
type: integer
format: int32
memory:
type: number
format: double
gpu:
type: boolean
`

context := NewContextBuilder().
WithDefinition("myservice", definition).
Build()

result := RunCli([]string{"myservice", "create", "--help"}, context)

if !strings.Contains(result.StdOut, "Example:") {
t.Errorf("Could not find example output, but got: %v", result.StdOut)
}
if !strings.Contains(result.StdOut, "config.cpu=integer; config.gpu=boolean; config.memory=float") {
t.Errorf("Could not find example command, but got: %v", result.StdOut)
}
if strings.Contains(result.StdOut, "config=object") {
t.Errorf("Should not contain the object itself in the example, but got: %v", result.StdOut)
}
}

0 comments on commit 398b7c5

Please sign in to comment.