Skip to content

Commit

Permalink
feat(token): completion improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
scop committed Feb 4, 2025
1 parent 08f11e5 commit 1c18808
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 1 deletion.
2 changes: 1 addition & 1 deletion internal/commands/tokens/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (s *createCommand) InitCommand() {
applyCreateFlags(s.flagSet, &s.params, defaultCreateParams)

s.AddFlags(s.flagSet)
_ = s.Cobra().MarkFlagRequired("name")
commands.Must(s.Cobra().MarkFlagRequired("name"))
}

// ExecuteWithoutArguments implements commands.NoArgumentCommand
Expand Down
4 changes: 4 additions & 0 deletions internal/commands/tokens/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package tokens

import (
"fmt"
"github.com/UpCloudLtd/upcloud-cli/v3/internal/completion"
"github.com/UpCloudLtd/upcloud-cli/v3/internal/resolver"

"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands"
"github.com/UpCloudLtd/upcloud-cli/v3/internal/output"
Expand All @@ -21,6 +23,8 @@ func DeleteCommand() commands.Command {

type deleteCommand struct {
*commands.BaseCommand
resolver.CachingToken
completion.Token
}

// Execute implements commands.MultipleArgumentCommand
Expand Down
4 changes: 4 additions & 0 deletions internal/commands/tokens/show.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package tokens

import (
"github.com/UpCloudLtd/upcloud-cli/v3/internal/commands"
"github.com/UpCloudLtd/upcloud-cli/v3/internal/completion"
"github.com/UpCloudLtd/upcloud-cli/v3/internal/output"
"github.com/UpCloudLtd/upcloud-cli/v3/internal/resolver"
"github.com/UpCloudLtd/upcloud-cli/v3/internal/ui"
"github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/request"
)
Expand All @@ -20,6 +22,8 @@ func ShowCommand() commands.Command {

type showCommand struct {
*commands.BaseCommand
resolver.CachingToken
completion.Token
}

// Execute implements commands.MultipleArgumentCommand
Expand Down
28 changes: 28 additions & 0 deletions internal/completion/token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package completion

import (
"context"
"github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/request"

"github.com/UpCloudLtd/upcloud-cli/v3/internal/service"
"github.com/spf13/cobra"
)

// Token implements argument completion for tokens, by id.
type Token struct{}

// make sure Token implements the interface
var _ Provider = Token{}

// CompleteArgument implements completion.Provider
func (s Token) CompleteArgument(ctx context.Context, svc service.AllServices, toComplete string) ([]string, cobra.ShellCompDirective) {
tokens, err := svc.GetTokens(ctx, &request.GetTokensRequest{})
if err != nil {
return None(toComplete)
}
var vals []string
for _, t := range *tokens {
vals = append(vals, t.ID)
}
return MatchStringPrefix(vals, toComplete, true), cobra.ShellCompDirectiveNoFileComp
}
57 changes: 57 additions & 0 deletions internal/completion/token_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package completion_test

import (
"context"
"fmt"
"testing"

"github.com/UpCloudLtd/upcloud-cli/v3/internal/completion"
smock "github.com/UpCloudLtd/upcloud-cli/v3/internal/mock"

"github.com/UpCloudLtd/upcloud-go-api/v8/upcloud"
"github.com/spf13/cobra"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

var mockTokens = &upcloud.Tokens{
{Name: "mock1", ID: "0c1eadbe-efde-adbe-efde-adbeefdeadbe"},
{Name: "mock2", ID: "0c2eadbe-efde-adbe-efde-adbeefdeadbe"},
{Name: "bock1", ID: "0c3eadbe-efde-adbe-efde-adbeefdeadbe"},
{Name: "bock2", ID: "0c4eadbe-efde-adbe-efde-adbeefdeadbe"},
{Name: "dock1", ID: "0c5eadbe-efde-adbe-efde-adbeefdeadbe"},
}

func TestToken_CompleteArgument(t *testing.T) {
for _, test := range []struct {
name string
complete string
expectedMatches []string
expectedDirective cobra.ShellCompDirective
}{
{name: "basic id", complete: "0c2", expectedMatches: []string{"0c2eadbe-efde-adbe-efde-adbeefdeadbe"}, expectedDirective: cobra.ShellCompDirectiveNoFileComp},
{name: "multiple ids", complete: "0c", expectedMatches: []string{
"0c1eadbe-efde-adbe-efde-adbeefdeadbe",
"0c2eadbe-efde-adbe-efde-adbeefdeadbe",
"0c3eadbe-efde-adbe-efde-adbeefdeadbe",
"0c4eadbe-efde-adbe-efde-adbeefdeadbe",
"0c5eadbe-efde-adbe-efde-adbeefdeadbe",
}, expectedDirective: cobra.ShellCompDirectiveNoFileComp},
} {
t.Run(test.name, func(t *testing.T) {
mService := new(smock.Service)
mService.On("GetTokens", mock.Anything).Return(mockTokens, nil)
tokens, directive := completion.Token{}.CompleteArgument(context.TODO(), mService, test.complete)
assert.Equal(t, test.expectedMatches, tokens)
assert.Equal(t, test.expectedDirective, directive)
})
}
}

func TestToken_CompleteArgumentServiceFail(t *testing.T) {
mService := new(smock.Service)
mService.On("GetTokens", mock.Anything).Return(nil, fmt.Errorf("MOCKFAIL"))
tokens, directive := completion.Token{}.CompleteArgument(context.TODO(), mService, "FOO")
assert.Nil(t, tokens)
assert.Equal(t, cobra.ShellCompDirectiveDefault, directive)
}
34 changes: 34 additions & 0 deletions internal/resolver/token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package resolver

import (
"context"

internal "github.com/UpCloudLtd/upcloud-cli/v3/internal/service"
"github.com/UpCloudLtd/upcloud-go-api/v8/upcloud/request"
)

// CachingToken implements resolver for tokens, caching the results.
type CachingToken struct{}

// make sure we implement the ResolutionProvider interface
var _ ResolutionProvider = CachingToken{}

// Get implements ResolutionProvider.Get
func (s CachingToken) Get(ctx context.Context, svc internal.AllServices) (Resolver, error) {
tokens, err := svc.GetTokens(ctx, &request.GetTokensRequest{})
if err != nil {
return nil, err
}
return func(arg string) Resolved {
rv := Resolved{Arg: arg}
for _, token := range *tokens {
rv.AddMatch(token.ID, MatchArgWithWhitespace(arg, token.ID))
}
return rv
}, nil
}

// PositionalArgumentHelp implements resolver.ResolutionProvider
func (s CachingToken) PositionalArgumentHelp() string {
return "<ID...>"
}

0 comments on commit 1c18808

Please sign in to comment.