From 777978644c348eaaaeb3b208412baee90cf70b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Ram=C3=ADrez?= Date: Tue, 5 Oct 2021 16:49:40 +0000 Subject: [PATCH] Adding pagination to list codespaces --- internal/codespaces/api/api.go | 74 ++++++++++++++++++----------- internal/codespaces/api/api_test.go | 55 ++++++++++++++++----- 2 files changed, 89 insertions(+), 40 deletions(-) diff --git a/internal/codespaces/api/api.go b/internal/codespaces/api/api.go index 03f01e7ab..0f114cdbe 100644 --- a/internal/codespaces/api/api.go +++ b/internal/codespaces/api/api.go @@ -189,36 +189,54 @@ type CodespaceEnvironmentConnection struct { // ListCodespaces returns a list of codespaces for the user. func (a *API) ListCodespaces(ctx context.Context) ([]*Codespace, error) { - req, err := http.NewRequest( - http.MethodGet, a.githubAPI+"/user/codespaces", nil, - ) - if err != nil { - return nil, fmt.Errorf("error creating request: %w", err) + page := 1 + per_page := 50 + codespaces := []*Codespace{} + + for { + req, err := http.NewRequest( + http.MethodGet, a.githubAPI+"/user/codespaces", nil, + ) + if err != nil { + return nil, fmt.Errorf("error creating request: %w", err) + } + a.setHeaders(req) + q := req.URL.Query() + q.Add("page", strconv.Itoa(page)) + q.Add("per_page", strconv.Itoa(per_page)) + + req.URL.RawQuery = q.Encode() + resp, err := a.do(ctx, req, "/user/codespaces") + if err != nil { + return nil, fmt.Errorf("error making request: %w", err) + } + defer resp.Body.Close() + + b, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("error reading response body: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return nil, jsonErrorResponse(b) + } + + var response struct { + Codespaces []*Codespace `json:"codespaces"` + } + if err := json.Unmarshal(b, &response); err != nil { + return nil, fmt.Errorf("error unmarshaling response: %w", err) + } + + if len(response.Codespaces) > 0 { + codespaces = append(codespaces, response.Codespaces...) + page++ + } else { + break + } } - a.setHeaders(req) - resp, err := a.do(ctx, req, "/user/codespaces") - if err != nil { - return nil, fmt.Errorf("error making request: %w", err) - } - defer resp.Body.Close() - - b, err := ioutil.ReadAll(resp.Body) - if err != nil { - return nil, fmt.Errorf("error reading response body: %w", err) - } - - if resp.StatusCode != http.StatusOK { - return nil, jsonErrorResponse(b) - } - - var response struct { - Codespaces []*Codespace `json:"codespaces"` - } - if err := json.Unmarshal(b, &response); err != nil { - return nil, fmt.Errorf("error unmarshaling response: %w", err) - } - return response.Codespaces, nil + return codespaces, nil } // getCodespaceTokenRequest is the request body for the get codespace token endpoint. diff --git a/internal/codespaces/api/api_test.go b/internal/codespaces/api/api_test.go index 8bbe1c8a9..6b9beeba9 100644 --- a/internal/codespaces/api/api_test.go +++ b/internal/codespaces/api/api_test.go @@ -6,22 +6,50 @@ import ( "fmt" "net/http" "net/http/httptest" + "strconv" "testing" ) -func TestListCodespaces(t *testing.T) { - codespaces := []*Codespace{ - { - Name: "testcodespace", - CreatedAt: "2021-08-09T10:10:24+02:00", - LastUsedAt: "2021-08-09T13:10:24+02:00", - }, +func generateCodespaceList(start int, end int) []*Codespace { + codespacesList := []*Codespace{} + for i := start; i < end; i++ { + codespacesList = append(codespacesList, &Codespace{ + Name: fmt.Sprintf("codespace-%d", i), + }) } + return codespacesList +} + +func TestListCodespaces(t *testing.T) { + svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/user/codespaces" { + t.Fatal("Incorrect path") + } + + page := 1 + if r.URL.Query().Has("page") { + page, _ = strconv.Atoi(r.URL.Query()["page"][0]) + } + + per_page := 0 + if r.URL.Query().Has("per_page") { + per_page, _ = strconv.Atoi(r.URL.Query()["per_page"][0]) + } + + codespaces := []*Codespace{} + if page == 1 { + codespaces = generateCodespaceList(0, per_page) + } else if page == 2 { + codespaces = generateCodespaceList(per_page, per_page*2) + } + response := struct { Codespaces []*Codespace `json:"codespaces"` + TotalCount int `json:"total_count"` }{ Codespaces: codespaces, + TotalCount: 100, } data, _ := json.Marshal(response) fmt.Fprint(w, string(data)) @@ -38,13 +66,16 @@ func TestListCodespaces(t *testing.T) { if err != nil { t.Fatal(err) } - - if len(codespaces) != 1 { - t.Fatalf("expected 1 codespace, got %d", len(codespaces)) + if len(codespaces) != 100 { + t.Fatalf("expected 100 codespace, got %d", len(codespaces)) } - if codespaces[0].Name != "testcodespace" { - t.Fatalf("expected testcodespace, got %s", codespaces[0].Name) + if codespaces[0].Name != "codespace-0" { + t.Fatalf("expected codespace-0, got %s", codespaces[0].Name) + } + + if codespaces[99].Name != "codespace-99" { + t.Fatalf("expected codespace-99, got %s", codespaces[0].Name) } }