Skip to content

Commit

Permalink
Merge branch version/0-43-0-RC1 to adopt changes from PR #2901
Browse files Browse the repository at this point in the history
  • Loading branch information
as-builds committed Nov 29, 2023
2 parents 1b7133d + 3388db7 commit 9ee9c1d
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 20 deletions.
4 changes: 4 additions & 0 deletions internal/locale/locales/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,8 @@ err_invalid_output_format:
other: "Invalid output format specified: '[NOTICE]{{.V0}}[/RESET]'; Supported formats: [ACTIONABLE]{{.V1}}[/RESET]"
err_invalid_language:
other: "Invalid language specified: '[NOTICE]{{.V0}}[/RESET]'; Supported languages: [ACTIONABLE]{{.V1}}[/RESET]"
err_init_invalid_org:
other: The organization [ACTIONABLE]{{.V0}}[/RESET] either does not exist, or you do not have permissions to create a project in it.
push_creating_project:
other: "Creating project [NOTICE]{{.V1}}[/RESET] under [NOTICE]{{.V0}}[/RESET] on the ActiveState Platform"
push_project_updated:
Expand Down Expand Up @@ -2034,6 +2036,8 @@ pjfile_deprecation_entry:
other: " - '[ACTIONABLE]{{.V0}}[/RESET]' located at byte [ACTIONABLE]{{.V1}}[/RESET]"
err_init_authenticated:
other: You need to be authenticated to initialize a project. Authenticate by running '[ACTIONABLE]state auth[/RESET]'.
err_init_project_exists:
other: A project file already exists for {{.V0}} at {{.V1}}
err_country_blocked:
other: This service is not available in your region.
err_commit_id_invalid:
Expand Down
29 changes: 20 additions & 9 deletions internal/runners/initialize/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/ActiveState/cli/internal/primer"
"github.com/ActiveState/cli/internal/runbits"
"github.com/ActiveState/cli/internal/runbits/commitmediator"
"github.com/ActiveState/cli/internal/runbits/rationalize"
"github.com/ActiveState/cli/pkg/platform/authentication"
"github.com/ActiveState/cli/pkg/platform/model"
"github.com/ActiveState/cli/pkg/platform/runtime/setup"
Expand Down Expand Up @@ -53,6 +54,15 @@ type primeable interface {
primer.SvcModeler
}

type errProjectExists struct {
error
path string
}

var errNoOwner = errs.New("Could not find organization")

var errNoLanguage = errs.New("No language specified")

// New returns a prepared ptr to Initialize instance.
func New(prime primeable) *Initialize {
return &Initialize{prime.Auth(), prime.Config(), prime.Output(), prime.Analytics(), prime.SvcModel()}
Expand Down Expand Up @@ -87,24 +97,27 @@ func inferLanguage(config projectfile.ConfigGetter) (string, string, bool) {
}

func (r *Initialize) Run(params *RunParams) (rerr error) {
defer rationalizeError(&rerr)
defer rationalizeError(params.Namespace, &rerr)
logging.Debug("Init: %s/%s %v", params.Namespace.Owner, params.Namespace.Project, params.Private)

if !r.auth.Authenticated() {
return locale.NewInputError("err_init_authenticated")
return rationalize.ErrNotAuthenticated
}

path := params.Path
if path == "" {
var err error
path, err = osutils.Getwd()
if err != nil {
return locale.WrapInputError(err, "err_init_sanitize_path", "Could not prepare path: {{.V0}}", err.Error())
return errs.Wrap(err, "Unable to get current working directory")
}
}

if fileutils.TargetExists(filepath.Join(path, constants.ConfigFileName)) {
return locale.NewInputError("err_projectfile_exists")
return &errProjectExists{
error: errs.New("Project file already exists"),
path: path,
}
}

err := fileutils.MkdirUnlessExists(path)
Expand All @@ -130,7 +143,7 @@ func (r *Initialize) Run(params *RunParams) (rerr error) {
}

if languageName == "" {
return locale.NewInputError("err_init_no_language")
return errNoLanguage
}

// Require 'python', 'python@3', or 'python@2' instead of 'python3' or 'python2'.
Expand Down Expand Up @@ -176,9 +189,7 @@ func (r *Initialize) Run(params *RunParams) (rerr error) {
}
}
if owner == "" {
return locale.NewInputError("err_invalid_org",
"The organization '[ACTIONABLE]{{.V0}}[/RESET]' either does not exist, or you do not have permissions to create a project in it.",
params.Namespace.Owner)
return errNoOwner
}
namespace := project.Namespaced{Owner: owner, Project: params.Namespace.Project}

Expand Down Expand Up @@ -244,7 +255,7 @@ func (r *Initialize) Run(params *RunParams) (rerr error) {
Description: locale.T("commit_message_add_initial"),
})
if err != nil {
return locale.WrapError(err, "err_init_commit", "Could not create initial commit")
return locale.WrapError(err, "err_init_commit", "Could not create project")
}

if err := commitmediator.Set(proj, commitID.String()); err != nil {
Expand Down
52 changes: 45 additions & 7 deletions internal/runners/initialize/rationalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,76 @@ import (
"github.com/ActiveState/cli/internal/constants"
"github.com/ActiveState/cli/internal/errs"
"github.com/ActiveState/cli/internal/locale"
"github.com/ActiveState/cli/internal/runbits/rationalize"
bpModel "github.com/ActiveState/cli/pkg/platform/api/buildplanner/model"
"github.com/ActiveState/cli/pkg/platform/runtime/setup"
"github.com/ActiveState/cli/pkg/project"
)

func rationalizeError(err *error) {
func rationalizeError(namespace *project.Namespaced, rerr *error) {
var pcErr *bpModel.ProjectCreatedError
var errArtifactSetup *setup.ArtifactSetupErrors
var projectExistsErr *errProjectExists

switch {
case err == nil:
case rerr == nil:
return

// Not authenticated
case errors.Is(*rerr, rationalize.ErrNotAuthenticated):
*rerr = errs.WrapUserFacing(*rerr,
locale.T("err_init_authenticated"),
errs.SetInput(),
)

case errors.As(*rerr, &projectExistsErr):
*rerr = errs.WrapUserFacing(*rerr,
locale.Tr("err_init_project_exists", namespace.Project, projectExistsErr.path),
errs.SetInput(),
)

case errors.Is(*rerr, errNoLanguage):
*rerr = errs.WrapUserFacing(*rerr,
locale.T("err_init_no_language"),
errs.SetInput(),
)

case errors.Is(*rerr, errNoOwner):
*rerr = errs.WrapUserFacing(*rerr,
locale.Tr("err_init_invalid_org", namespace.Owner),
errs.SetInput(),
)

// Error creating project.
case errors.As(*err, &pcErr):
case errors.As(*rerr, &pcErr):
switch pcErr.Type {
case bpModel.AlreadyExistsErrorType:
*err = errs.NewUserFacing(locale.Tl("err_create_project_exists", "That project already exists."), errs.SetInput())
*rerr = errs.WrapUserFacing(
pcErr,
locale.Tl("err_create_project_exists", "The project {{.V0}} already exists under {{.V1}}", namespace.Project, namespace.Owner),
errs.SetInput(),
)
case bpModel.ForbiddenErrorType:
*err = errs.NewUserFacing(
*rerr = 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")))
case bpModel.NotFoundErrorType:
*rerr = errs.WrapUserFacing(
pcErr,
locale.Tl("err_create_project_not_found", "Could not create project because the organization {{.V0}} was not found.", namespace.Owner),
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):
case errors.As(*rerr, &errArtifactSetup):
for _, serr := range errArtifactSetup.Errors() {
if !errs.Matches(serr, &setup.ArtifactDownloadError{}) {
continue
}
*err = errs.WrapUserFacing(*err,
*rerr = errs.WrapUserFacing(*rerr,
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)),
Expand Down
8 changes: 4 additions & 4 deletions pkg/platform/api/buildplanner/model/buildplan.go
Original file line number Diff line number Diff line change
Expand Up @@ -407,11 +407,11 @@ type ProjectCreatedError struct {
func (p *ProjectCreatedError) Error() string { return p.Message }

func ProcessProjectCreatedError(pcErr *projectCreated, fallbackMessage string) error {
if pcErr.Type != "" {
// These will be handled individually per type as user-facing errors in DX-2300.
return &ProjectCreatedError{pcErr.Type, pcErr.Message}
if pcErr.Error == nil {
return errs.New(fallbackMessage)
}
return errs.New(fallbackMessage)

return &ProjectCreatedError{pcErr.Type, pcErr.Message}
}

type BuildExpression struct {
Expand Down
22 changes: 22 additions & 0 deletions test/integration/init_int_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,28 @@ func (suite *InitIntegrationTestSuite) TestInit_NotAuthenticated() {
cp.Expect("You need to be authenticated to initialize a project.")
}

func (suite *InitIntegrationTestSuite) TestInit_AlreadyExists() {
suite.OnlyRunForTags(tagsuite.Init)
ts := e2e.New(suite.T(), false)
defer ts.Close()
ts.LoginAsPersistentUser()

cp := ts.Spawn("init", fmt.Sprintf("%s/test-project", e2e.PersistentUsername), "--language", "python@3")
cp.Expect("The project test-project already exists under cli-integration-tests")
cp.ExpectExitCode(1)
}

func (suite *InitIntegrationTestSuite) TestInit_NoOrg() {
suite.OnlyRunForTags(tagsuite.Init)
ts := e2e.New(suite.T(), false)
defer ts.Close()
ts.LoginAsPersistentUser()

cp := ts.Spawn("init", "random-org/test-project", "--language", "python@3")
cp.Expect("The organization random-org either does not exist, or you do not have permissions to create a project in it.")
cp.ExpectExitCode(1)
}

func TestInitIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(InitIntegrationTestSuite))
}

0 comments on commit 9ee9c1d

Please sign in to comment.