Move ProvisionCodespace to API client

- Make CreateCodespace private along with its errors
This commit is contained in:
Jose Garcia 2021-09-22 11:49:41 -04:00
parent 8c5330d9e9
commit d2d21996bc
4 changed files with 86 additions and 91 deletions

View file

@ -75,74 +75,3 @@ func ConnectToLiveshare(ctx context.Context, log logger, apiClient *api.API, use
return lsclient.JoinWorkspace(ctx)
}
type apiClient interface {
CreateCodespace(ctx context.Context, user *api.User, repo *api.Repository, machine, branch, location string) (*api.Codespace, error)
GetCodespaceToken(ctx context.Context, userLogin, codespaceName string) (string, error)
GetCodespace(ctx context.Context, token, userLogin, codespaceName string) (*api.Codespace, error)
}
// ProvisionParams are the required parameters for provisioning a Codespace.
type ProvisionParams struct {
User *api.User
Repository *api.Repository
Branch, Machine, Location string
}
// Provision creates a codespace with the given parameters and handles polling in the case
// of initial creation failures.
func Provision(ctx context.Context, log logger, client apiClient, params *ProvisionParams) (*api.Codespace, error) {
codespace, err := client.CreateCodespace(
ctx, params.User, params.Repository, params.Machine, params.Branch, params.Location,
)
if err != nil {
// This error is returned by the API when the initial creation fails with a retryable error.
// A retryable error means that GitHub will retry to re-create Codespace and clients should poll
// the API and attempt to fetch the Codespace for the next two minutes.
if err == api.ErrProvisioningInProgress {
pollTimeout := 2 * time.Minute
pollInterval := 1 * time.Second
log.Print(".")
codespace, err = pollForCodespace(ctx, client, log, pollTimeout, pollInterval, params.User.Login, codespace.Name)
log.Print("\n")
if err != nil {
return nil, fmt.Errorf("error creating codespace with async provisioning: %s: %w", codespace.Name, err)
}
}
return nil, err
}
return codespace, nil
}
// pollForCodespace polls the Codespaces GET endpoint on a given interval for a specified duration.
// If it succeeds at fetching the codespace, we consider the codespace provisioned.
func pollForCodespace(ctx context.Context, client apiClient, log logger, duration, interval time.Duration, user, name string) (*api.Codespace, error) {
ctx, cancel := context.WithTimeout(ctx, duration)
defer cancel()
ticker := time.NewTicker(interval)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return nil, ctx.Err()
case <-ticker.C:
log.Print(".")
token, err := client.GetCodespaceToken(ctx, user, name)
if err != nil {
if err == api.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)
}
return client.GetCodespace(ctx, token, user, name)
}
}
}