Fetch codespace by name directly if name argument given

This commit is contained in:
Mislav Marohnić 2021-09-23 18:57:22 +02:00
parent e8212a80a9
commit 75c1dfdf49
4 changed files with 174 additions and 33 deletions

View file

@ -28,14 +28,16 @@ type deleteOptions struct {
prompter prompter
}
//go:generate moq -fmt goimports -rm -out mock_prompter.go . prompter
//go:generate moq -fmt goimports -rm -skip-ensure -out mock_prompter.go . prompter
type prompter interface {
Confirm(message string) (bool, error)
}
//go:generate moq -fmt goimports -rm -out mock_api.go . apiClient
//go:generate moq -fmt goimports -rm -skip-ensure -out mock_api.go . apiClient
type apiClient interface {
GetUser(ctx context.Context) (*api.User, error)
GetCodespaceToken(ctx context.Context, user, name string) (string, error)
GetCodespace(ctx context.Context, token, user, name string) (*api.Codespace, error)
ListCodespaces(ctx context.Context, user string) ([]*api.Codespace, error)
DeleteCodespace(ctx context.Context, user, name string) error
}
@ -80,18 +82,34 @@ func delete(ctx context.Context, log logger, opts deleteOptions) error {
return fmt.Errorf("error getting user: %w", err)
}
codespaces, err := opts.apiClient.ListCodespaces(ctx, user.Login)
if err != nil {
return fmt.Errorf("error getting codespaces: %w", err)
}
var codespaces []*api.Codespace
nameFilter := opts.codespaceName
if nameFilter == "" && !opts.deleteAll && opts.repoFilter == "" {
c, err := chooseCodespaceFromList(ctx, codespaces)
if nameFilter == "" {
codespaces, err = opts.apiClient.ListCodespaces(ctx, user.Login)
if err != nil {
return fmt.Errorf("error choosing codespace: %w", err)
return fmt.Errorf("error getting codespaces: %w", err)
}
nameFilter = c.Name
if !opts.deleteAll && opts.repoFilter == "" {
c, err := chooseCodespaceFromList(ctx, codespaces)
if err != nil {
return fmt.Errorf("error choosing codespace: %w", err)
}
nameFilter = c.Name
}
} else {
// TODO: this token is discarded and then re-requested later in DeleteCodespace
token, err := opts.apiClient.GetCodespaceToken(ctx, user.Login, nameFilter)
if err != nil {
return fmt.Errorf("error getting codespace token: %w", err)
}
codespace, err := opts.apiClient.GetCodespace(ctx, token, user.Login, nameFilter)
if err != nil {
return fmt.Errorf("error fetching codespace information: %w", err)
}
codespaces = []*api.Codespace{codespace}
}
codespacesToDelete := make([]*api.Codespace, 0, len(codespaces))
@ -112,7 +130,7 @@ func delete(ctx context.Context, log logger, opts deleteOptions) error {
continue
}
}
if nameFilter == "" || !opts.skipConfirm {
if !opts.skipConfirm {
confirmed, err := confirmDeletion(opts.prompter, c, opts.isInteractive)
if err != nil {
return fmt.Errorf("unable to confirm: %w", err)
@ -133,7 +151,7 @@ func delete(ctx context.Context, log logger, opts deleteOptions) error {
codespaceName := c.Name
g.Go(func() error {
if err := opts.apiClient.DeleteCodespace(ctx, user.Login, codespaceName); err != nil {
log.Errorf("error deleting codespace %q: %v", codespaceName, err)
_, _ = log.Errorf("error deleting codespace %q: %v", codespaceName, err)
return err
}
return nil

View file

@ -31,9 +31,6 @@ func TestDelete(t *testing.T) {
codespaceName: "hubot-robawt-abc",
},
codespaces: []*api.Codespace{
{
Name: "monalisa-spoonknife-123",
},
{
Name: "hubot-robawt-abc",
},
@ -130,12 +127,6 @@ func TestDelete(t *testing.T) {
GetUserFunc: func(_ context.Context) (*api.User, error) {
return user, nil
},
ListCodespacesFunc: func(_ context.Context, userLogin string) ([]*api.Codespace, error) {
if userLogin != user.Login {
return nil, fmt.Errorf("unexpected user %q", userLogin)
}
return tt.codespaces, nil
},
DeleteCodespaceFunc: func(_ context.Context, userLogin, name string) error {
if userLogin != user.Login {
return fmt.Errorf("unexpected user %q", userLogin)
@ -143,6 +134,30 @@ func TestDelete(t *testing.T) {
return nil
},
}
if tt.opts.codespaceName == "" {
apiMock.ListCodespacesFunc = func(_ context.Context, userLogin string) ([]*api.Codespace, error) {
if userLogin != user.Login {
return nil, fmt.Errorf("unexpected user %q", userLogin)
}
return tt.codespaces, nil
}
} else {
apiMock.GetCodespaceTokenFunc = func(_ context.Context, userLogin, name string) (string, error) {
if userLogin != user.Login {
return "", fmt.Errorf("unexpected user %q", userLogin)
}
return "CS_TOKEN", nil
}
apiMock.GetCodespaceFunc = func(_ context.Context, token, userLogin, name string) (*api.Codespace, error) {
if userLogin != user.Login {
return nil, fmt.Errorf("unexpected user %q", userLogin)
}
if token != "CS_TOKEN" {
return nil, fmt.Errorf("unexpected token %q", token)
}
return tt.codespaces[0], nil
}
}
opts := tt.opts
opts.apiClient = apiMock
opts.now = func() time.Time { return now }

View file

@ -10,10 +10,6 @@ import (
"github.com/github/ghcs/internal/api"
)
// Ensure, that apiClientMock does implement apiClient.
// If this is not the case, regenerate this file with moq.
var _ apiClient = &apiClientMock{}
// apiClientMock is a mock implementation of apiClient.
//
// func TestSomethingThatUsesapiClient(t *testing.T) {
@ -23,6 +19,12 @@ var _ apiClient = &apiClientMock{}
// DeleteCodespaceFunc: func(ctx context.Context, user string, name string) error {
// panic("mock out the DeleteCodespace method")
// },
// GetCodespaceFunc: func(ctx context.Context, token string, user string, name string) (*api.Codespace, error) {
// panic("mock out the GetCodespace method")
// },
// GetCodespaceTokenFunc: func(ctx context.Context, user string, name string) (string, error) {
// panic("mock out the GetCodespaceToken method")
// },
// GetUserFunc: func(ctx context.Context) (*api.User, error) {
// panic("mock out the GetUser method")
// },
@ -39,6 +41,12 @@ type apiClientMock struct {
// DeleteCodespaceFunc mocks the DeleteCodespace method.
DeleteCodespaceFunc func(ctx context.Context, user string, name string) error
// GetCodespaceFunc mocks the GetCodespace method.
GetCodespaceFunc func(ctx context.Context, token string, user string, name string) (*api.Codespace, error)
// GetCodespaceTokenFunc mocks the GetCodespaceToken method.
GetCodespaceTokenFunc func(ctx context.Context, user string, name string) (string, error)
// GetUserFunc mocks the GetUser method.
GetUserFunc func(ctx context.Context) (*api.User, error)
@ -56,6 +64,26 @@ type apiClientMock struct {
// Name is the name argument value.
Name string
}
// GetCodespace holds details about calls to the GetCodespace method.
GetCodespace []struct {
// Ctx is the ctx argument value.
Ctx context.Context
// Token is the token argument value.
Token string
// User is the user argument value.
User string
// Name is the name argument value.
Name string
}
// GetCodespaceToken holds details about calls to the GetCodespaceToken method.
GetCodespaceToken []struct {
// Ctx is the ctx argument value.
Ctx context.Context
// User is the user argument value.
User string
// Name is the name argument value.
Name string
}
// GetUser holds details about calls to the GetUser method.
GetUser []struct {
// Ctx is the ctx argument value.
@ -69,9 +97,11 @@ type apiClientMock struct {
User string
}
}
lockDeleteCodespace sync.RWMutex
lockGetUser sync.RWMutex
lockListCodespaces sync.RWMutex
lockDeleteCodespace sync.RWMutex
lockGetCodespace sync.RWMutex
lockGetCodespaceToken sync.RWMutex
lockGetUser sync.RWMutex
lockListCodespaces sync.RWMutex
}
// DeleteCodespace calls DeleteCodespaceFunc.
@ -113,6 +143,88 @@ func (mock *apiClientMock) DeleteCodespaceCalls() []struct {
return calls
}
// GetCodespace calls GetCodespaceFunc.
func (mock *apiClientMock) GetCodespace(ctx context.Context, token string, user string, name string) (*api.Codespace, error) {
if mock.GetCodespaceFunc == nil {
panic("apiClientMock.GetCodespaceFunc: method is nil but apiClient.GetCodespace was just called")
}
callInfo := struct {
Ctx context.Context
Token string
User string
Name string
}{
Ctx: ctx,
Token: token,
User: user,
Name: name,
}
mock.lockGetCodespace.Lock()
mock.calls.GetCodespace = append(mock.calls.GetCodespace, callInfo)
mock.lockGetCodespace.Unlock()
return mock.GetCodespaceFunc(ctx, token, user, name)
}
// GetCodespaceCalls gets all the calls that were made to GetCodespace.
// Check the length with:
// len(mockedapiClient.GetCodespaceCalls())
func (mock *apiClientMock) GetCodespaceCalls() []struct {
Ctx context.Context
Token string
User string
Name string
} {
var calls []struct {
Ctx context.Context
Token string
User string
Name string
}
mock.lockGetCodespace.RLock()
calls = mock.calls.GetCodespace
mock.lockGetCodespace.RUnlock()
return calls
}
// GetCodespaceToken calls GetCodespaceTokenFunc.
func (mock *apiClientMock) GetCodespaceToken(ctx context.Context, user string, name string) (string, error) {
if mock.GetCodespaceTokenFunc == nil {
panic("apiClientMock.GetCodespaceTokenFunc: method is nil but apiClient.GetCodespaceToken was just called")
}
callInfo := struct {
Ctx context.Context
User string
Name string
}{
Ctx: ctx,
User: user,
Name: name,
}
mock.lockGetCodespaceToken.Lock()
mock.calls.GetCodespaceToken = append(mock.calls.GetCodespaceToken, callInfo)
mock.lockGetCodespaceToken.Unlock()
return mock.GetCodespaceTokenFunc(ctx, user, name)
}
// GetCodespaceTokenCalls gets all the calls that were made to GetCodespaceToken.
// Check the length with:
// len(mockedapiClient.GetCodespaceTokenCalls())
func (mock *apiClientMock) GetCodespaceTokenCalls() []struct {
Ctx context.Context
User string
Name string
} {
var calls []struct {
Ctx context.Context
User string
Name string
}
mock.lockGetCodespaceToken.RLock()
calls = mock.calls.GetCodespaceToken
mock.lockGetCodespaceToken.RUnlock()
return calls
}
// GetUser calls GetUserFunc.
func (mock *apiClientMock) GetUser(ctx context.Context) (*api.User, error) {
if mock.GetUserFunc == nil {

View file

@ -7,10 +7,6 @@ import (
"sync"
)
// Ensure, that prompterMock does implement prompter.
// If this is not the case, regenerate this file with moq.
var _ prompter = &prompterMock{}
// prompterMock is a mock implementation of prompter.
//
// func TestSomethingThatUsesprompter(t *testing.T) {