diff --git a/cli/cmd/context/rm.go b/cli/cmd/context/rm.go index cded45124..40a887b87 100644 --- a/cli/cmd/context/rm.go +++ b/cli/cmd/context/rm.go @@ -32,37 +32,61 @@ import ( "errors" "fmt" - "github.com/spf13/cobra" apicontext "github.com/docker/api/context" "github.com/docker/api/context/store" "github.com/docker/api/multierror" + "github.com/spf13/cobra" ) +type removeOpts struct { + force bool +} + func removeCommand() *cobra.Command { - return &cobra.Command{ + var opts removeOpts + cmd := &cobra.Command{ Use: "rm CONTEXT [CONTEXT...]", Short: "Remove one or more contexts", Aliases: []string{"remove"}, Args: cobra.MinimumNArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - return runRemove(cmd.Context(), args) + return runRemove(cmd.Context(), args, opts.force) }, } + cmd.Flags().BoolVarP(&opts.force, "force", "f", false, "force removing current context") + + return cmd } -func runRemove(ctx context.Context, args []string) error { +func runRemove(ctx context.Context, args []string, force bool) error { currentContext := apicontext.CurrentContext(ctx) s := store.ContextStore(ctx) var errs *multierror.Error - for _, n := range args { - if currentContext == n { - errs = multierror.Append(errs, errors.New("cannot delete current context")) - } else if err := s.Remove(n); err != nil { - errs = multierror.Append(errs, err) + for _, contextName := range args { + if currentContext == contextName { + if force { + err := runUse(ctx, "default") + if err != nil { + errs = multierror.Append(errs, errors.New("cannot delete current context")) + } else { + errs = removeContext(s, contextName, errs) + } + } else { + errs = multierror.Append(errs, errors.New("cannot delete current context")) + } } else { - fmt.Println(n) + errs = removeContext(s, contextName, errs) } } return errs.ErrorOrNil() } + +func removeContext(s store.Store, n string, errs *multierror.Error) *multierror.Error { + if err := s.Remove(n); err != nil { + errs = multierror.Append(errs, err) + } else { + fmt.Println(n) + } + return errs +} diff --git a/local/e2e/backend_test.go b/local/e2e/backend_test.go index c719060a3..03285c78e 100644 --- a/local/e2e/backend_test.go +++ b/local/e2e/backend_test.go @@ -21,8 +21,7 @@ func (m *LocalBackendTestSuite) BeforeTest(suiteName string, testName string) { } func (m *LocalBackendTestSuite) AfterTest(suiteName string, testName string) { - m.NewDockerCommand("context", "rm", "test-context").ExecOrDie() - m.NewDockerCommand("context", "use", "default").ExecOrDie() + m.NewDockerCommand("context", "rm", "-f", "test-context").ExecOrDie() } func (m *LocalBackendTestSuite) TestPs() { diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index be69ee1c4..5b432fcad 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -80,12 +80,20 @@ func (s *E2eSuite) TestContextCreateParseErrorDoesNotDelegateToLegacy() { } func (s *E2eSuite) TestCannotRemoveCurrentContext() { - s.NewDockerCommand("context", "create", "test-context", "--from", "default").ExecOrDie() - s.NewDockerCommand("context", "use", "test-context").ExecOrDie() - _, err := s.NewDockerCommand("context", "rm", "test-context").Exec() + s.NewDockerCommand("context", "create", "test-context-rm", "--from", "default").ExecOrDie() + s.NewDockerCommand("context", "use", "test-context-rm").ExecOrDie() + _, err := s.NewDockerCommand("context", "rm", "test-context-rm").Exec() Expect(err.Error()).To(ContainSubstring("cannot delete current context")) } +func (s *E2eSuite) TestCanForceRemoveCurrentContext() { + s.NewDockerCommand("context", "create", "test-context-rmf", "--from", "default").ExecOrDie() + s.NewDockerCommand("context", "use", "test-context-rmf").ExecOrDie() + s.NewDockerCommand("context", "rm", "-f", "test-context-rmf").ExecOrDie() + out := s.NewDockerCommand("context", "ls").ExecOrDie() + Expect(out).To(ContainSubstring("default *")) +} + func (s *E2eSuite) TestClassicLoginWithparameters() { output, err := s.NewDockerCommand("login", "-u", "nouser", "-p", "wrongpasword").Exec() Expect(output).To(ContainSubstring("Get https://registry-1.docker.io/v2/: unauthorized: incorrect username or password"))