diff --git a/azure/resourcegroup.go b/azure/resourcegroup.go index 1ca9420a5..e31732467 100644 --- a/azure/resourcegroup.go +++ b/azure/resourcegroup.go @@ -130,7 +130,7 @@ func getSubscriptionsClient() (subscription.SubscriptionsClient, error) { subc := subscription.NewSubscriptionsClient() err := setupClient(&subc.Client) if err != nil { - return subscription.SubscriptionsClient{}, errors.Wrap(errdefs.ErrLoginFailed, err.Error()) + return subscription.SubscriptionsClient{}, errors.Wrap(errdefs.ErrLoginRequired, err.Error()) } return subc, nil } diff --git a/cli/main.go b/cli/main.go index 3dc324a39..1475ac7c1 100644 --- a/cli/main.go +++ b/cli/main.go @@ -27,6 +27,8 @@ import ( "syscall" "time" + "github.com/docker/api/errdefs" + "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -174,15 +176,23 @@ func main() { // Context should always be handled by new CLI requiredCmd, _, _ := root.Find(os.Args[1:]) if requiredCmd != nil && isOwnCommand(requiredCmd) { - fatal(err) + exit(err) } mobycli.ExecIfDefaultCtxType(ctx) checkIfUnknownCommandExistInDefaultContext(err, currentContext) - fatal(err) + exit(err) } } +func exit(err error) { + if errors.Is(err, errdefs.ErrLoginRequired) { + fmt.Fprintln(os.Stderr, fmt.Errorf("%v", err)) + os.Exit(errdefs.ExitCodeLoginRequired) + } + fatal(err) +} + func checkIfUnknownCommandExistInDefaultContext(err error, currentContext string) { submatch := unknownCommandRegexp.FindSubmatch([]byte(err.Error())) if len(submatch) == 2 { diff --git a/errdefs/errors.go b/errdefs/errors.go index 65b4316b9..db5141cc5 100644 --- a/errdefs/errors.go +++ b/errdefs/errors.go @@ -20,6 +20,12 @@ import ( "github.com/pkg/errors" ) +const ( + //ExitCodeLoginRequired exit code when command cannot execute because it requires cloud login + // This will be used by VSCode to detect when creating context if the user needs to login first + ExitCodeLoginRequired = 5 +) + var ( // ErrNotFound is returned when an object is not found ErrNotFound = errors.New("not found") @@ -31,6 +37,8 @@ var ( ErrUnknown = errors.New("unknown") // ErrLoginFailed is returned when login failed ErrLoginFailed = errors.New("login failed") + // ErrLoginRequired is returned when login is required for a specific action + ErrLoginRequired = errors.New("login required") // ErrNotImplemented is returned when a backend doesn't implement // an action ErrNotImplemented = errors.New("not implemented") diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 31b9034ff..c1f9fe672 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -18,11 +18,14 @@ package main import ( "os" + "os/exec" "path/filepath" "runtime" "testing" "time" + "github.com/docker/api/errdefs" + . "github.com/onsi/gomega" "github.com/stretchr/testify/suite" @@ -43,6 +46,14 @@ func (s *E2eSuite) TestContextHelp() { Expect(output).To(ContainSubstring("--resource-group")) } +func (s *E2eSuite) TestContextCreateAciExitWithErrorCodeIfLoginRequired() { + cmd := exec.Command("docker", "context", "create", "aci", "someContext") + output, err := cmd.CombinedOutput() + Expect(err).NotTo(BeNil()) + Expect(string(output)).To(ContainSubstring("not logged in to azure, you need to run \"docker login azure\" first")) + Expect(cmd.ProcessState.ExitCode()).To(Equal(errdefs.ExitCodeLoginRequired)) +} + func (s *E2eSuite) TestListAndShowDefaultContext() { output := s.NewDockerCommand("context", "show").ExecOrDie() Expect(output).To(ContainSubstring("default"))