diff --git a/gh_test.go b/gh_test.go index ade5f1b..781c4c4 100644 --- a/gh_test.go +++ b/gh_test.go @@ -105,6 +105,34 @@ func TestGQLClient(t *testing.T) { assert.Equal(t, "hubot", res.Viewer.Login) } +func TestGQLClientError(t *testing.T) { + t.Cleanup(gock.Off) + tempDir := t.TempDir() + orig_GH_CONFIG_DIR := os.Getenv("GH_CONFIG_DIR") + orig_GH_TOKEN := os.Getenv("GH_TOKEN") + t.Cleanup(func() { + os.Setenv("GH_CONFIG_DIR", orig_GH_CONFIG_DIR) + os.Setenv("GH_TOKEN", orig_GH_TOKEN) + }) + os.Setenv("GH_CONFIG_DIR", tempDir) + os.Setenv("GH_TOKEN", "GH_TOKEN") + + gock.New("https://api.github.com"). + Post("/graphql"). + MatchHeader("Authorization", "token GH_TOKEN"). + BodyString(`{"query":"QUERY","variables":null}`). + Reply(200). + JSON(`{"errors":[{"type":"NOT_FOUND","path":["organization"],"message":"Could not resolve to an Organization with the login of 'cli'."}]}`) + + client, err := GQLClient(nil) + assert.NoError(t, err) + + res := struct{ Organization struct{ Name string } }{} + err = client.Do("QUERY", nil, &res) + assert.EqualError(t, err, "GQL error: Could not resolve to an Organization with the login of 'cli'.") + assert.True(t, gock.IsDone(), printPendingMocks(gock.Pending())) +} + func TestHTTPClient(t *testing.T) { t.Cleanup(gock.Off) tempDir := t.TempDir() diff --git a/internal/api/gql_client.go b/internal/api/gql_client.go index d22d97b..b4d727b 100644 --- a/internal/api/gql_client.go +++ b/internal/api/gql_client.go @@ -7,7 +7,6 @@ import ( "fmt" "io" "net/http" - "strings" "github.com/cli/go-gh/pkg/api" graphql "github.com/cli/shurcooL-graphql" @@ -75,7 +74,7 @@ func (c gqlClient) Do(query string, variables map[string]interface{}, response i } if len(gr.Errors) > 0 { - return &gqlErrorResponse{Errors: gr.Errors} + return &api.GQLError{Errors: gr.Errors} } return nil @@ -97,22 +96,5 @@ func (c gqlClient) Query(name string, q interface{}, variables map[string]interf type gqlResponse struct { Data interface{} - Errors []gqlError -} - -type gqlError struct { - Type string - Message string -} - -type gqlErrorResponse struct { - Errors []gqlError -} - -func (gr gqlErrorResponse) Error() string { - errorMessages := make([]string, 0, len(gr.Errors)) - for _, e := range gr.Errors { - errorMessages = append(errorMessages, e.Message) - } - return fmt.Sprintf("GQL error: %s", strings.Join(errorMessages, "\n")) + Errors []api.GQLErrorItem } diff --git a/internal/api/http.go b/internal/api/http.go index f7c4bcc..228c9e6 100644 --- a/internal/api/http.go +++ b/internal/api/http.go @@ -149,9 +149,9 @@ func handleHTTPError(resp *http.Response) error { var errString string _ = json.Unmarshal(raw, &errString) messages = append(messages, errString) - httpError.Errors = append(httpError.Errors, api.HttpErrorItem{Message: errString}) + httpError.Errors = append(httpError.Errors, api.HTTPErrorItem{Message: errString}) case '{': - var errInfo api.HttpErrorItem + var errInfo api.HTTPErrorItem _ = json.Unmarshal(raw, &errInfo) msg := errInfo.Message if errInfo.Code != "" && errInfo.Code != "custom" { diff --git a/pkg/api/client.go b/pkg/api/client.go index 842988f..ce3e2ad 100644 --- a/pkg/api/client.go +++ b/pkg/api/client.go @@ -2,8 +2,10 @@ package api import ( + "fmt" "io" "net/http" + "strings" "time" ) @@ -97,3 +99,23 @@ type GQLClient interface { // to the GitHub GraphQL schema. Query(name string, query interface{}, variables map[string]interface{}) error } + +// GQLError contains GQLErrors from a GraphQL request. +type GQLError struct { + Errors []GQLErrorItem +} + +// GQLErrorItem contains error information from a GraphQL request. +type GQLErrorItem struct { + Type string + Message string +} + +// Error formats all GQLError messages. +func (gr GQLError) Error() string { + errorMessages := make([]string, 0, len(gr.Errors)) + for _, e := range gr.Errors { + errorMessages = append(errorMessages, e.Message) + } + return fmt.Sprintf("GQL error: %s", strings.Join(errorMessages, "\n")) +} diff --git a/pkg/api/http.go b/pkg/api/http.go index 89546a9..e996f76 100644 --- a/pkg/api/http.go +++ b/pkg/api/http.go @@ -12,12 +12,12 @@ type HTTPError struct { RequestURL *url.URL Message string OAuthScopes string - Errors []HttpErrorItem + Errors []HTTPErrorItem } // HTTPErrorItem stores additional information about an error response // returned from the GitHub API. -type HttpErrorItem struct { +type HTTPErrorItem struct { Message string Resource string Field string