Skip to content

Commit 7ea267e

Browse files
authored
refactor(base): allow positional argument override in update (#1161)
This refactor allows positional argument overrides in update commands. This allows us to update subresources (e.g. Storage Box Snapshots).
1 parent dd22cfd commit 7ea267e

1 file changed

Lines changed: 45 additions & 6 deletions

File tree

internal/cmd/base/update.go

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package base
22

33
import (
44
"fmt"
5+
"log"
56
"reflect"
67

78
"github.com/spf13/cobra"
@@ -20,20 +21,49 @@ type UpdateCmd struct {
2021
ShortDescription string
2122
NameSuggestions func(client hcapi2.Client) func() []string
2223
DefineFlags func(*cobra.Command)
23-
Fetch func(s state.State, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error)
24-
Update func(s state.State, cmd *cobra.Command, resource interface{}, flags map[string]pflag.Value) error
24+
25+
Fetch func(s state.State, cmd *cobra.Command, idOrName string) (interface{}, *hcloud.Response, error)
26+
// Can be set in case the resource has more than a single identifier that is used in the positional arguments.
27+
// See [UpdateCmd.PositionalArgumentOverride].
28+
FetchWithArgs func(s state.State, cmd *cobra.Command, args []string) (any, *hcloud.Response, error)
29+
30+
Update func(s state.State, cmd *cobra.Command, resource interface{}, flags map[string]pflag.Value) error
31+
32+
// In case the resource does not have a single identifier that matches [UpdateCmd.ResourceNameSingular], this field
33+
// can be set to define the list of positional arguments.
34+
// For example, passing:
35+
// []string{"a", "b", "c"}
36+
// Would result in the usage string:
37+
// <a> <b> <c>
38+
PositionalArgumentOverride []string
39+
40+
// Can be set if the default [UpdateCmd.NameSuggestions] is not enough. This is usually the case when
41+
// [UpdateCmd.FetchWithArgs] and [UpdateCmd.PositionalArgumentOverride] is being used.
42+
ValidArgsFunction func(client hcapi2.Client) []cobra.CompletionFunc
2543

2644
// Experimental is a function that will be used to mark the command as experimental.
2745
Experimental func(state.State, *cobra.Command) *cobra.Command
2846
}
2947

3048
// CobraCommand creates a command that can be registered with cobra.
3149
func (uc *UpdateCmd) CobraCommand(s state.State) *cobra.Command {
50+
var suggestArgs []cobra.CompletionFunc
51+
switch {
52+
case uc.NameSuggestions != nil:
53+
suggestArgs = append(suggestArgs,
54+
cmpl.SuggestCandidatesF(uc.NameSuggestions(s.Client())),
55+
)
56+
case uc.ValidArgsFunction != nil:
57+
suggestArgs = append(suggestArgs, uc.ValidArgsFunction(s.Client())...)
58+
default:
59+
log.Fatalf("update command %s is missing ValidArgsFunction or NameSuggestions", uc.ResourceNameSingular)
60+
}
61+
3262
cmd := &cobra.Command{
33-
Use: fmt.Sprintf("update [options] <%s>", util.ToKebabCase(uc.ResourceNameSingular)),
63+
Use: fmt.Sprintf("update [options] %s", positionalArguments(uc.ResourceNameSingular, uc.PositionalArgumentOverride)),
3464
Short: uc.ShortDescription,
3565
Args: util.Validate,
36-
ValidArgsFunction: cmpl.SuggestArgs(cmpl.SuggestCandidatesF(uc.NameSuggestions(s.Client()))),
66+
ValidArgsFunction: cmpl.SuggestArgs(suggestArgs...),
3767
TraverseChildren: true,
3868
DisableFlagsInUseLine: true,
3969
PreRunE: util.ChainRunE(s.EnsureToken),
@@ -50,12 +80,21 @@ func (uc *UpdateCmd) CobraCommand(s state.State) *cobra.Command {
5080

5181
// Run executes a update command.
5282
func (uc *UpdateCmd) Run(s state.State, cmd *cobra.Command, args []string) error {
53-
idOrName := args[0]
54-
resource, _, err := uc.Fetch(s, cmd, idOrName)
83+
var (
84+
resource any
85+
err error
86+
)
87+
if uc.FetchWithArgs != nil {
88+
resource, _, err = uc.FetchWithArgs(s, cmd, args)
89+
} else {
90+
resource, _, err = uc.Fetch(s, cmd, args[0])
91+
}
5592
if err != nil {
5693
return err
5794
}
5895

96+
idOrName := args[len(args)-1]
97+
5998
// resource is an interface that always has a type, so the interface is never nil
6099
// (i.e. == nil) is always false.
61100
if reflect.ValueOf(resource).IsNil() {

0 commit comments

Comments
 (0)