Skip to content

Commit c03bbbb

Browse files
authored
feat(server): take stopped/started state into account in completions (#332)
We could add some more to avoid various other completions for servers let's say in `maintenance` state, but this covers the most common cases for now.
1 parent 1a1a673 commit c03bbbb

7 files changed

Lines changed: 57 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
12+
- Take server state into account in server completions. For example, do not offer started servers as completions for `server start` command.
13+
1014
## [3.11.1] - 2024-08-12
1115

1216
### Fixed

internal/commands/server/delete.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func DeleteCommand() commands.Command {
2929
type deleteCommand struct {
3030
*commands.BaseCommand
3131
resolver.CachingServer
32-
completion.Server
32+
completion.StoppedServer
3333
deleteStorages config.OptionalBoolean
3434
}
3535

internal/commands/server/restart.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func RestartCommand() commands.Command {
2929
type restartCommand struct {
3030
*commands.BaseCommand
3131
resolver.CachingServer
32-
completion.Server
32+
completion.StartedServer
3333
WaitForServerToStart bool
3434
StopType string
3535
Host int

internal/commands/server/start.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ func StartCommand() commands.Command {
2727

2828
type startCommand struct {
2929
*commands.BaseCommand
30-
completion.Server
30+
completion.StoppedServer
3131
resolver.CachingServer
3232
host int
3333
avoidHost int

internal/commands/server/stop.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ type stopCommand struct {
3333
StopType string
3434
wait config.OptionalBoolean
3535
resolver.CachingServer
36-
completion.Server
36+
completion.StartedServer
3737
}
3838

3939
// InitCommand implements Command.InitCommand

internal/completion/server.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package completion
22

33
import (
44
"context"
5+
"slices"
56

67
"github.com/UpCloudLtd/upcloud-cli/v3/internal/service"
78
"github.com/spf13/cobra"
@@ -15,13 +16,41 @@ var _ Provider = Server{}
1516

1617
// CompleteArgument implements completion.Provider
1718
func (s Server) CompleteArgument(ctx context.Context, svc service.AllServices, toComplete string) ([]string, cobra.ShellCompDirective) {
19+
return completeServers(ctx, svc, toComplete)
20+
}
21+
22+
// StartedServer implements argument completion for started servers, by uuid, name or hostname.
23+
type StartedServer struct{}
24+
25+
// make sure StartedServer implements the interface
26+
var _ Provider = StartedServer{}
27+
28+
// CompleteArgument implements completion.Provider
29+
func (s StartedServer) CompleteArgument(ctx context.Context, svc service.AllServices, toComplete string) ([]string, cobra.ShellCompDirective) {
30+
return completeServers(ctx, svc, toComplete, "started")
31+
}
32+
33+
// Stopped implements argument completion for stopped servers, by uuid, name or hostname.
34+
type StoppedServer struct{}
35+
36+
// make sure StoppedServer implements the interface
37+
var _ Provider = StoppedServer{}
38+
39+
// CompleteArgument implements completion.Provider
40+
func (s StoppedServer) CompleteArgument(ctx context.Context, svc service.AllServices, toComplete string) ([]string, cobra.ShellCompDirective) {
41+
return completeServers(ctx, svc, toComplete, "stopped")
42+
}
43+
44+
func completeServers(ctx context.Context, svc service.AllServices, toComplete string, states ...string) ([]string, cobra.ShellCompDirective) {
1845
servers, err := svc.GetServers(ctx)
1946
if err != nil {
2047
return None(toComplete)
2148
}
2249
var vals []string
2350
for _, v := range servers.Servers {
24-
vals = append(vals, v.UUID, v.Hostname, v.Title)
51+
if len(states) == 0 || slices.Contains(states, v.State) {
52+
vals = append(vals, v.UUID, v.Hostname, v.Title)
53+
}
2554
}
2655
return MatchStringPrefix(vals, toComplete, true), cobra.ShellCompDirectiveNoFileComp
2756
}

internal/completion/server_test.go

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,14 @@ var mockServers = &upcloud.Servers{Servers: []upcloud.Server{
1919
{Title: "bock1", UUID: "jklmno", Hostname: "faa"},
2020
{Title: "bock2", UUID: "pqrstu", Hostname: "fii"},
2121
{Title: "dock1", UUID: "vwxyzä", Hostname: "bfoo"},
22+
{Title: "case started", UUID: "started", Hostname: "astarted", State: "started"},
23+
{Title: "case stopped", UUID: "stopped", Hostname: "astopped", State: "stopped"},
2224
}}
2325

2426
func TestServer_CompleteArgument(t *testing.T) {
27+
mService := new(smock.Service)
28+
mService.On("GetServers", mock.Anything).Return(mockServers, nil)
29+
2530
for _, test := range []struct {
2631
name string
2732
complete string
@@ -37,13 +42,23 @@ func TestServer_CompleteArgument(t *testing.T) {
3742
{name: "hostnames and titles", complete: "b", expectedMatches: []string{"bock1", "bock2", "bfoo"}, expectedDirective: cobra.ShellCompDirectiveNoFileComp},
3843
} {
3944
t.Run(test.name, func(t *testing.T) {
40-
mService := new(smock.Service)
41-
mService.On("GetServers", mock.Anything).Return(mockServers, nil)
42-
ips, directive := completion.Server{}.CompleteArgument(context.TODO(), mService, test.complete)
43-
assert.Equal(t, test.expectedMatches, ips)
45+
servers, directive := completion.Server{}.CompleteArgument(context.TODO(), mService, test.complete)
46+
assert.Equal(t, test.expectedMatches, servers)
4447
assert.Equal(t, test.expectedDirective, directive)
4548
})
4649
}
50+
51+
t.Run("stopped", func(t *testing.T) {
52+
servers, directive := completion.StoppedServer{}.CompleteArgument(context.TODO(), mService, "s")
53+
assert.Equal(t, []string{"stopped"}, servers)
54+
assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, directive)
55+
})
56+
57+
t.Run("started", func(t *testing.T) {
58+
servers, directive := completion.StartedServer{}.CompleteArgument(context.TODO(), mService, "s")
59+
assert.Equal(t, []string{"started"}, servers)
60+
assert.Equal(t, cobra.ShellCompDirectiveNoFileComp, directive)
61+
})
4762
}
4863

4964
func TestServer_CompleteArgumentServiceFail(t *testing.T) {

0 commit comments

Comments
 (0)