From dc5c8777e806f67816649adc97348bd0784d63be Mon Sep 17 00:00:00 2001 From: David Symonds Date: Mon, 26 Mar 2018 14:15:45 +1100 Subject: [PATCH] In CreateFork, return the repo info when 202 Accepted occurs. Per the docs (https://developer.github.com/v3/repos/forks/#create-a-fork), there is still a useful body, and it is helpful for automatic fork creation to get that response. --- github/github.go | 19 +++++++++++++------ github/repos_forks.go | 6 +++++- github/repos_forks_test.go | 24 ++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 7 deletions(-) diff --git a/github/github.go b/github/github.go index 46731a36600..f5bb2ec7d5b 100644 --- a/github/github.go +++ b/github/github.go @@ -487,18 +487,25 @@ func (c *Client) Do(ctx context.Context, req *http.Request, v interface{}) (*Res err = CheckResponse(resp) if err != nil { - // even though there was an error, we still return the response - // in case the caller wants to inspect it further - return response, err + // Even though there was an error, we still return the response + // in case the caller wants to inspect it further. + // However, if the error is AcceptedError, decode it below before + // returning from this function and closing the response body. + if _, ok := err.(*AcceptedError); !ok { + return response, err + } } if v != nil { if w, ok := v.(io.Writer); ok { io.Copy(w, resp.Body) } else { - err = json.NewDecoder(resp.Body).Decode(v) - if err == io.EOF { - err = nil // ignore EOF errors caused by empty response body + decErr := json.NewDecoder(resp.Body).Decode(v) + if decErr == io.EOF { + decErr = nil // ignore EOF errors caused by empty response body + } + if decErr != nil { + err = decErr } } } diff --git a/github/repos_forks.go b/github/repos_forks.go index 4ca19a42dc3..d0bff544706 100644 --- a/github/repos_forks.go +++ b/github/repos_forks.go @@ -58,7 +58,8 @@ type RepositoryCreateForkOptions struct { // // This method might return an *AcceptedError and a status code of // 202. This is because this is the status that GitHub returns to signify that -// it is now computing creating the fork in a background task. +// it is now computing creating the fork in a background task. In this event, +// the Repository value will be returned, which includes the details about the pending fork. // A follow up request, after a delay of a second or so, should result // in a successful request. // @@ -77,6 +78,9 @@ func (s *RepositoriesService) CreateFork(ctx context.Context, owner, repo string fork := new(Repository) resp, err := s.client.Do(ctx, req, fork) + if _, ok := err.(*AcceptedError); ok { + return fork, resp, err + } if err != nil { return nil, resp, err } diff --git a/github/repos_forks_test.go b/github/repos_forks_test.go index 8513f0e2ac2..065f592735c 100644 --- a/github/repos_forks_test.go +++ b/github/repos_forks_test.go @@ -72,6 +72,30 @@ func TestRepositoriesService_CreateFork(t *testing.T) { } } +func TestRepositoriesService_CreateFork_deferred(t *testing.T) { + client, mux, _, teardown := setup() + defer teardown() + + mux.HandleFunc("/repos/o/r/forks", func(w http.ResponseWriter, r *http.Request) { + testMethod(t, r, "POST") + testFormValues(t, r, values{"organization": "o"}) + // This response indicates the fork will happen asynchronously. + w.WriteHeader(http.StatusAccepted) + fmt.Fprint(w, `{"id":1}`) + }) + + opt := &RepositoryCreateForkOptions{Organization: "o"} + repo, _, err := client.Repositories.CreateFork(context.Background(), "o", "r", opt) + if _, ok := err.(*AcceptedError); !ok { + t.Errorf("Repositories.CreateFork returned error: %v (want AcceptedError)", err) + } + + want := &Repository{ID: Int64(1)} + if !reflect.DeepEqual(repo, want) { + t.Errorf("Repositories.CreateFork returned %+v, want %+v", repo, want) + } +} + func TestRepositoriesService_CreateFork_invalidOwner(t *testing.T) { client, _, _, teardown := setup() defer teardown()