Skip to content
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

Implement user-facing error when runtime artifacts fail to download. #2878

Merged
merged 2 commits into from
Nov 14, 2023
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
2 changes: 1 addition & 1 deletion internal/retryhttp/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
18 changes: 18 additions & 0 deletions internal/runbits/runtime/rationalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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
Expand Down
48 changes: 34 additions & 14 deletions internal/runners/initialize/rationalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

}
}
Loading