From ec55043d46dabc05df3b408a1d39ddce098ca63e Mon Sep 17 00:00:00 2001 From: CMGS Date: Wed, 9 Sep 2026 18:50:25 +0900 Subject: [PATCH] cut: declare required positionals through cli arguments Seventeen commands checked their positional by hand and returned their own "must be given" error. They now declare it through utils.Positional (a required cli.StringArgs, max -1 for an id list), so urfave rejects the run before the action; the argIDs helper goes with them. The missing-argument failure is now the framework's message through the logger with exit code 1 instead of a bare line with 255. image build keeps its exactly-one check (a declared argument ignores extras) and workload dissociate keeps its optional ids. --- cmd/node/add.go | 8 +------- cmd/node/add_test.go | 10 ++++------ cmd/node/cmd.go | 21 ++++++++++++--------- cmd/node/down.go | 7 +------ cmd/node/get.go | 8 +------- cmd/node/remove.go | 8 +------- cmd/node/resource.go | 8 +------- cmd/node/set.go | 8 +------- cmd/node/status.go | 7 +------ cmd/node/up.go | 8 +------- cmd/node/workloads.go | 8 +------- cmd/pod/add.go | 8 +------- cmd/pod/capacity.go | 8 +------- cmd/pod/cmd.go | 13 +++++++------ cmd/pod/networks.go | 8 +------- cmd/pod/nodes.go | 7 +------ cmd/pod/remove.go | 8 +------- cmd/pod/resource.go | 8 +------- cmd/utils/flags.go | 5 +++++ cmd/workload/cmd.go | 27 +++++++++++++++------------ cmd/workload/control.go | 7 +------ cmd/workload/deploy_test.go | 12 +++++++++++- cmd/workload/get.go | 7 +------ cmd/workload/realloc.go | 7 +------ cmd/workload/remove.go | 7 +------ cmd/workload/send.go | 7 +------ cmd/workload/sendlarge.go | 7 +------ cmd/workload/status.go | 14 ++------------ cmd/workload/utils.go | 15 +-------------- 29 files changed, 78 insertions(+), 198 deletions(-) diff --git a/cmd/node/add.go b/cmd/node/add.go index 6f041d2..bb7b586 100644 --- a/cmd/node/add.go +++ b/cmd/node/add.go @@ -2,7 +2,6 @@ package node import ( "context" - "errors" "fmt" "strings" @@ -48,11 +47,6 @@ func cmdNodeAdd(ctx context.Context, cmd *cli.Command) error { } func generateAddNodeOptions(cmd *cli.Command) (*corepb.AddNodeOptions, error) { - podname := cmd.Args().First() - if podname == "" { - return nil, errors.New("podname must not be empty") - } - nodename := cmd.String("nodename") endpoint := cmd.String("endpoint") @@ -80,7 +74,7 @@ func generateAddNodeOptions(cmd *cli.Command) (*corepb.AddNodeOptions, error) { return &corepb.AddNodeOptions{ Nodename: nodename, Endpoint: endpoint, - Podname: podname, + Podname: cmd.StringArgs(argPod)[0], Labels: labels, Resources: resources, Test: cmd.Bool("test"), diff --git a/cmd/node/add_test.go b/cmd/node/add_test.go index 77d26e8..8b52ac1 100644 --- a/cmd/node/add_test.go +++ b/cmd/node/add_test.go @@ -82,14 +82,12 @@ func TestGenerateAddNodeOptionsRequiresEndpoint(t *testing.T) { func TestGenerateAddNodeOptionsWithoutPod(t *testing.T) { c := Command() - lookupSubcommand(t, c, "add").Action = func(_ context.Context, cmd *cli.Command) error { - if _, err := generateAddNodeOptions(cmd); err == nil { - t.Error("got nil, want an error for node add without a pod") - } + lookupSubcommand(t, c, "add").Action = func(context.Context, *cli.Command) error { + t.Error("the action ran without a pod argument") return nil } - if err := c.Run(t.Context(), []string{"node", "add"}); err != nil { - t.Fatalf("run: %v", err) + if err := c.Run(t.Context(), []string{"node", "add"}); err == nil { + t.Error("got nil, want an error for node add without a pod") } } diff --git a/cmd/node/cmd.go b/cmd/node/cmd.go index eda0b51..03215d3 100644 --- a/cmd/node/cmd.go +++ b/cmd/node/cmd.go @@ -7,7 +7,10 @@ import ( ) const ( + argNode = "node" + argPod = "pod" nodeArgsUsage = "node name" + podArgsUsage = "pod name" flagLabel = "label" flagStorage = "storage" @@ -22,13 +25,13 @@ func Command() *cli.Command { { Name: "get", Usage: "get a node", - ArgsUsage: nodeArgsUsage, + Arguments: utils.Positional(argNode, nodeArgsUsage, 1), Action: utils.ExitCoder(cmdNodeGet), }, { Name: "remove", Usage: "remove a node", - ArgsUsage: nodeArgsUsage, + Arguments: utils.Positional(argNode, nodeArgsUsage, 1), Action: utils.ExitCoder(cmdNodeRemove), }, { @@ -41,13 +44,13 @@ func Command() *cli.Command { }, }, Aliases: []string{"containers"}, - ArgsUsage: nodeArgsUsage, + Arguments: utils.Positional(argNode, nodeArgsUsage, 1), Action: utils.ExitCoder(cmdNodeListWorkloads), }, { Name: "up", Usage: "set node up", - ArgsUsage: nodeArgsUsage, + Arguments: utils.Positional(argNode, nodeArgsUsage, 1), Action: utils.ExitCoder(cmdNodeSetUp), }, { @@ -64,7 +67,7 @@ func Command() *cli.Command { Value: 20, }, }, - ArgsUsage: nodeArgsUsage, + Arguments: utils.Positional(argNode, nodeArgsUsage, 1), Action: utils.ExitCoder(cmdNodeSetDown), }, { @@ -82,7 +85,7 @@ func Command() *cli.Command { Value: 0, }, }, - ArgsUsage: nodeArgsUsage, + Arguments: utils.Positional(argNode, nodeArgsUsage, 1), Action: utils.ExitCoder(cmdNodeSetStatus), }, { @@ -93,7 +96,7 @@ func Command() *cli.Command { { Name: "resource", Usage: "check node resource", - ArgsUsage: nodeArgsUsage, + Arguments: utils.Positional(argNode, nodeArgsUsage, 1), Flags: []cli.Flag{ &cli.BoolFlag{ Name: "fix", @@ -106,7 +109,7 @@ func Command() *cli.Command { Name: "set", Aliases: []string{"update"}, Usage: "set node resource", - ArgsUsage: nodeArgsUsage, + Arguments: utils.Positional(argNode, nodeArgsUsage, 1), Action: utils.ExitCoder(cmdNodeSet), Flags: []cli.Flag{ &cli.BoolFlag{ @@ -177,7 +180,7 @@ func Command() *cli.Command { { Name: "add", Usage: "add node", - ArgsUsage: "pod name", + Arguments: utils.Positional(argPod, podArgsUsage, 1), Action: utils.ExitCoder(cmdNodeAdd), Flags: []cli.Flag{ &cli.StringFlag{ diff --git a/cmd/node/down.go b/cmd/node/down.go index 2f76f05..49c8925 100644 --- a/cmd/node/down.go +++ b/cmd/node/down.go @@ -50,14 +50,9 @@ func cmdNodeSetDown(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("node name must be given") - } - o := &setNodeDownOptions{ client: client, - name: name, + name: cmd.StringArgs(argNode)[0], check: cmd.Bool("check"), checkTimeout: cmd.Int("check-timeout"), } diff --git a/cmd/node/get.go b/cmd/node/get.go index 7e59b4a..943af6f 100644 --- a/cmd/node/get.go +++ b/cmd/node/get.go @@ -2,7 +2,6 @@ package node import ( "context" - "errors" corepb "github.com/projecteru2/core/rpc/gen" "github.com/urfave/cli/v3" @@ -34,14 +33,9 @@ func cmdNodeGet(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("node name must be given") - } - o := &getNodeOptions{ client: client, - name: name, + name: cmd.StringArgs(argNode)[0], } return o.run(ctx) } diff --git a/cmd/node/remove.go b/cmd/node/remove.go index 838f20d..d493e67 100644 --- a/cmd/node/remove.go +++ b/cmd/node/remove.go @@ -2,7 +2,6 @@ package node import ( "context" - "errors" "github.com/projecteru2/core/log" corepb "github.com/projecteru2/core/rpc/gen" @@ -33,14 +32,9 @@ func cmdNodeRemove(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("node name must be given") - } - o := &removeNodeOptions{ client: client, - name: name, + name: cmd.StringArgs(argNode)[0], } return o.run(ctx) } diff --git a/cmd/node/resource.go b/cmd/node/resource.go index c88a98c..36315bb 100644 --- a/cmd/node/resource.go +++ b/cmd/node/resource.go @@ -2,7 +2,6 @@ package node import ( "context" - "errors" corepb "github.com/projecteru2/core/rpc/gen" "github.com/urfave/cli/v3" @@ -37,14 +36,9 @@ func cmdNodeResource(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("node name must be given") - } - o := &nodeResourceOptions{ client: client, - name: name, + name: cmd.StringArgs(argNode)[0], fix: cmd.Bool("fix"), } return o.run(ctx) diff --git a/cmd/node/set.go b/cmd/node/set.go index 9053ba7..f6b86fd 100644 --- a/cmd/node/set.go +++ b/cmd/node/set.go @@ -2,7 +2,6 @@ package node import ( "context" - "errors" "github.com/projecteru2/core/log" resourcetypes "github.com/projecteru2/core/resource/types" @@ -45,11 +44,6 @@ func cmdNodeSet(ctx context.Context, cmd *cli.Command) error { } func generateSetNodeOptions(cmd *cli.Command) (*corepb.SetNodeOptions, error) { - name := cmd.Args().First() - if name == "" { - return nil, errors.New("node name must be given") - } - cpumem, storage := collectResourceParams(cmd) if cmd.IsSet("cpu") { cpumem["cpu"] = cmd.String("cpu") @@ -67,7 +61,7 @@ func generateSetNodeOptions(cmd *cli.Command) (*corepb.SetNodeOptions, error) { } return &corepb.SetNodeOptions{ - Nodename: name, + Nodename: cmd.StringArgs(argNode)[0], Resources: resources, Labels: utils.SplitEquality(cmd.StringSlice(flagLabel)), WorkloadsDown: cmd.Bool("mark-workloads-down"), diff --git a/cmd/node/status.go b/cmd/node/status.go index d3fd601..ab98d1d 100644 --- a/cmd/node/status.go +++ b/cmd/node/status.go @@ -2,7 +2,6 @@ package node import ( "context" - "errors" "fmt" "time" @@ -55,17 +54,13 @@ func cmdNodeSetStatus(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("node name must be given") - } if cmd.Int("interval") < 0 { return fmt.Errorf("--interval must not be negative, got %d", cmd.Int("interval")) } o := &setNodeStatusOptions{ client: client, - name: name, + name: cmd.StringArgs(argNode)[0], ttl: cmd.Int("ttl"), interval: cmd.Int("interval"), } diff --git a/cmd/node/up.go b/cmd/node/up.go index db5dde0..4d828a3 100644 --- a/cmd/node/up.go +++ b/cmd/node/up.go @@ -2,7 +2,6 @@ package node import ( "context" - "errors" "github.com/projecteru2/core/log" corepb "github.com/projecteru2/core/rpc/gen" @@ -34,14 +33,9 @@ func cmdNodeSetUp(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("node name must be given") - } - o := &setNodeUpOptions{ client: client, - name: name, + name: cmd.StringArgs(argNode)[0], } return o.run(ctx) } diff --git a/cmd/node/workloads.go b/cmd/node/workloads.go index 60a972c..bb42766 100644 --- a/cmd/node/workloads.go +++ b/cmd/node/workloads.go @@ -2,7 +2,6 @@ package node import ( "context" - "errors" corepb "github.com/projecteru2/core/rpc/gen" "github.com/urfave/cli/v3" @@ -36,14 +35,9 @@ func cmdNodeListWorkloads(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("node name must be given") - } - o := &listNodeWorkloadsOptions{ client: client, - name: name, + name: cmd.StringArgs(argNode)[0], labels: utils.SplitEquality(cmd.StringSlice(flagLabel)), } return o.run(ctx) diff --git a/cmd/pod/add.go b/cmd/pod/add.go index 63eb232..cfbcd28 100644 --- a/cmd/pod/add.go +++ b/cmd/pod/add.go @@ -2,7 +2,6 @@ package pod import ( "context" - "errors" corepb "github.com/projecteru2/core/rpc/gen" "github.com/urfave/cli/v3" @@ -36,14 +35,9 @@ func cmdPodAdd(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("pod name must be given") - } - o := &addPodOptions{ client: client, - name: name, + name: cmd.StringArgs(argPod)[0], desc: cmd.String("desc"), } return o.run(ctx) diff --git a/cmd/pod/capacity.go b/cmd/pod/capacity.go index 121942e..b966630 100644 --- a/cmd/pod/capacity.go +++ b/cmd/pod/capacity.go @@ -3,7 +3,6 @@ package pod import ( "context" "crypto/rand" - "errors" "fmt" "strings" @@ -50,11 +49,6 @@ func cmdPodCapacity(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("pod name must be given") - } - resources, err := capacityResources(cmd) if err != nil { return err @@ -62,7 +56,7 @@ func cmdPodCapacity(ctx context.Context, cmd *cli.Command) error { o := &capacityPodOptions{ client: client, - podname: name, + podname: cmd.StringArgs(argPod)[0], nodenames: cmd.StringSlice("node"), resources: resources, } diff --git a/cmd/pod/cmd.go b/cmd/pod/cmd.go index 4f3828f..517bf90 100644 --- a/cmd/pod/cmd.go +++ b/cmd/pod/cmd.go @@ -7,6 +7,7 @@ import ( ) const ( + argPod = "pod" podArgsUsage = "pod name" up = "up" @@ -32,7 +33,7 @@ func Command() *cli.Command { { Name: "add", Usage: "add new pod", - ArgsUsage: podArgsUsage, + Arguments: utils.Positional(argPod, podArgsUsage, 1), Action: utils.ExitCoder(cmdPodAdd), Flags: []cli.Flag{ &cli.StringFlag{ @@ -44,13 +45,13 @@ func Command() *cli.Command { { Name: "remove", Usage: "remove pod", - ArgsUsage: podArgsUsage, + Arguments: utils.Positional(argPod, podArgsUsage, 1), Action: utils.ExitCoder(cmdPodRemove), }, { Name: "resource", Usage: "pod resource usage", - ArgsUsage: podArgsUsage, + Arguments: utils.Positional(argPod, podArgsUsage, 1), Action: utils.ExitCoder(cmdPodResource), Flags: []cli.Flag{ &cli.StringFlag{ @@ -67,7 +68,7 @@ func Command() *cli.Command { { Name: "capacity", Usage: "pod remained capacity", - ArgsUsage: podArgsUsage, + Arguments: utils.Positional(argPod, podArgsUsage, 1), Action: utils.ExitCoder(cmdPodCapacity), Flags: []cli.Flag{ &cli.Float64Flag{ @@ -103,7 +104,7 @@ func Command() *cli.Command { { Name: "nodes", Usage: "list all nodes in one pod", - ArgsUsage: podArgsUsage, + Arguments: utils.Positional(argPod, podArgsUsage, 1), Action: utils.ExitCoder(cmdPodListNodes), Flags: []cli.Flag{ &cli.StringFlag{ @@ -134,7 +135,7 @@ func Command() *cli.Command { { Name: "networks", Usage: "list all networks in one pod", - ArgsUsage: podArgsUsage, + Arguments: utils.Positional(argPod, podArgsUsage, 1), Action: utils.ExitCoder(cmdPodListNetworks), Flags: []cli.Flag{ &cli.StringFlag{ diff --git a/cmd/pod/networks.go b/cmd/pod/networks.go index 19045c4..b4f6e58 100644 --- a/cmd/pod/networks.go +++ b/cmd/pod/networks.go @@ -2,7 +2,6 @@ package pod import ( "context" - "errors" corepb "github.com/projecteru2/core/rpc/gen" "github.com/urfave/cli/v3" @@ -36,14 +35,9 @@ func cmdPodListNetworks(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("pod name must be given") - } - o := &listPodNetworksOptions{ client: client, - name: name, + name: cmd.StringArgs(argPod)[0], driver: cmd.String("driver"), } return o.run(ctx) diff --git a/cmd/pod/nodes.go b/cmd/pod/nodes.go index 6b33b0f..66e136f 100644 --- a/cmd/pod/nodes.go +++ b/cmd/pod/nodes.go @@ -48,11 +48,6 @@ func cmdPodListNodes(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("pod name must be given") - } - filter := strings.ToLower(cmd.String("filter")) if filter != up && filter != down && filter != all { return errors.New("filter should be one of up/down/all") @@ -60,7 +55,7 @@ func cmdPodListNodes(ctx context.Context, cmd *cli.Command) error { o := &listPodNodesOptions{ client: client, - name: name, + name: cmd.StringArgs(argPod)[0], filter: filter, labels: utils.SplitEquality(cmd.StringSlice("label")), timeoutInSecond: int32(cmd.Int("timeout")), //nolint:gosec diff --git a/cmd/pod/remove.go b/cmd/pod/remove.go index c67cb50..0342366 100644 --- a/cmd/pod/remove.go +++ b/cmd/pod/remove.go @@ -2,7 +2,6 @@ package pod import ( "context" - "errors" "github.com/projecteru2/core/log" corepb "github.com/projecteru2/core/rpc/gen" @@ -34,14 +33,9 @@ func cmdPodRemove(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("pod name must be given") - } - o := &removePodOptions{ client: client, - name: name, + name: cmd.StringArgs(argPod)[0], } return o.run(ctx) } diff --git a/cmd/pod/resource.go b/cmd/pod/resource.go index 8db5406..78d34fd 100644 --- a/cmd/pod/resource.go +++ b/cmd/pod/resource.go @@ -2,7 +2,6 @@ package pod import ( "context" - "errors" "fmt" "regexp" "strconv" @@ -43,11 +42,6 @@ func cmdPodResource(ctx context.Context, cmd *cli.Command) error { return err } - name := cmd.Args().First() - if name == "" { - return errors.New("pod name must be given") - } - keep, err := parseFilter(cmd.String("filter")) if err != nil { return err @@ -55,7 +49,7 @@ func cmdPodResource(ctx context.Context, cmd *cli.Command) error { o := &resourcePodOptions{ client: client, - name: name, + name: cmd.StringArgs(argPod)[0], keep: keep, stream: cmd.Bool("stream"), } diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 8762535..d24db21 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -25,3 +25,8 @@ func ForceFlag(usage string) *cli.BoolFlag { Aliases: []string{"f"}, } } + +// Positional declares one required positional argument, max -1 for an unlimited list. +func Positional(name, usage string, max int) []cli.Argument { + return []cli.Argument{&cli.StringArgs{Name: name, UsageText: usage, Min: 1, Max: max}} +} diff --git a/cmd/workload/cmd.go b/cmd/workload/cmd.go index caa3d8a..86864bb 100644 --- a/cmd/workload/cmd.go +++ b/cmd/workload/cmd.go @@ -9,6 +9,9 @@ import ( ) const ( + argSpec = "spec" + argWorkload = "workload" + workloadArgsUsage = "workloadID(s)" specFileURI = "" copyArgsUsage = "workloadID:path1,path2,...,pathn" @@ -41,7 +44,7 @@ func Command() *cli.Command { { Name: "get", Usage: "get workload(s)", - ArgsUsage: workloadArgsUsage, + Arguments: utils.Positional(argWorkload, workloadArgsUsage, -1), Action: utils.ExitCoder(cmdWorkloadGet), }, { @@ -73,13 +76,13 @@ func Command() *cli.Command { { Name: "get-status", Usage: "get workload status", - ArgsUsage: workloadArgsUsage, + Arguments: utils.Positional(argWorkload, workloadArgsUsage, -1), Action: utils.ExitCoder(cmdWorkloadGetStatus), }, { Name: "set-status", Usage: "set workload status", - ArgsUsage: workloadArgsUsage, + Arguments: utils.Positional(argWorkload, workloadArgsUsage, -1), Flags: []cli.Flag{ &cli.BoolFlag{ Name: "running", @@ -148,7 +151,7 @@ func Command() *cli.Command { { Name: "stop", Usage: "stop workload(s)", - ArgsUsage: workloadArgsUsage, + Arguments: utils.Positional(argWorkload, workloadArgsUsage, -1), Action: utils.ExitCoder(cmdWorkloadControl(corecluster.WorkloadStop)), Flags: []cli.Flag{ utils.ForceFlag("force to stop"), @@ -157,7 +160,7 @@ func Command() *cli.Command { { Name: "start", Usage: "start workload(s)", - ArgsUsage: workloadArgsUsage, + Arguments: utils.Positional(argWorkload, workloadArgsUsage, -1), Action: utils.ExitCoder(cmdWorkloadControl(corecluster.WorkloadStart)), Flags: []cli.Flag{ utils.ForceFlag("force to start"), @@ -166,7 +169,7 @@ func Command() *cli.Command { { Name: "restart", Usage: "restart workload(s)", - ArgsUsage: workloadArgsUsage, + Arguments: utils.Positional(argWorkload, workloadArgsUsage, -1), Action: utils.ExitCoder(cmdWorkloadControl(corecluster.WorkloadRestart)), Flags: []cli.Flag{ utils.ForceFlag("force to restart"), @@ -175,7 +178,7 @@ func Command() *cli.Command { { Name: "remove", Usage: "remove workload(s)", - ArgsUsage: workloadArgsUsage, + Arguments: utils.Positional(argWorkload, workloadArgsUsage, -1), Action: utils.ExitCoder(cmdWorkloadRemove), Flags: []cli.Flag{ utils.ForceFlag("force to remove"), @@ -198,7 +201,7 @@ func Command() *cli.Command { { Name: "send", Usage: "send file(s) to workload(s)", - ArgsUsage: workloadArgsUsage, + Arguments: utils.Positional(argWorkload, workloadArgsUsage, -1), Action: utils.ExitCoder(cmdWorkloadSend), Flags: []cli.Flag{ utils.FileFlag("copy local files into the workloads, repeatable"), @@ -207,7 +210,7 @@ func Command() *cli.Command { { Name: "sendlarge", Usage: "send single large file to workload(s)", - ArgsUsage: workloadArgsUsage, + Arguments: utils.Positional(argWorkload, workloadArgsUsage, -1), Action: utils.ExitCoder(cmdWorkloadSendLarge), Flags: []cli.Flag{ utils.FileFlag("stream one local file into the workloads"), @@ -228,7 +231,7 @@ func Command() *cli.Command { { Name: "realloc", Usage: "realloc workload resource", - ArgsUsage: "workloadID", + Arguments: utils.Positional(argWorkload, "workloadID", 1), Action: utils.ExitCoder(cmdWorkloadRealloc), Flags: []cli.Flag{ &cli.Float64Flag{ @@ -318,7 +321,7 @@ func Command() *cli.Command { { Name: "replace", Usage: "replace workloads by params", - ArgsUsage: specFileURI, + Arguments: utils.Positional(argSpec, specFileURI, 1), Action: utils.ExitCoder(cmdWorkloadReplace), Flags: []cli.Flag{ &cli.StringFlag{ @@ -387,7 +390,7 @@ func Command() *cli.Command { { Name: "deploy", Usage: "deploy workloads by params", - ArgsUsage: specFileURI, + Arguments: utils.Positional(argSpec, specFileURI, 1), Action: utils.ExitCoder(cmdWorkloadDeploy), Flags: []cli.Flag{ &cli.BoolFlag{ diff --git a/cmd/workload/control.go b/cmd/workload/control.go index b7c3d97..8bf718b 100644 --- a/cmd/workload/control.go +++ b/cmd/workload/control.go @@ -49,14 +49,9 @@ func cmdWorkloadControl(action string) cli.ActionFunc { return err } - ids, err := argIDs(cmd) - if err != nil { - return err - } - o := &controlWorkloadsOptions{ client: client, - ids: ids, + ids: cmd.StringArgs(argWorkload), action: action, force: cmd.Bool(utils.FlagForce), } diff --git a/cmd/workload/deploy_test.go b/cmd/workload/deploy_test.go index 3fea067..c052d9b 100644 --- a/cmd/workload/deploy_test.go +++ b/cmd/workload/deploy_test.go @@ -119,7 +119,6 @@ func TestGenerateDeployOptionsErrors(t *testing.T) { name string args []string }{ - {name: "no spec", args: []string{"workload", "deploy", "--entry", "release"}}, {name: "unknown entry", args: []string{"workload", "deploy", "--entry", "nope", spec}}, {name: "bad memory", args: []string{"workload", "deploy", "--entry", "release", "--memory", "abc", spec}}, {name: "bad storage", args: []string{"workload", "deploy", "--entry", "release", "--storage", "abc", spec}}, @@ -143,6 +142,17 @@ func TestGenerateDeployOptionsErrors(t *testing.T) { } } +func TestDeployRequiresASpec(t *testing.T) { + c := Command() + lookupSubcommand(t, c, "deploy").Action = func(context.Context, *cli.Command) error { + t.Error("the action ran without a spec argument") + return nil + } + if err := c.Run(t.Context(), []string{"workload", "deploy", "--entry", "release"}); err == nil { + t.Error("got nil, want an error for a missing spec argument") + } +} + func writeSpec(t *testing.T) string { t.Helper() path := filepath.Join(t.TempDir(), "specs.yaml") diff --git a/cmd/workload/get.go b/cmd/workload/get.go index cfef78d..205e689 100644 --- a/cmd/workload/get.go +++ b/cmd/workload/get.go @@ -31,14 +31,9 @@ func cmdWorkloadGet(ctx context.Context, cmd *cli.Command) error { return err } - ids, err := argIDs(cmd) - if err != nil { - return err - } - o := &getWorkloadsOptions{ client: client, - ids: ids, + ids: cmd.StringArgs(argWorkload), } return o.run(ctx) } diff --git a/cmd/workload/realloc.go b/cmd/workload/realloc.go index d2a09a8..a59438b 100644 --- a/cmd/workload/realloc.go +++ b/cmd/workload/realloc.go @@ -50,11 +50,6 @@ func cmdWorkloadRealloc(ctx context.Context, cmd *cli.Command) error { } func generateReallocOptions(cmd *cli.Command) (*corepb.ReallocOptions, error) { - id := cmd.Args().First() - if id == "" { - return nil, errors.New("workload id must be given") - } - memoryRequest, memoryLimit, err := ramOption(cmd, flagMemoryRequest, flagMemoryLimit, "memory") if err != nil { return nil, err @@ -95,7 +90,7 @@ func generateReallocOptions(cmd *cli.Command) (*corepb.ReallocOptions, error) { } return &corepb.ReallocOptions{ - Id: id, + Id: cmd.StringArgs(argWorkload)[0], Resources: resources, }, nil } diff --git a/cmd/workload/remove.go b/cmd/workload/remove.go index 465dfe5..ff8f341 100644 --- a/cmd/workload/remove.go +++ b/cmd/workload/remove.go @@ -46,18 +46,13 @@ func cmdWorkloadRemove(ctx context.Context, cmd *cli.Command) error { return err } - ids, err := argIDs(cmd) - if err != nil { - return err - } - force := cmd.Bool(utils.FlagForce) if force { log.WithFunc("workload.cmdWorkloadRemove").Warn(ctx, "if workload not stopped, force to remove will not trigger hook process if set") } o := &removeWorkloadsOptions{ client: client, - ids: ids, + ids: cmd.StringArgs(argWorkload), force: force, } return o.run(ctx) diff --git a/cmd/workload/send.go b/cmd/workload/send.go index e9b40ca..20692bb 100644 --- a/cmd/workload/send.go +++ b/cmd/workload/send.go @@ -56,14 +56,9 @@ func cmdWorkloadSend(ctx context.Context, cmd *cli.Command) error { return errors.New("files should not be empty") } - ids, err := argIDs(cmd) - if err != nil { - return err - } - o := &sendWorkloadsOptions{ client: client, - ids: ids, + ids: cmd.StringArgs(argWorkload), content: files.Data, modes: files.Modes, owners: files.Owners, diff --git a/cmd/workload/sendlarge.go b/cmd/workload/sendlarge.go index d0ecbd2..ac564b7 100644 --- a/cmd/workload/sendlarge.go +++ b/cmd/workload/sendlarge.go @@ -104,11 +104,6 @@ func cmdWorkloadSendLarge(ctx context.Context, cmd *cli.Command) error { return err } - ids, err := argIDs(cmd) - if err != nil { - return err - } - src, err := os.Open(spec.Src) if err != nil { return err @@ -123,7 +118,7 @@ func cmdWorkloadSendLarge(ctx context.Context, cmd *cli.Command) error { } o := &sendLargeWorkloadsOptions{ client: client, - ids: ids, + ids: cmd.StringArgs(argWorkload), dst: spec.Dst, src: src, size: stat.Size(), diff --git a/cmd/workload/status.go b/cmd/workload/status.go index d05b888..c99b842 100644 --- a/cmd/workload/status.go +++ b/cmd/workload/status.go @@ -31,14 +31,9 @@ func cmdWorkloadGetStatus(ctx context.Context, cmd *cli.Command) error { return err } - ids, err := argIDs(cmd) - if err != nil { - return err - } - o := &getWorkloadsStatusOptions{ client: client, - ids: ids, + ids: cmd.StringArgs(argWorkload), } return o.run(ctx) } @@ -83,14 +78,9 @@ func cmdWorkloadSetStatus(ctx context.Context, cmd *cli.Command) error { return err } - ids, err := argIDs(cmd) - if err != nil { - return err - } - o := &setWorkloadsStatusOptions{ client: client, - ids: ids, + ids: cmd.StringArgs(argWorkload), running: cmd.Bool("running"), healthy: cmd.Bool("healthy"), ttl: cmd.Int64("ttl"), diff --git a/cmd/workload/utils.go b/cmd/workload/utils.go index e6d64f6..31c10be 100644 --- a/cmd/workload/utils.go +++ b/cmd/workload/utils.go @@ -15,14 +15,6 @@ import ( "github.com/projecteru2/cli/types" ) -func argIDs(cmd *cli.Command) ([]string, error) { - ids := cmd.Args().Slice() - if len(ids) == 0 { - return nil, errors.New("workload id(s) should not be empty") - } - return ids, nil -} - func validateDeployFlags(cmd *cli.Command, keys ...string) error { for _, key := range keys { if cmd.String(key) == "" { @@ -36,12 +28,7 @@ func validateDeployFlags(cmd *cli.Command, keys ...string) error { } func loadSpecs(ctx context.Context, cmd *cli.Command) (*types.Specs, error) { - specURI := cmd.Args().First() - if specURI == "" { - return nil, errors.New("a spec must be given") - } - - data, err := utils.ReadSpecURI(ctx, specURI) + data, err := utils.ReadSpecURI(ctx, cmd.StringArgs(argSpec)[0]) if err != nil { return nil, err }