Merge branch 'trunk' of github.com:cli/cli into jg/choose-codespace-prompt

This commit is contained in:
Jose Garcia 2021-10-06 09:57:39 -04:00
commit 017632d63d
12 changed files with 72 additions and 245 deletions

View file

@ -180,77 +180,28 @@ func (a *API) ListCodespaces(ctx context.Context) ([]*codespace.Codespace, error
return response.Codespaces, nil
}
// getCodespaceTokenRequest is the request body for the get codespace token endpoint.
type getCodespaceTokenRequest struct {
MintRepositoryToken bool `json:"mint_repository_token"`
}
type getCodespaceTokenResponse struct {
RepositoryToken string `json:"repository_token"`
}
// ErrNotProvisioned is returned by GetCodespacesToken to indicate that the
// creation of a codespace is not yet complete and that the caller should try again.
var ErrNotProvisioned = errors.New("codespace not provisioned")
// GetCodespaceToken returns a codespace token for the user.
func (a *API) GetCodespaceToken(ctx context.Context, ownerLogin, codespaceName string) (string, error) {
reqBody, err := json.Marshal(getCodespaceTokenRequest{true})
if err != nil {
return "", fmt.Errorf("error preparing request body: %w", err)
}
req, err := http.NewRequest(
http.MethodPost,
a.githubAPI+"/vscs_internal/user/"+ownerLogin+"/codespaces/"+codespaceName+"/token",
bytes.NewBuffer(reqBody),
)
if err != nil {
return "", fmt.Errorf("error creating request: %w", err)
}
a.setHeaders(req)
resp, err := a.do(ctx, req, "/vscs_internal/user/*/codespaces/*/token")
if err != nil {
return "", fmt.Errorf("error making request: %w", err)
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("error reading response body: %w", err)
}
if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusUnprocessableEntity {
return "", ErrNotProvisioned
}
return "", jsonErrorResponse(b)
}
var response getCodespaceTokenResponse
if err := json.Unmarshal(b, &response); err != nil {
return "", fmt.Errorf("error unmarshaling response: %w", err)
}
return response.RepositoryToken, nil
}
// GetCodespace returns a codespace for the user.
func (a *API) GetCodespace(ctx context.Context, token, owner, codespaceName string) (*codespace.Codespace, error) {
// GetCodespace returns the user codespace based on the provided name.
// If the codespace is not found, an error is returned.
// If includeConnection is true, it will return the connection information for the codespace.
func (a *API) GetCodespace(ctx context.Context, codespaceName string, includeConnection bool) (*codespace.Codespace, error) {
req, err := http.NewRequest(
http.MethodGet,
a.githubAPI+"/vscs_internal/user/"+owner+"/codespaces/"+codespaceName,
a.githubAPI+"/user/codespaces/"+codespaceName,
nil,
)
if err != nil {
return nil, fmt.Errorf("error creating request: %w", err)
}
// TODO: use a.setHeaders()
req.Header.Set("Authorization", "Bearer "+token)
resp, err := a.do(ctx, req, "/vscs_internal/user/*/codespaces/*")
if includeConnection {
q := req.URL.Query()
q.Add("internal", "true")
q.Add("refresh", "true")
req.URL.RawQuery = q.Encode()
}
a.setHeaders(req)
resp, err := a.do(ctx, req, "/user/codespaces/*")
if err != nil {
return nil, fmt.Errorf("error making request: %w", err)
}
@ -397,7 +348,6 @@ func (a *API) GetCodespacesMachines(ctx context.Context, repoID int, branch, loc
// CreateCodespaceParams are the required parameters for provisioning a Codespace.
type CreateCodespaceParams struct {
User string
RepositoryID int
Branch, Machine, Location string
}
@ -405,9 +355,9 @@ type CreateCodespaceParams struct {
// CreateCodespace creates a codespace with the given parameters and returns a non-nil error if it
// fails to create.
func (a *API) CreateCodespace(ctx context.Context, params *CreateCodespaceParams) (*codespace.Codespace, error) {
codespace, err := a.startCreate(ctx, params.RepositoryID, params.Machine, params.Branch, params.Location)
cs, err := a.startCreate(ctx, params.RepositoryID, params.Machine, params.Branch, params.Location)
if err != errProvisioningInProgress {
return codespace, err
return nil, err
}
// errProvisioningInProgress indicates that codespace creation did not complete
@ -424,22 +374,17 @@ func (a *API) CreateCodespace(ctx context.Context, params *CreateCodespaceParams
case <-ctx.Done():
return nil, ctx.Err()
case <-ticker.C:
token, err := a.GetCodespaceToken(ctx, params.User, codespace.Name)
if err != nil {
if err == ErrNotProvisioned {
// Do nothing. We expect this to fail until the codespace is provisioned
continue
}
return nil, fmt.Errorf("failed to get codespace token: %w", err)
}
codespace, err = a.GetCodespace(ctx, token, params.User, codespace.Name)
cs, err = a.GetCodespace(ctx, cs.Name, false)
if err != nil {
return nil, fmt.Errorf("failed to get codespace: %w", err)
}
return codespace, nil
// we continue to poll until the codespace shows as provisioned
if cs.State != codespace.StateProvisioned {
continue
}
return cs, nil
}
}
}

View file

@ -6,6 +6,7 @@ type Codespace struct {
Name string `json:"name"`
CreatedAt string `json:"created_at"`
LastUsedAt string `json:"last_used_at"`
State string `json:"state"`
GUID string `json:"guid"`
Branch string `json:"branch"`
RepositoryName string `json:"repository_name"`
@ -14,6 +15,8 @@ type Codespace struct {
Environment Environment `json:"environment"`
}
const StateProvisioned = "provisioned"
// DisplayName returns the repository nwo and branch.
// If includeName is true, the name of the codespace is included.
// If includeGitStatus is true, the branch will include a star if

View file

@ -24,14 +24,13 @@ func connectionReady(cs *codespace.Codespace) bool {
}
type apiClient interface {
GetCodespace(ctx context.Context, token, user, name string) (*codespace.Codespace, error)
GetCodespaceToken(ctx context.Context, user, codespace string) (string, error)
GetCodespace(ctx context.Context, name string, includeConnection bool) (*codespace.Codespace, error)
StartCodespace(ctx context.Context, name string) error
}
// ConnectToLiveshare waits for a Codespace to become running,
// and connects to it using a Live Share session.
func ConnectToLiveshare(ctx context.Context, log logger, apiClient apiClient, userLogin, token string, cs *codespace.Codespace) (*liveshare.Session, error) {
func ConnectToLiveshare(ctx context.Context, log logger, apiClient apiClient, cs *codespace.Codespace) (*liveshare.Session, error) {
var startedCodespace bool
if cs.Environment.State != codespace.EnvironmentStateAvailable {
startedCodespace = true
@ -55,7 +54,7 @@ func ConnectToLiveshare(ctx context.Context, log logger, apiClient apiClient, us
}
var err error
cs, err = apiClient.GetCodespace(ctx, token, userLogin, cs.Name)
cs, err = apiClient.GetCodespace(ctx, cs.Name, true)
if err != nil {
return nil, fmt.Errorf("error getting codespace: %w", err)
}

View file

@ -9,7 +9,6 @@ import (
"strings"
"time"
"github.com/cli/cli/v2/internal/codespaces/api"
"github.com/cli/cli/v2/internal/codespaces/codespace"
"github.com/cli/cli/v2/pkg/liveshare"
)
@ -37,13 +36,8 @@ type PostCreateState struct {
// PollPostCreateStates watches for state changes in a codespace,
// and calls the supplied poller for each batch of state changes.
// It runs until it encounters an error, including cancellation of the context.
func PollPostCreateStates(ctx context.Context, log logger, apiClient apiClient, user *api.User, cs *codespace.Codespace, poller func([]PostCreateState)) (err error) {
token, err := apiClient.GetCodespaceToken(ctx, user.Login, cs.Name)
if err != nil {
return fmt.Errorf("getting codespace token: %w", err)
}
session, err := ConnectToLiveshare(ctx, log, apiClient, user.Login, token, cs)
func PollPostCreateStates(ctx context.Context, log logger, apiClient apiClient, cs *codespace.Codespace, poller func([]PostCreateState)) (err error) {
session, err := ConnectToLiveshare(ctx, log, apiClient, cs)
if err != nil {
return fmt.Errorf("connect to Live Share: %w", err)
}

View file

@ -35,8 +35,7 @@ func NewApp(logger *output.Logger, apiClient apiClient) *App {
//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) (*codespace.Codespace, error)
GetCodespace(ctx context.Context, name string, includeConnection bool) (*codespace.Codespace, error)
ListCodespaces(ctx context.Context) ([]*codespace.Codespace, error)
DeleteCodespace(ctx context.Context, name string) error
StartCodespace(ctx context.Context, name string) error
@ -136,35 +135,24 @@ func chooseCodespaceFromList(ctx context.Context, codespaces []*codespace.Codesp
}
// getOrChooseCodespace prompts the user to choose a codespace if the codespaceName is empty.
// It then fetches the codespace token and the codespace record.
func getOrChooseCodespace(ctx context.Context, apiClient apiClient, user *api.User, codespaceName string) (codespace *codespace.Codespace, token string, err error) {
// It then fetches the codespace record with full connection details.
func getOrChooseCodespace(ctx context.Context, apiClient apiClient, codespaceName string) (cs *codespace.Codespace, err error) {
if codespaceName == "" {
codespace, err = chooseCodespace(ctx, apiClient)
cs, err = chooseCodespace(ctx, apiClient)
if err != nil {
if err == errNoCodespaces {
return nil, "", err
return nil, err
}
return nil, "", fmt.Errorf("choosing codespace: %w", err)
}
codespaceName = codespace.Name
token, err = apiClient.GetCodespaceToken(ctx, user.Login, codespaceName)
if err != nil {
return nil, "", fmt.Errorf("getting codespace token: %w", err)
return nil, fmt.Errorf("choosing codespace: %w", err)
}
} else {
token, err = apiClient.GetCodespaceToken(ctx, user.Login, codespaceName)
cs, err = apiClient.GetCodespace(ctx, codespaceName, true)
if err != nil {
return nil, "", fmt.Errorf("getting codespace token for given codespace: %w", err)
}
codespace, err = apiClient.GetCodespace(ctx, token, user.Login, codespaceName)
if err != nil {
return nil, "", fmt.Errorf("getting full codespace details: %w", err)
return nil, fmt.Errorf("getting full codespace details: %w", err)
}
}
return codespace, token, nil
return cs, nil
}
func safeClose(closer io.Closer, err *error) {

View file

@ -82,7 +82,6 @@ func (a *App) Create(ctx context.Context, opts createOptions) error {
a.logger.Print("Creating your codespace...")
codespace, err := a.apiClient.CreateCodespace(ctx, &api.CreateCodespaceParams{
User: userResult.User.Login,
RepositoryID: repository.ID,
Branch: branch,
Machine: machine,
@ -158,7 +157,7 @@ func showStatus(ctx context.Context, log *output.Logger, apiClient apiClient, us
}
}
err := codespaces.PollPostCreateStates(ctx, log, apiClient, user, cs, poller)
err := codespaces.PollPostCreateStates(ctx, log, apiClient, cs, poller)
if err != nil {
if errors.Is(err, context.Canceled) && breakNextState {
return nil // we cancelled the context to stop polling, we can ignore the error

View file

@ -58,12 +58,7 @@ func newDeleteCmd(app *App) *cobra.Command {
return deleteCmd
}
func (a *App) Delete(ctx context.Context, opts deleteOptions) error {
user, err := a.apiClient.GetUser(ctx)
if err != nil {
return fmt.Errorf("error getting user: %w", err)
}
func (a *App) Delete(ctx context.Context, opts deleteOptions) (err error) {
var codespaces []*codespace.Codespace
nameFilter := opts.codespaceName
if nameFilter == "" {
@ -80,12 +75,7 @@ func (a *App) Delete(ctx context.Context, opts deleteOptions) error {
nameFilter = c.Name
}
} else {
token, err := a.apiClient.GetCodespaceToken(ctx, user.Login, nameFilter)
if err != nil {
return fmt.Errorf("error getting codespace token: %w", err)
}
cs, err := a.apiClient.GetCodespace(ctx, token, user.Login, nameFilter)
cs, err := a.apiClient.GetCodespace(ctx, nameFilter, false)
if err != nil {
return fmt.Errorf("error fetching codespace information: %w", err)
}

View file

@ -169,19 +169,7 @@ func TestDelete(t *testing.T) {
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) (*codespace.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)
}
apiMock.GetCodespaceFunc = func(_ context.Context, name string, includeConnection bool) (*codespace.Codespace, error) {
return tt.codespaces[0], nil
}
}
@ -207,9 +195,6 @@ func TestDelete(t *testing.T) {
if (err != nil) != tt.wantErr {
t.Errorf("delete() error = %v, wantErr %v", err, tt.wantErr)
}
if n := len(apiMock.GetUserCalls()); n != 1 {
t.Errorf("GetUser invoked %d times, expected %d", n, 1)
}
var gotDeleted []string
for _, delArgs := range apiMock.DeleteCodespaceCalls() {
gotDeleted = append(gotDeleted, delArgs.Name)

View file

@ -46,12 +46,12 @@ func (a *App) Logs(ctx context.Context, codespaceName string, follow bool) (err
authkeys <- checkAuthorizedKeys(ctx, a.apiClient, user.Login)
}()
codespace, token, err := getOrChooseCodespace(ctx, a.apiClient, user, codespaceName)
codespace, err := getOrChooseCodespace(ctx, a.apiClient, codespaceName)
if err != nil {
return fmt.Errorf("get or choose codespace: %w", err)
}
session, err := codespaces.ConnectToLiveshare(ctx, a.logger, a.apiClient, user.Login, token, codespace)
session, err := codespaces.ConnectToLiveshare(ctx, a.logger, a.apiClient, codespace)
if err != nil {
return fmt.Errorf("connecting to Live Share: %w", err)
}

View file

@ -26,7 +26,7 @@ import (
// DeleteCodespaceFunc: func(ctx context.Context, name string) error {
// panic("mock out the DeleteCodespace method")
// },
// GetCodespaceFunc: func(ctx context.Context, token string, user string, name string) (*codespace.Codespace, error) {
// GetCodespaceFunc: func(ctx context.Context, name string, includeConnection bool) (*codespace.Codespace, error) {
// panic("mock out the GetCodespace method")
// },
// GetCodespaceRegionLocationFunc: func(ctx context.Context) (string, error) {
@ -35,9 +35,6 @@ import (
// GetCodespaceRepositoryContentsFunc: func(ctx context.Context, codespaceMoqParam *codespace.Codespace, path string) ([]byte, error) {
// panic("mock out the GetCodespaceRepositoryContents method")
// },
// GetCodespaceTokenFunc: func(ctx context.Context, user string, name string) (string, error) {
// panic("mock out the GetCodespaceToken method")
// },
// GetCodespacesMachinesFunc: func(ctx context.Context, repoID int, branch string, location string) ([]*api.Machine, error) {
// panic("mock out the GetCodespacesMachines method")
// },
@ -70,7 +67,7 @@ type apiClientMock struct {
DeleteCodespaceFunc func(ctx context.Context, name string) error
// GetCodespaceFunc mocks the GetCodespace method.
GetCodespaceFunc func(ctx context.Context, token string, user string, name string) (*codespace.Codespace, error)
GetCodespaceFunc func(ctx context.Context, name string, includeConnection bool) (*codespace.Codespace, error)
// GetCodespaceRegionLocationFunc mocks the GetCodespaceRegionLocation method.
GetCodespaceRegionLocationFunc func(ctx context.Context) (string, error)
@ -78,9 +75,6 @@ type apiClientMock struct {
// GetCodespaceRepositoryContentsFunc mocks the GetCodespaceRepositoryContents method.
GetCodespaceRepositoryContentsFunc func(ctx context.Context, codespaceMoqParam *codespace.Codespace, path string) ([]byte, error)
// GetCodespaceTokenFunc mocks the GetCodespaceToken method.
GetCodespaceTokenFunc func(ctx context.Context, user string, name string) (string, error)
// GetCodespacesMachinesFunc mocks the GetCodespacesMachines method.
GetCodespacesMachinesFunc func(ctx context.Context, repoID int, branch string, location string) ([]*api.Machine, error)
@ -123,12 +117,10 @@ type apiClientMock struct {
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
// IncludeConnection is the includeConnection argument value.
IncludeConnection bool
}
// GetCodespaceRegionLocation holds details about calls to the GetCodespaceRegionLocation method.
GetCodespaceRegionLocation []struct {
@ -144,15 +136,6 @@ type apiClientMock struct {
// Path is the path argument value.
Path 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
}
// GetCodespacesMachines holds details about calls to the GetCodespacesMachines method.
GetCodespacesMachines []struct {
// Ctx is the ctx argument value.
@ -195,7 +178,6 @@ type apiClientMock struct {
lockGetCodespace sync.RWMutex
lockGetCodespaceRegionLocation sync.RWMutex
lockGetCodespaceRepositoryContents sync.RWMutex
lockGetCodespaceToken sync.RWMutex
lockGetCodespacesMachines sync.RWMutex
lockGetRepository sync.RWMutex
lockGetUser sync.RWMutex
@ -309,41 +291,37 @@ func (mock *apiClientMock) DeleteCodespaceCalls() []struct {
}
// GetCodespace calls GetCodespaceFunc.
func (mock *apiClientMock) GetCodespace(ctx context.Context, token string, user string, name string) (*codespace.Codespace, error) {
func (mock *apiClientMock) GetCodespace(ctx context.Context, name string, includeConnection bool) (*codespace.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 context.Context
Name string
IncludeConnection bool
}{
Ctx: ctx,
Token: token,
User: user,
Name: name,
Ctx: ctx,
Name: name,
IncludeConnection: includeConnection,
}
mock.lockGetCodespace.Lock()
mock.calls.GetCodespace = append(mock.calls.GetCodespace, callInfo)
mock.lockGetCodespace.Unlock()
return mock.GetCodespaceFunc(ctx, token, user, name)
return mock.GetCodespaceFunc(ctx, name, includeConnection)
}
// 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
Ctx context.Context
Name string
IncludeConnection bool
} {
var calls []struct {
Ctx context.Context
Token string
User string
Name string
Ctx context.Context
Name string
IncludeConnection bool
}
mock.lockGetCodespace.RLock()
calls = mock.calls.GetCodespace
@ -421,45 +399,6 @@ func (mock *apiClientMock) GetCodespaceRepositoryContentsCalls() []struct {
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
}
// GetCodespacesMachines calls GetCodespacesMachinesFunc.
func (mock *apiClientMock) GetCodespacesMachines(ctx context.Context, repoID int, branch string, location string) ([]*api.Machine, error) {
if mock.GetCodespacesMachinesFunc == nil {

View file

@ -49,12 +49,7 @@ func newPortsCmd(app *App) *cobra.Command {
// ListPorts lists known ports in a codespace.
func (a *App) ListPorts(ctx context.Context, codespaceName string, asJSON bool) (err error) {
user, err := a.apiClient.GetUser(ctx)
if err != nil {
return fmt.Errorf("error getting user: %w", err)
}
codespace, token, err := getOrChooseCodespace(ctx, a.apiClient, user, codespaceName)
codespace, err := getOrChooseCodespace(ctx, a.apiClient, codespaceName)
if err != nil {
// TODO(josebalius): remove special handling of this error here and it other places
if err == errNoCodespaces {
@ -65,7 +60,7 @@ func (a *App) ListPorts(ctx context.Context, codespaceName string, asJSON bool)
devContainerCh := getDevContainer(ctx, a.apiClient, codespace)
session, err := codespaces.ConnectToLiveshare(ctx, a.logger, a.apiClient, user.Login, token, codespace)
session, err := codespaces.ConnectToLiveshare(ctx, a.logger, a.apiClient, codespace)
if err != nil {
return fmt.Errorf("error connecting to Live Share: %w", err)
}
@ -191,12 +186,7 @@ func newPortsPrivateCmd(app *App) *cobra.Command {
}
func (a *App) UpdatePortVisibility(ctx context.Context, codespaceName, sourcePort string, public bool) (err error) {
user, err := a.apiClient.GetUser(ctx)
if err != nil {
return fmt.Errorf("error getting user: %w", err)
}
codespace, token, err := getOrChooseCodespace(ctx, a.apiClient, user, codespaceName)
codespace, err := getOrChooseCodespace(ctx, a.apiClient, codespaceName)
if err != nil {
if err == errNoCodespaces {
return err
@ -204,7 +194,7 @@ func (a *App) UpdatePortVisibility(ctx context.Context, codespaceName, sourcePor
return fmt.Errorf("error getting codespace: %w", err)
}
session, err := codespaces.ConnectToLiveshare(ctx, a.logger, a.apiClient, user.Login, token, codespace)
session, err := codespaces.ConnectToLiveshare(ctx, a.logger, a.apiClient, codespace)
if err != nil {
return fmt.Errorf("error connecting to Live Share: %w", err)
}
@ -255,12 +245,7 @@ func (a *App) ForwardPorts(ctx context.Context, codespaceName string, ports []st
return fmt.Errorf("get port pairs: %w", err)
}
user, err := a.apiClient.GetUser(ctx)
if err != nil {
return fmt.Errorf("error getting user: %w", err)
}
codespace, token, err := getOrChooseCodespace(ctx, a.apiClient, user, codespaceName)
codespace, err := getOrChooseCodespace(ctx, a.apiClient, codespaceName)
if err != nil {
if err == errNoCodespaces {
return err
@ -268,7 +253,7 @@ func (a *App) ForwardPorts(ctx context.Context, codespaceName string, ports []st
return fmt.Errorf("error getting codespace: %w", err)
}
session, err := codespaces.ConnectToLiveshare(ctx, a.logger, a.apiClient, user.Login, token, codespace)
session, err := codespaces.ConnectToLiveshare(ctx, a.logger, a.apiClient, codespace)
if err != nil {
return fmt.Errorf("error connecting to Live Share: %w", err)
}

View file

@ -45,12 +45,12 @@ func (a *App) SSH(ctx context.Context, sshArgs []string, sshProfile, codespaceNa
authkeys <- checkAuthorizedKeys(ctx, a.apiClient, user.Login)
}()
codespace, token, err := getOrChooseCodespace(ctx, a.apiClient, user, codespaceName)
codespace, err := getOrChooseCodespace(ctx, a.apiClient, codespaceName)
if err != nil {
return fmt.Errorf("get or choose codespace: %w", err)
}
session, err := codespaces.ConnectToLiveshare(ctx, a.logger, a.apiClient, user.Login, token, codespace)
session, err := codespaces.ConnectToLiveshare(ctx, a.logger, a.apiClient, codespace)
if err != nil {
return fmt.Errorf("error connecting to Live Share: %w", err)
}