Skip to content

Commit

Permalink
Merge pull request #3579 from ActiveState/mitchell/dx-2855
Browse files Browse the repository at this point in the history
Implement user-facing errors for environment setup commands.
  • Loading branch information
mitchell-as authored Nov 8, 2024
2 parents 4a9f51c + bdd8b3c commit 3ef1501
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 33 deletions.
4 changes: 0 additions & 4 deletions internal/locale/locales/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -646,8 +646,6 @@ err_incompatible_move_file_dir:
other: |
Could not move [NOTICE]{{.V0}}[/RESET] to [NOTICE]{{.V1}}[/RESET]. One is a file, the other a directory.
This indicates that the requested build may be corrupted.
err_init_lang:
other: "Invalid language: {{.V0}}@{{.V1}}"
initializing_project:
other: |
Initializing Project
Expand Down Expand Up @@ -1217,8 +1215,6 @@ err_findproject_notfound:
other: "Could not load project [ACTIONABLE]{{.V0}}[/RESET] from path: [ACTIONABLE]{{.V1}}[/RESET]"
arg_state_shell_namespace_description:
other: The namespace of the project you wish to start a virtual environment shell/prompt for, or just the project name if previously used
err_language_by_commit:
other: Could not get language from commit ID {{.V0}}
err_parse_project:
other: Could not parse project file at {{.V0}}
err_uninstall_privilege_mismatch:
Expand Down
16 changes: 8 additions & 8 deletions internal/runbits/checkout/checkout.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ package checkout
import (
"path/filepath"

"github.com/ActiveState/cli/internal/locale"
"github.com/ActiveState/cli/internal/primer"
"github.com/ActiveState/cli/internal/runbits/buildscript"
"github.com/go-openapi/strfmt"

"github.com/ActiveState/cli/internal/constants"
"github.com/ActiveState/cli/internal/errs"
"github.com/ActiveState/cli/internal/fileutils"
"github.com/ActiveState/cli/internal/language"
"github.com/ActiveState/cli/internal/osutils"
"github.com/ActiveState/cli/internal/primer"
"github.com/ActiveState/cli/internal/runbits/buildscript"
"github.com/ActiveState/cli/internal/runbits/git"
"github.com/ActiveState/cli/pkg/localcommit"
"github.com/ActiveState/cli/pkg/platform/api/mono/mono_models"
Expand Down Expand Up @@ -47,6 +46,7 @@ func (e errCommitDoesNotBelong) Error() string {
}

var errNoCommitID = errs.New("commitID is nil")
var ErrNoOrg = errs.New("unable to get org name")

func New(repo git.Repository, prime primeable) *Checkout {
return &Checkout{repo, prime}
Expand Down Expand Up @@ -87,7 +87,7 @@ func (r *Checkout) Run(ns *project.Namespaced, branchName, cachePath, targetPath
if !noClone && repoURL != nil && *repoURL != "" {
err := r.repo.CloneProject(ns.Owner, ns.Project, path, r.prime.Output(), r.prime.Analytics())
if err != nil {
return "", locale.WrapError(err, "err_clone_project", "Could not clone associated git repository")
return "", errs.Wrap(err, "Could not clone associated git repository")
}
}
} else if commitID == nil {
Expand Down Expand Up @@ -119,7 +119,7 @@ func (r *Checkout) fetchProject(
// the project and create the project file
pj, err := model.FetchProjectByName(ns.Owner, ns.Project, r.prime.Auth())
if err != nil {
return "", "", nil, "", "", nil, locale.WrapError(err, "err_fetch_project", "", ns.String())
return "", "", nil, "", "", nil, errs.Wrap(err, "Unable to fetch project '%s'", ns.String())
}
proj := pj.Name

Expand All @@ -144,7 +144,7 @@ func (r *Checkout) fetchProject(
case branchName != "":
branch, err = model.BranchForProjectByName(pj, branchName)
if err != nil {
return "", "", nil, "", "", nil, locale.WrapError(err, "err_fetch_branch", "", branchName)
return "", "", nil, "", "", nil, errs.Wrap(err, "Could not get branch '%s'", branchName)
}
commitID = branch.CommitID

Expand Down Expand Up @@ -175,7 +175,7 @@ func (r *Checkout) fetchProject(
return "", "", nil, "", "", nil, errs.Wrap(err, "Unable to get the project's org")
}
if len(owners) == 0 {
return "", "", nil, "", "", nil, locale.NewInputError("err_no_org_name", "Your project's organization name could not be found")
return "", "", nil, "", "", nil, ErrNoOrg
}
owner := owners[0].URLName

Expand Down Expand Up @@ -211,7 +211,7 @@ func CreateProjectFiles(checkoutPath, cachePath, owner, name, branch, commitID,
func getLanguage(commitID strfmt.UUID, auth *authentication.Auth) (language.Language, error) {
modelLanguage, err := model.LanguageByCommit(commitID, auth)
if err != nil {
return language.Unset, locale.WrapError(err, "err_language_by_commit", "", string(commitID))
return language.Unset, errs.Wrap(err, "Could not get language from commit ID '%s'", string(commitID))
}

return language.MakeByNameAndVersion(modelLanguage.Name, modelLanguage.Version), nil
Expand Down
17 changes: 16 additions & 1 deletion internal/runners/checkout/checkout.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package checkout

import (
"errors"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -77,6 +78,19 @@ func NewCheckout(prime primeable) *Checkout {
}
}

func rationalizeError(rerr *error) {
if rerr == nil {
return
}

switch {
case errors.Is(*rerr, checkout.ErrNoOrg):
*rerr = errs.WrapUserFacing(*rerr,
locale.Tl("err_no_org_name", "Your project's organization name could not be found"),
errs.SetInput())
}
}

func (u *Checkout) Run(params *Params) (rerr error) {
var err error
var ns *project.Namespaced
Expand All @@ -101,6 +115,7 @@ func (u *Checkout) Run(params *Params) (rerr error) {
}

defer func() { runtime_runbit.RationalizeSolveError(u.prime.Project(), u.auth, &rerr) }()
defer rationalizeError(&rerr)

logging.Debug("Checking out %s to %s", ns.String(), params.PreferredPath)

Expand All @@ -113,7 +128,7 @@ func (u *Checkout) Run(params *Params) (rerr error) {

proj, err := project.FromPath(projectDir)
if err != nil {
return locale.WrapError(err, "err_project_frompath")
return errs.Wrap(err, "Could not read created project file")
}
u.prime.SetProject(proj)

Expand Down
20 changes: 8 additions & 12 deletions internal/runners/initialize/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import (
"github.com/ActiveState/cli/internal/primer"
"github.com/ActiveState/cli/internal/runbits/buildscript"
"github.com/ActiveState/cli/internal/runbits/dependencies"
"github.com/ActiveState/cli/internal/runbits/errors"
"github.com/ActiveState/cli/internal/runbits/org"
"github.com/ActiveState/cli/internal/runbits/rationalize"
"github.com/ActiveState/cli/internal/runbits/runtime"
Expand Down Expand Up @@ -90,6 +89,8 @@ func (e errUnrecognizedLanguage) Error() string {
return fmt.Sprintf("unrecognized language: %s", e.Name)
}

var errDeleteProjectAfterError = errs.New("could not delete initialized project")

// New returns a prepared ptr to Initialize instance.
func New(prime primeable) *Initialize {
return &Initialize{prime, prime.Auth(), prime.Config(), prime.Output(), prime.Analytics(), prime.SvcModel()}
Expand Down Expand Up @@ -164,24 +165,23 @@ func (r *Initialize) Run(params *RunParams) (rerr error) {

err := fileutils.MkdirUnlessExists(path)
if err != nil {
return locale.WrapError(err, "err_init_preparedir", "Could not create directory at [NOTICE]{{.V0}}[/RESET]. Error: {{.V1}}", params.Path, err.Error())
return errs.Wrap(err, "Could not create directory '%s'", params.Path)
}

path, err = filepath.Abs(params.Path)
if err != nil {
return locale.WrapExternalError(err, "err_init_abs_path", "Could not determine absolute path to [NOTICE]{{.V0}}[/RESET]. Error: {{.V1}}", path, err.Error())
return errs.Wrap(err, "Could not determine absolute path to '%s'", params.Path)
}

var languageName, languageVersion string
var inferred bool
if params.Language != "" {
langParts := strings.Split(params.Language, "@")
languageName = langParts[0]
if len(langParts) > 1 {
languageVersion = langParts[1]
}
} else {
languageName, languageVersion, inferred = inferLanguage(r.config, r.auth)
languageName, languageVersion, _ = inferLanguage(r.config, r.auth)
}

if languageName == "" {
Expand All @@ -200,11 +200,7 @@ func (r *Initialize) Run(params *RunParams) (rerr error) {

version, err := deriveVersion(lang, languageVersion, r.auth)
if err != nil {
if inferred || errors.IsReportableError(err) {
return locale.WrapError(err, "err_init_lang", "", languageName, languageVersion)
} else {
return locale.WrapExternalError(err, "err_init_lang", "", languageName, languageVersion)
}
return errs.Wrap(err, "Unable to get language version")
}

resolvedOwner, err = org.Get(paramOwner, r.auth, r.config)
Expand All @@ -226,7 +222,7 @@ func (r *Initialize) Run(params *RunParams) (rerr error) {

pjfile, err := projectfile.Create(createParams)
if err != nil {
return locale.WrapError(err, "err_init_pjfile", "Could not create project file")
return errs.Wrap(err, "Could not create project file")
}

// If an error occurs, remove the created activestate.yaml file so the user can try again.
Expand Down Expand Up @@ -296,7 +292,7 @@ func (r *Initialize) Run(params *RunParams) (rerr error) {
err2 := model.DeleteProject(namespace.Owner, namespace.Project, r.auth)
if err2 != nil {
multilog.Error("Error deleting remotely created project after runtime setup error: %v", errs.JoinMessage(err2))
return locale.WrapError(err, "err_init_refresh_delete_project", "Could not setup runtime after init, and could not delete newly created Platform project. Please delete it manually before trying again")
return errDeleteProjectAfterError
}
return errs.Wrap(err, "Failed to fetch build result")
}
Expand Down
5 changes: 5 additions & 0 deletions internal/runners/initialize/rationalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,10 @@ func rationalizeError(owner, project string, rerr *error) {
errs.SetTips(locale.T("err_init_authenticated")))
}

case errors.Is(*rerr, errDeleteProjectAfterError):
*rerr = errs.WrapUserFacing(*rerr,
locale.Tl("err_init_refresh_delete_project", "Could not setup runtime after init, and could not delete newly created Platform project. Please delete it manually before trying again"),
)

}
}
44 changes: 36 additions & 8 deletions internal/runners/swtch/switch.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package swtch

import (
"errors"

"github.com/ActiveState/cli/internal/analytics"
"github.com/ActiveState/cli/internal/config"
"github.com/ActiveState/cli/internal/errs"
Expand Down Expand Up @@ -74,6 +76,15 @@ func (b branchIdentifier) Locale() string {
return locale.Tl("branch_identifier_type", "branch")
}

type errCommitNotOnBranch struct {
commitID string
branch string
}

func (e errCommitNotOnBranch) Error() string {
return "commit is not on branch"
}

func New(prime primeable) *Switch {
return &Switch{
prime: prime,
Expand All @@ -86,7 +97,24 @@ func New(prime primeable) *Switch {
}
}

func (s *Switch) Run(params SwitchParams) error {
func rationalizeError(rerr *error) {
if rerr == nil {
return
}

var commitNotOnBranchErr *errCommitNotOnBranch

switch {
case errors.As(*rerr, &commitNotOnBranchErr):
*rerr = errs.WrapUserFacing(*rerr,
locale.Tl("err_identifier_branch_not_on_branch", "Commit does not belong to history for branch [ACTIONABLE]{{.V0}}[/RESET]", commitNotOnBranchErr.branch),
errs.SetInput(),
)
}
}

func (s *Switch) Run(params SwitchParams) (rerr error) {
defer rationalizeError(&rerr)
logging.Debug("ExecuteSwitch")

if s.project == nil {
Expand All @@ -96,27 +124,27 @@ func (s *Switch) Run(params SwitchParams) error {

project, err := model.LegacyFetchProjectByName(s.project.Owner(), s.project.Name())
if err != nil {
return locale.WrapError(err, "err_fetch_project", "", s.project.Namespace().String())
return errs.Wrap(err, "Could not fetch project '%s'", s.project.Namespace().String())
}

identifier, err := resolveIdentifier(project, params.Identifier)
if err != nil {
return locale.WrapError(err, "err_resolve_identifier", "Could not resolve identifier '{{.V0}}'", params.Identifier)
return errs.Wrap(err, "Could not resolve identifier '%s'", params.Identifier)
}

if id, ok := identifier.(branchIdentifier); ok {
err = s.project.Source().SetBranch(id.branch.Label)
if err != nil {
return locale.WrapError(err, "err_switch_set_branch", "Could not update branch")
return errs.Wrap(err, "Could not update branch")
}
}

belongs, err := model.CommitBelongsToBranch(s.project.Owner(), s.project.Name(), s.project.BranchName(), identifier.CommitID(), s.auth)
if err != nil {
return locale.WrapError(err, "err_identifier_branch", "Could not determine if commit belongs to branch")
return errs.Wrap(err, "Could not determine if commit belongs to branch")
}
if !belongs {
return locale.NewInputError("err_identifier_branch_not_on_branch", "Commit does not belong to history for branch [ACTIONABLE]{{.V0}}[/RESET]", s.project.BranchName())
return &errCommitNotOnBranch{identifier.CommitID().String(), s.project.BranchName()}
}

err = localcommit.Set(s.project.Dir(), identifier.CommitID().String())
Expand All @@ -126,7 +154,7 @@ func (s *Switch) Run(params SwitchParams) error {

_, err = runtime_runbit.Update(s.prime, trigger.TriggerSwitch)
if err != nil {
return locale.WrapError(err, "err_refresh_runtime")
return errs.Wrap(err, "Could not setup runtime")
}

s.out.Print(output.Prepare(
Expand All @@ -148,7 +176,7 @@ func resolveIdentifier(project *mono_models.Project, idParam string) (identifier

branch, err := model.BranchForProjectByName(project, idParam)
if err != nil {
return nil, locale.WrapError(err, "err_identifier_branch", "Could not get branch '{{.V0}}' for current project", idParam)
return nil, errs.Wrap(err, "Could not get branch '%s'", idParam)

}

Expand Down

0 comments on commit 3ef1501

Please sign in to comment.