Skip to content

Remove deprecated experimental error source and fix some error sources #423

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 26, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions pkg/dfutil/framer.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package dfutil
import (
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource"
)

// Framer is an interface that allows any type to be treated as a data frame
Expand All @@ -22,7 +21,10 @@ func FrameResponse(f Framer) backend.DataResponse {
// This function is particularly useful if you have a function that returns `(Framer, error)`, which is a very common pattern
func FrameResponseWithError(f Framer, err error) backend.DataResponse {
if err != nil {
res := errorsource.Response(err)
if backend.IsDownstreamHTTPError(err) {
err = backend.DownstreamError(err)
}
res := backend.ErrorResponseWithErrorSource(err)
backend.Logger.Debug("Error response", "errorsource", res.ErrorSource, "error", res.Error)
return res
}
Expand Down
17 changes: 8 additions & 9 deletions pkg/github/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import (
googlegithub "github.com/google/go-github/v53/github"
"github.com/grafana/github-datasource/pkg/models"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource"
"github.com/influxdata/tdigest"
"github.com/shurcooL/githubv4"
"golang.org/x/oauth2"
Expand Down Expand Up @@ -61,23 +60,23 @@ func New(ctx context.Context, settings models.Settings) (*Client, error) {
return createAccessTokenClient(ctx, settings)
}

return nil, errorsource.DownstreamError(fmt.Errorf("access token or app token are required"), false)
return nil, backend.DownstreamError(errors.New("access token or app token are required"))
}

func createAppClient(settings models.Settings) (*Client, error) {
appId, err := strconv.ParseInt(settings.AppId, 10, 64)
if err != nil {
return nil, errorsource.DownstreamError(fmt.Errorf("error parsing app id"), false)
return nil, backend.DownstreamError(errors.New("error parsing app id"))
}

installationId, err := strconv.ParseInt(settings.InstallationId, 10, 64)
if err != nil {
return nil, errorsource.DownstreamError(fmt.Errorf("error parsing installation id"), false)
return nil, backend.DownstreamError(errors.New("error parsing installation id"))
}

itr, err := ghinstallation.New(http.DefaultTransport, appId, installationId, []byte(settings.PrivateKey))
if err != nil {
return nil, errorsource.DownstreamError(fmt.Errorf("error creating token source"), false)
return nil, backend.DownstreamError(errors.New("error creating token source"))
}

httpClient := &http.Client{Transport: itr}
Expand Down Expand Up @@ -112,12 +111,12 @@ func createAccessTokenClient(ctx context.Context, settings models.Settings) (*Cl
func useGitHubEnterprise(httpClient *http.Client, settings models.Settings) (*Client, error) {
_, err := url.Parse(settings.GitHubURL)
if err != nil {
return nil, errorsource.DownstreamError(fmt.Errorf("incorrect enterprise url"), false)
return nil, backend.DownstreamError(errors.New("incorrect enterprise url"))
}

restClient, err := googlegithub.NewEnterpriseClient(settings.GitHubURL, settings.GitHubURL, httpClient)
if err != nil {
return nil, fmt.Errorf("instantiating enterprise rest client: %w", err)
return nil, backend.DownstreamError(errors.New("instantiating enterprise rest client"))
}

return &Client{
Expand Down Expand Up @@ -227,7 +226,7 @@ func (client *Client) GetWorkflowUsage(ctx context.Context, owner, repo, workflo
usage, response, err := client.getWorkflowUsage(ctx, owner, repo, workflow)
if err != nil {
if response.StatusCode == http.StatusNotFound {
return models.WorkflowUsage{}, errorsource.DownstreamError(errWorkflowNotFound, false)
return models.WorkflowUsage{}, backend.DownstreamError(errWorkflowNotFound)
}
return models.WorkflowUsage{}, addErrorSourceToError(fmt.Errorf("fetching workflow usage: %w", err), response)
}
Expand Down Expand Up @@ -333,7 +332,7 @@ func (client *Client) getWorkflowRuns(ctx context.Context, owner, repo, workflow
if err != nil {
// If the workflow is not found, return a specific error.
if response != nil && response.StatusCode == http.StatusNotFound {
return nil, 0, errorsource.SourceError(backend.ErrorSourceDownstream, errWorkflowNotFound, false)
return nil, 0, backend.DownstreamError(errWorkflowNotFound)
}
return nil, 0, addErrorSourceToError(fmt.Errorf("fetching workflow runs: %w", err), response)
}
Expand Down
23 changes: 14 additions & 9 deletions pkg/github/client/errorsourcehandling.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
package githubclient

import (
"context"
"errors"
"regexp"
"strconv"
"strings"
"syscall"

googlegithub "github.com/google/go-github/v53/github"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource"
)

var statusErrorStringFromGraphQLPackage = "non-200 OK status code: "
Expand All @@ -19,9 +16,11 @@ var (
downstreamErrors = []string{
"Could not resolve to",
"Your token has not been granted the required scopes to execute this query",
"Resource protected by organization SAML enforcement. You must grant your Personal Access token access to this organization.",
"Resource protected by organization SAML enforcement",
"Resource not accessible by personal access token",
"API rate limit exceeded",
"Resource not accessible by integration", // issue with incorrectly set permissions for token/app
"registry is not supported by GraphQL APIs",
}
)

Expand All @@ -31,13 +30,13 @@ func addErrorSourceToError(err error, resp *googlegithub.Response) error {
return nil
}

if errors.Is(err, syscall.ECONNREFUSED) || errors.Is(err, context.Canceled) {
return errorsource.DownstreamError(err, false)
if backend.IsDownstreamHTTPError(err) {
return backend.DownstreamError(err)
}

for _, downstreamError := range downstreamErrors {
if strings.Contains(err.Error(), downstreamError) {
return errorsource.DownstreamError(err, false)
return backend.DownstreamError(err)
}
}
// Unfortunately graphql library that is used is not returning original error from the client.
Expand All @@ -46,13 +45,19 @@ func addErrorSourceToError(err error, resp *googlegithub.Response) error {
if strings.Contains(err.Error(), statusErrorStringFromGraphQLPackage) {
statusCode, statusErr := extractStatusCode(err)
if statusErr == nil {
return errorsource.SourceError(backend.ErrorSourceFromHTTPStatus(statusCode), err, false)
if backend.ErrorSourceFromHTTPStatus(statusCode) == backend.ErrorSourceDownstream {
return backend.DownstreamError(err)
}
return backend.PluginError(err)
}
}
// If we have response we can use the status code from it
if resp != nil {
if resp.StatusCode/100 != 2 {
return errorsource.SourceError(backend.ErrorSourceFromHTTPStatus(resp.StatusCode), err, false)
if backend.ErrorSourceFromHTTPStatus(resp.StatusCode) == backend.ErrorSourceDownstream {
return backend.DownstreamError(err)
}
return backend.PluginError(err)
}
}
// Otherwise we are not adding source which means it is going to be plugin error
Expand Down
27 changes: 17 additions & 10 deletions pkg/github/client/errorsourcehandling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ package githubclient
import (
"context"
"errors"
"net"
"net/http"
"os"
"syscall"
"testing"

googlegithub "github.com/google/go-github/v53/github"
"github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/experimental/errorsource"
"github.com/stretchr/testify/require"
)

Expand All @@ -28,27 +29,33 @@ func TestAddErrorSourceToError(t *testing.T) {
},
{
name: "ECONNREFUSED error",
err: syscall.ECONNREFUSED,
err: &net.OpError{Err: &os.SyscallError{Err: syscall.ECONNREFUSED}},
resp: nil,
expected: errorsource.DownstreamError(syscall.ECONNREFUSED, false),
expected: backend.DownstreamError(&net.OpError{Err: &os.SyscallError{Err: syscall.ECONNREFUSED}}),
},
{
name: "DNS not found error",
err: &net.DNSError{IsNotFound: true},
resp: nil,
expected: backend.DownstreamError(&net.DNSError{IsNotFound: true}),
},
{
name: "graphql error with status code",
err: errors.New("non-200 OK status code: 404 Not Found"),
resp: nil,
expected: errorsource.SourceError(backend.ErrorSourceFromHTTPStatus(404), errors.New("non-200 OK status code: 404 Not Found"), false),
expected: backend.DownstreamError(errors.New("non-200 OK status code: 404 Not Found")),
},
{
name: "identified downstream graphql error",
err: errors.New("Your token has not been granted the required scopes to execute this query"),
resp: nil,
expected: errorsource.DownstreamError(errors.New("Your token has not been granted the required scopes to execute this query"),false),
expected: backend.DownstreamError(errors.New("Your token has not been granted the required scopes to execute this query")),
},
{
name: "response with non-2xx status code",
err: errors.New("some other error"),
resp: &googlegithub.Response{Response: &http.Response{StatusCode: 500}},
expected: errorsource.SourceError(backend.ErrorSourceFromHTTPStatus(500), errors.New("some other error"), false),
expected: backend.DownstreamError(errors.New("some other error")),
},
{
name: "other error with 2xx status code",
Expand All @@ -60,25 +67,25 @@ func TestAddErrorSourceToError(t *testing.T) {
name: "context canceled error",
err: context.Canceled,
resp: nil,
expected: errorsource.DownstreamError(context.Canceled, false),
expected: backend.DownstreamError(context.Canceled),
},
{
name: "saml error message",
err: errors.New("Resource protected by organization SAML enforcement. You must grant your Personal Access token access to this organization."),
resp: nil,
expected: errorsource.DownstreamError(errors.New("Resource protected by organization SAML enforcement. You must grant your Personal Access token access to this organization."), false),
expected: backend.DownstreamError(errors.New("Resource protected by organization SAML enforcement. You must grant your Personal Access token access to this organization.")),
},
{
name: "limit exceeded error message",
err: errors.New("API rate limit exceeded for ID 1"),
resp: nil,
expected: errorsource.DownstreamError(errors.New("API rate limit exceeded for ID 1"), false),
expected: backend.DownstreamError(errors.New("API rate limit exceeded for ID 1")),
},
{
name: "permission error message",
err: errors.New("Resource not accessible by integration"),
resp: nil,
expected: errorsource.DownstreamError(errors.New("Resource not accessible by integration"), false),
expected: backend.DownstreamError(errors.New("Resource not accessible by integration")),
},
}

Expand Down
1 change: 1 addition & 0 deletions pkg/github/query_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ func UnmarshalQuery(b []byte, v interface{}) *backend.DataResponse {
if err := json.Unmarshal(b, v); err != nil {
return &backend.DataResponse{
Error: errors.Wrap(err, "failed to unmarshal JSON request into query"),
ErrorSource: backend.ErrorSourceDownstream,
}
}
return nil
Expand Down
Loading