From 5c9734ad9f39a65d0343fea37bda735496a70628 Mon Sep 17 00:00:00 2001 From: mitchell Date: Tue, 7 Nov 2023 11:36:41 -0500 Subject: [PATCH 1/2] Make DNS errors input errors to inform the user something is wrong with their network. --- internal/retryhttp/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/retryhttp/client.go b/internal/retryhttp/client.go index 5924591357..a97f438b06 100644 --- a/internal/retryhttp/client.go +++ b/internal/retryhttp/client.go @@ -124,7 +124,7 @@ func normalizeResponse(res *http.Response, err error) (*http.Response, error) { var dnsError *net.DNSError if errors.As(err, &dnsError) { - return res, locale.WrapError(&UserNetworkError{}, "err_user_network_dns", "Request failed due to DNS error: {{.V0}}. {{.V1}}", err.Error(), locale.Tr("err_user_network_solution", constants.ForumsURL)) + return res, locale.WrapInputError(&UserNetworkError{}, "err_user_network_dns", "Request failed due to DNS error: {{.V0}}. {{.V1}}", err.Error(), locale.Tr("err_user_network_solution", constants.ForumsURL)) } // Due to Go's handling of these types of errors and due to Windows localizing the errors in question we have to rely on the `wsarecv:` keyword to capture a series From ccae35beb456b866b635688a4d1170a7b09d0b1f Mon Sep 17 00:00:00 2001 From: mitchell Date: Fri, 10 Nov 2023 17:31:31 -0500 Subject: [PATCH 2/2] Implement user-facing error when runtime artifacts fail to download. --- internal/runbits/runtime/rationalize.go | 18 ++++++++ internal/runners/initialize/rationalize.go | 48 +++++++++++++++------- 2 files changed, 52 insertions(+), 14 deletions(-) diff --git a/internal/runbits/runtime/rationalize.go b/internal/runbits/runtime/rationalize.go index a295c9dc29..7ab4f8b36a 100644 --- a/internal/runbits/runtime/rationalize.go +++ b/internal/runbits/runtime/rationalize.go @@ -4,16 +4,19 @@ import ( "errors" "strings" + "github.com/ActiveState/cli/internal/constants" "github.com/ActiveState/cli/internal/errs" "github.com/ActiveState/cli/internal/locale" "github.com/ActiveState/cli/internal/multilog" "github.com/ActiveState/cli/pkg/platform/authentication" "github.com/ActiveState/cli/pkg/platform/model" + "github.com/ActiveState/cli/pkg/platform/runtime/setup" "github.com/ActiveState/cli/pkg/project" ) func rationalizeError(auth *authentication.Auth, proj *project.Project, rerr *error) { var errNoMatchingPlatform *model.ErrNoMatchingPlatform + var errArtifactSetup *setup.ArtifactSetupErrors isUpdateErr := errs.Matches(*rerr, &ErrUpdate{}) switch { @@ -39,6 +42,21 @@ func rationalizeError(auth *authentication.Auth, proj *project.Project, rerr *er errNoMatchingPlatform.HostPlatform, errNoMatchingPlatform.HostArch)) } + // If there was an artifact download error, say so, rather than reporting a generic "could not + // update runtime" error. + case isUpdateErr && errors.As(*rerr, &errArtifactSetup): + for _, err := range errArtifactSetup.Errors() { + if !errs.Matches(err, &setup.ArtifactDownloadError{}) { + continue + } + *rerr = errs.WrapUserFacing(*rerr, + locale.Tl("err_runtime_setup_download", "Your runtime could not be installed or updated because one or more artifacts failed to download."), + errs.SetInput(), + errs.SetTips(locale.Tr("err_user_network_solution", constants.ForumsURL)), + ) + break // it only takes one download failure to report the runtime failure as due to download error + } + // If updating failed due to unidentified errors, and the user is not authenticated, add a tip suggesting that they authenticate as // this may be a private project. // Note since we cannot assert the actual error type we do not wrap this as user-facing, as we do not know what we're diff --git a/internal/runners/initialize/rationalize.go b/internal/runners/initialize/rationalize.go index 606fc6f3f7..bf3c9fd011 100644 --- a/internal/runners/initialize/rationalize.go +++ b/internal/runners/initialize/rationalize.go @@ -3,27 +3,47 @@ package initialize import ( "errors" + "github.com/ActiveState/cli/internal/constants" "github.com/ActiveState/cli/internal/errs" "github.com/ActiveState/cli/internal/locale" bpModel "github.com/ActiveState/cli/pkg/platform/api/buildplanner/model" + "github.com/ActiveState/cli/pkg/platform/runtime/setup" ) func rationalizeError(err *error) { - if err == nil { - return - } + var pcErr *bpModel.ProjectCreatedError + var errArtifactSetup *setup.ArtifactSetupErrors - pcErr := &bpModel.ProjectCreatedError{} - if !errors.As(*err, &pcErr) { + switch { + case err == nil: return - } - switch pcErr.Type { - case bpModel.AlreadyExistsErrorType: - *err = errs.NewUserFacing(locale.Tl("err_create_project_exists", "That project already exists."), errs.SetInput()) - case bpModel.ForbiddenErrorType: - *err = errs.NewUserFacing( - locale.Tl("err_create_project_forbidden", "You do not have permission to create that project"), - errs.SetInput(), - errs.SetTips(locale.T("err_init_authenticated"))) + + // Error creating project. + case errors.As(*err, &pcErr): + switch pcErr.Type { + case bpModel.AlreadyExistsErrorType: + *err = errs.NewUserFacing(locale.Tl("err_create_project_exists", "That project already exists."), errs.SetInput()) + case bpModel.ForbiddenErrorType: + *err = errs.NewUserFacing( + locale.Tl("err_create_project_forbidden", "You do not have permission to create that project"), + errs.SetInput(), + errs.SetTips(locale.T("err_init_authenticated"))) + } + + // If there was an artifact download error, say so, rather than reporting a generic "could not + // update runtime" error. + case errors.As(*err, &errArtifactSetup): + for _, serr := range errArtifactSetup.Errors() { + if !errs.Matches(serr, &setup.ArtifactDownloadError{}) { + continue + } + *err = errs.WrapUserFacing(*err, + locale.Tl("err_init_download", "Your project could not be created because one or more artifacts failed to download."), + errs.SetInput(), + errs.SetTips(locale.Tr("err_user_network_solution", constants.ForumsURL)), + ) + break // it only takes one download failure to report the runtime failure as due to download error + } + } }