diff --git a/internal/commands/server/delete.go b/internal/commands/server/delete.go index ae701bd83..8be787810 100644 --- a/internal/commands/server/delete.go +++ b/internal/commands/server/delete.go @@ -29,7 +29,7 @@ func DeleteCommand() commands.Command { type deleteCommand struct { *commands.BaseCommand resolver.CachingServer - completion.Server + completion.StoppedServer deleteStorages config.OptionalBoolean } diff --git a/internal/commands/server/restart.go b/internal/commands/server/restart.go index 794784e80..785ef4dfe 100644 --- a/internal/commands/server/restart.go +++ b/internal/commands/server/restart.go @@ -29,7 +29,7 @@ func RestartCommand() commands.Command { type restartCommand struct { *commands.BaseCommand resolver.CachingServer - completion.Server + completion.StartedServer WaitForServerToStart bool StopType string Host int diff --git a/internal/commands/server/start.go b/internal/commands/server/start.go index 1b1958560..c02f611e4 100644 --- a/internal/commands/server/start.go +++ b/internal/commands/server/start.go @@ -27,7 +27,7 @@ func StartCommand() commands.Command { type startCommand struct { *commands.BaseCommand - completion.Server + completion.StoppedServer resolver.CachingServer host int avoidHost int diff --git a/internal/commands/server/stop.go b/internal/commands/server/stop.go index 1ccad1147..03f1caee0 100644 --- a/internal/commands/server/stop.go +++ b/internal/commands/server/stop.go @@ -33,7 +33,7 @@ type stopCommand struct { StopType string wait config.OptionalBoolean resolver.CachingServer - completion.Server + completion.StartedServer } // InitCommand implements Command.InitCommand diff --git a/internal/completion/server.go b/internal/completion/server.go index 11689b0df..b236fcf26 100644 --- a/internal/completion/server.go +++ b/internal/completion/server.go @@ -2,6 +2,7 @@ package completion import ( "context" + "slices" "github.com/UpCloudLtd/upcloud-cli/v3/internal/service" "github.com/spf13/cobra" @@ -15,13 +16,41 @@ var _ Provider = Server{} // CompleteArgument implements completion.Provider func (s Server) CompleteArgument(ctx context.Context, svc service.AllServices, toComplete string) ([]string, cobra.ShellCompDirective) { + return completeServers(ctx, svc, toComplete) +} + +// StartedServer implements argument completion for started servers, by uuid, name or hostname. +type StartedServer struct{} + +// make sure StartedServer implements the interface +var _ Provider = StartedServer{} + +// CompleteArgument implements completion.Provider +func (s StartedServer) CompleteArgument(ctx context.Context, svc service.AllServices, toComplete string) ([]string, cobra.ShellCompDirective) { + return completeServers(ctx, svc, toComplete, "started") +} + +// Stopped implements argument completion for stopped servers, by uuid, name or hostname. +type StoppedServer struct{} + +// make sure StoppedServer implements the interface +var _ Provider = StoppedServer{} + +// CompleteArgument implements completion.Provider +func (s StoppedServer) CompleteArgument(ctx context.Context, svc service.AllServices, toComplete string) ([]string, cobra.ShellCompDirective) { + return completeServers(ctx, svc, toComplete, "stopped") +} + +func completeServers(ctx context.Context, svc service.AllServices, toComplete string, states ...string) ([]string, cobra.ShellCompDirective) { servers, err := svc.GetServers(ctx) if err != nil { return None(toComplete) } var vals []string for _, v := range servers.Servers { - vals = append(vals, v.UUID, v.Hostname, v.Title) + if len(states) == 0 || slices.Contains(states, v.State) { + vals = append(vals, v.UUID, v.Hostname, v.Title) + } } return MatchStringPrefix(vals, toComplete, true), cobra.ShellCompDirectiveNoFileComp } diff --git a/internal/completion/server_test.go b/internal/completion/server_test.go index 6f660376c..0133adfed 100644 --- a/internal/completion/server_test.go +++ b/internal/completion/server_test.go @@ -19,9 +19,14 @@ var mockServers = &upcloud.Servers{Servers: []upcloud.Server{ {Title: "bock1", UUID: "jklmno", Hostname: "faa"}, {Title: "bock2", UUID: "pqrstu", Hostname: "fii"}, {Title: "dock1", UUID: "vwxyzä", Hostname: "bfoo"}, + {Title: "case started", UUID: "started", Hostname: "astarted", State: "started"}, + {Title: "case stopped", UUID: "stopped", Hostname: "astopped", State: "stopped"}, }} func TestServer_CompleteArgument(t *testing.T) { + mService := new(smock.Service) + mService.On("GetServers", mock.Anything).Return(mockServers, nil) + for _, test := range []struct { name string complete string @@ -37,13 +42,23 @@ func TestServer_CompleteArgument(t *testing.T) { {name: "hostnames and titles", complete: "b", expectedMatches: []string{"bock1", "bock2", "bfoo"}, expectedDirective: cobra.ShellCompDirectiveNoFileComp}, } { t.Run(test.name, func(t *testing.T) { - mService := new(smock.Service) - mService.On("GetServers", mock.Anything).Return(mockServers, nil) - ips, directive := completion.Server{}.CompleteArgument(context.TODO(), mService, test.complete) - assert.Equal(t, test.expectedMatches, ips) + servers, directive := completion.Server{}.CompleteArgument(context.TODO(), mService, test.complete) + assert.Equal(t, test.expectedMatches, servers) assert.Equal(t, test.expectedDirective, directive) }) } + + t.Run("stopped", func(t *testing.T) { + servers, directive := completion.StoppedServer{}.CompleteArgument(context.TODO(), mService, "s") + assert.Equal(t, []string{"stopped"}, servers) + assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, directive) + }) + + t.Run("started", func(t *testing.T) { + servers, directive := completion.StartedServer{}.CompleteArgument(context.TODO(), mService, "s") + assert.Equal(t, []string{"started"}, servers) + assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, directive) + }) } func TestServer_CompleteArgumentServiceFail(t *testing.T) {