Skip to content

Commit d54c911

Browse files
Mia-CrossCodelax
andauthored
feat(core): set can handle all positional args together (#3722)
Co-authored-by: Jules Castéran <[email protected]>
1 parent c16e24e commit d54c911

File tree

5 files changed

+119
-2
lines changed

5 files changed

+119
-2
lines changed

internal/core/cobra_utils.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,15 +74,31 @@ func cobraRun(ctx context.Context, cmd *Command) func(*cobra.Command, []string)
7474

7575
results := MultiResults(nil)
7676
rawArgs = rawArgs.RemoveAllPositional()
77-
for _, positionalArg := range positionalArgs {
78-
rawArgsWithPositional := rawArgs.Add(positionalArgSpec.Name, positionalArg)
7977

78+
if cmd.AcceptMultiplePositionalArgs {
79+
argNameWithIndex := fmt.Sprintf("%s.%d", positionalArgSpec.Name, 0)
80+
rawArgsWithPositional := rawArgs.Add(argNameWithIndex, positionalArgs[0])
81+
for i := 1; i < len(positionalArgs); i++ {
82+
argNameWithIndex = fmt.Sprintf("%s.%d", positionalArgSpec.Name, i)
83+
rawArgsWithPositional = rawArgsWithPositional.Add(argNameWithIndex, positionalArgs[i])
84+
}
8085
result, err := run(ctx, cobraCmd, cmd, rawArgsWithPositional)
8186
if err != nil {
8287
return err
8388
}
8489

8590
results = append(results, result)
91+
} else {
92+
for _, positionalArg := range positionalArgs {
93+
rawArgsWithPositional := rawArgs.Add(positionalArgSpec.Name, positionalArg)
94+
95+
result, err := run(ctx, cobraCmd, cmd, rawArgsWithPositional)
96+
if err != nil {
97+
return err
98+
}
99+
100+
results = append(results, result)
101+
}
86102
}
87103
// If only one positional parameter was provided we return the result directly instead of
88104
// an array of results

internal/core/cobra_utils_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"time"
99

1010
"github.com/scaleway/scaleway-cli/v2/internal/core"
11+
"github.com/stretchr/testify/assert"
1112

1213
"github.com/scaleway/scaleway-cli/v2/internal/args"
1314
)
@@ -21,6 +22,11 @@ type testDate struct {
2122
Date *time.Time
2223
}
2324

25+
type testAcceptMultiPositionalArgsType struct {
26+
NameIDs []string
27+
Tag string
28+
}
29+
2430
func testGetCommands() *core.Commands {
2531
return core.NewCommands(
2632
&core.Command{
@@ -54,6 +60,25 @@ func testGetCommands() *core.Commands {
5460
return argsI, nil
5561
},
5662
},
63+
&core.Command{
64+
Namespace: "test",
65+
Resource: "multi-positional",
66+
ArgSpecs: core.ArgSpecs{
67+
{
68+
Name: "name-ids",
69+
Positional: true,
70+
},
71+
{
72+
Name: "tag",
73+
},
74+
},
75+
AcceptMultiplePositionalArgs: true,
76+
AllowAnonymousClient: true,
77+
ArgsType: reflect.TypeOf(testAcceptMultiPositionalArgsType{}),
78+
Run: func(_ context.Context, argsI interface{}) (i interface{}, e error) {
79+
return argsI, nil
80+
},
81+
},
5782
&core.Command{
5883
Namespace: "test",
5984
Resource: "raw-args",
@@ -247,3 +272,49 @@ func Test_PositionalArg(t *testing.T) {
247272
),
248273
}))
249274
}
275+
276+
func Test_MultiPositionalArg(t *testing.T) {
277+
t.Run("multi-positional with one positional", core.Test(&core.TestConfig{
278+
Commands: testGetCommands(),
279+
Cmd: "scw test multi-positional pos1 tag=tag1",
280+
Check: core.TestCheckCombine(
281+
core.TestCheckExitCode(0),
282+
core.TestCheckGolden(),
283+
func(t *testing.T, ctx *core.CheckFuncCtx) {
284+
res := ctx.Result.(*testAcceptMultiPositionalArgsType)
285+
assert.Equal(t, 1, len(res.NameIDs))
286+
assert.Equal(t, "pos1", res.NameIDs[0])
287+
assert.Equal(t, "tag1", res.Tag)
288+
},
289+
),
290+
}))
291+
292+
t.Run("multi-positional with multi positional", core.Test(&core.TestConfig{
293+
Commands: testGetCommands(),
294+
Cmd: "scw test multi-positional pos1 pos2 pos3 tag=tag1",
295+
Check: core.TestCheckCombine(
296+
core.TestCheckExitCode(0),
297+
core.TestCheckGolden(),
298+
func(t *testing.T, ctx *core.CheckFuncCtx) {
299+
res := ctx.Result.(*testAcceptMultiPositionalArgsType)
300+
assert.Equal(t, 3, len(res.NameIDs))
301+
assert.Equal(t, "pos1", res.NameIDs[0])
302+
assert.Equal(t, "pos2", res.NameIDs[1])
303+
assert.Equal(t, "pos3", res.NameIDs[2])
304+
assert.Equal(t, "tag1", res.Tag)
305+
},
306+
),
307+
}))
308+
309+
t.Run("multi-positional with no positional", core.Test(&core.TestConfig{
310+
Commands: testGetCommands(),
311+
Cmd: "scw test multi-positional tag=tag1",
312+
Check: core.TestCheckCombine(
313+
core.TestCheckExitCode(1),
314+
core.TestCheckError(&core.CliError{
315+
Err: fmt.Errorf("a positional argument is required for this command"),
316+
Hint: "Try running: scw test multi-positional <name-ids> tag=tag1",
317+
}),
318+
),
319+
}))
320+
}

internal/core/command.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ type Command struct {
4747
// ArgSpecs defines specifications for arguments.
4848
ArgSpecs ArgSpecs
4949

50+
// AcceptMultiplePositionalArgs defines whether the command can accept multiple positional arguments.
51+
// If enabled, positional argument is expected to be a list.
52+
AcceptMultiplePositionalArgs bool
53+
5054
// View defines the View for this command.
5155
// It is used to create the different options for the different Marshalers.
5256
View *View
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲
2+
🟩🟩🟩 STDOUT️ 🟩🟩🟩️
3+
NameIDs.0 pos1
4+
NameIDs.1 pos2
5+
NameIDs.2 pos3
6+
Tag tag1
7+
🟩🟩🟩 JSON STDOUT 🟩🟩🟩
8+
{
9+
"NameIDs": [
10+
"pos1",
11+
"pos2",
12+
"pos3"
13+
],
14+
"Tag": "tag1"
15+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
🎲🎲🎲 EXIT CODE: 0 🎲🎲🎲
2+
🟩🟩🟩 STDOUT️ 🟩🟩🟩️
3+
NameIDs.0 pos1
4+
Tag tag1
5+
🟩🟩🟩 JSON STDOUT 🟩🟩🟩
6+
{
7+
"NameIDs": [
8+
"pos1"
9+
],
10+
"Tag": "tag1"
11+
}

0 commit comments

Comments
 (0)