From 38039c33a7bb1250deac95092f347bc1f8bb6e13 Mon Sep 17 00:00:00 2001 From: Ben Pearce Date: Fri, 14 Oct 2022 11:30:01 +1000 Subject: [PATCH] feat: project delete (#112) --- go.mod | 2 +- go.sum | 2 + pkg/cmd/account/delete/delete.go | 10 +-- pkg/cmd/environment/delete/delete.go | 10 +-- pkg/cmd/project/delete/delete.go | 94 ++++++++++++++++++++++++++++ pkg/cmd/project/project.go | 2 + pkg/cmd/space/delete/delete.go | 10 +-- pkg/question/input.go | 19 +++++- 8 files changed, 126 insertions(+), 23 deletions(-) create mode 100644 pkg/cmd/project/delete/delete.go diff --git a/go.mod b/go.mod index a8659ab6..7286c706 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.19 require ( github.com/AlecAivazis/survey/v2 v2.3.5 github.com/MakeNowJust/heredoc/v2 v2.0.1 - github.com/OctopusDeploy/go-octopusdeploy/v2 v2.8.1 + github.com/OctopusDeploy/go-octopusdeploy/v2 v2.9.1 github.com/briandowns/spinner v1.19.0 github.com/google/uuid v1.3.0 github.com/hashicorp/go-multierror v1.1.1 diff --git a/go.sum b/go.sum index 1173c6e9..41d51324 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,8 @@ github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63n github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/OctopusDeploy/go-octopusdeploy/v2 v2.8.1 h1:jaMlQAeI93w/BlwUf5LNXXlm0aRneroFKuV1BH0D89s= github.com/OctopusDeploy/go-octopusdeploy/v2 v2.8.1/go.mod h1:XWqxyDUVElUlTaPqyCBblukpsHSnPcAKkAHgJgbsIAs= +github.com/OctopusDeploy/go-octopusdeploy/v2 v2.9.1 h1:rnG8B0t759J3en86aTSi9nZ/dv8VcNIz3s+iKWQxVrI= +github.com/OctopusDeploy/go-octopusdeploy/v2 v2.9.1/go.mod h1:XWqxyDUVElUlTaPqyCBblukpsHSnPcAKkAHgJgbsIAs= github.com/briandowns/spinner v1.19.0 h1:s8aq38H+Qju89yhp89b4iIiMzMm8YN3p6vGpwyh/a8E= github.com/briandowns/spinner v1.19.0/go.mod h1:mQak9GHqbspjC/5iUx3qMlIho8xBS/ppAL/hX5SmPJU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= diff --git a/pkg/cmd/account/delete/delete.go b/pkg/cmd/account/delete/delete.go index 388ae8bd..6c09c218 100644 --- a/pkg/cmd/account/delete/delete.go +++ b/pkg/cmd/account/delete/delete.go @@ -15,6 +15,7 @@ import ( ) func NewCmdDelete(f factory.Factory) *cobra.Command { + var skipConfirmation bool cmd := &cobra.Command{ Use: "delete { | }", Short: "Delete an account in an instance of Octopus Deploy", @@ -31,11 +32,6 @@ func NewCmdDelete(f factory.Factory) *cobra.Command { itemIDOrName := args[0] - skipConfirmation, err := cmd.Flags().GetBool("confirm") - if err != nil { - return err - } - client, err := f.GetSpacedClient() if err != nil { return err @@ -70,8 +66,8 @@ func NewCmdDelete(f factory.Factory) *cobra.Command { return delete(client, itemToDelete) }, } - // TODO confirm might want to be a global flag? - cmd.Flags().BoolP("confirm", "y", false, "Don't ask for confirmation before deleting the account.") + + question.RegisterDeleteFlag(cmd, &skipConfirmation, "account") return cmd } diff --git a/pkg/cmd/environment/delete/delete.go b/pkg/cmd/environment/delete/delete.go index 9eea452e..2a528fb5 100644 --- a/pkg/cmd/environment/delete/delete.go +++ b/pkg/cmd/environment/delete/delete.go @@ -15,6 +15,7 @@ import ( ) func NewCmdDelete(f factory.Factory) *cobra.Command { + var skipConfirmation bool cmd := &cobra.Command{ Use: "delete { | }", Short: "Delete an environment in an instance of Octopus Deploy", @@ -31,11 +32,6 @@ func NewCmdDelete(f factory.Factory) *cobra.Command { itemIDOrName := args[0] - skipConfirmation, err := cmd.Flags().GetBool("confirm") - if err != nil { - return err - } - client, err := f.GetSpacedClient() if err != nil { return err @@ -70,8 +66,8 @@ func NewCmdDelete(f factory.Factory) *cobra.Command { return delete(client, itemToDelete) }, } - // TODO confirm might want to be a global flag? - cmd.Flags().BoolP("confirm", "y", false, "Don't ask for confirmation before deleting the space.") + + question.RegisterDeleteFlag(cmd, &skipConfirmation, "environment") return cmd } diff --git a/pkg/cmd/project/delete/delete.go b/pkg/cmd/project/delete/delete.go new file mode 100644 index 00000000..2361a8fc --- /dev/null +++ b/pkg/cmd/project/delete/delete.go @@ -0,0 +1,94 @@ +package delete + +import ( + "github.com/MakeNowJust/heredoc/v2" + "github.com/OctopusDeploy/cli/pkg/factory" + "github.com/OctopusDeploy/cli/pkg/question" + "github.com/OctopusDeploy/cli/pkg/question/selectors" + "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/client" + "github.com/OctopusDeploy/go-octopusdeploy/v2/pkg/projects" + "github.com/spf13/cobra" +) + +type DeleteOptions struct { + Client *client.Client + Ask question.Asker + NoPrompt bool + IdOrName string + *question.DeleteFlags +} + +func NewCmdList(f factory.Factory) *cobra.Command { + deleteFlags := question.NewDeleteFlags() + cmd := &cobra.Command{ + Use: "delete { | | }", + Short: "Delete projects in Octopus Deploy", + Long: "Delete projects in Octopus Deploy", + Aliases: []string{"del", "rm", "remove"}, + Example: heredoc.Doc(` + $ octopus project delete + $ octopus project rm + `), + RunE: func(cmd *cobra.Command, args []string) error { + client, err := f.GetSpacedClient() + if err != nil { + return err + } + + opts := &DeleteOptions{ + Client: client, + Ask: f.Ask, + NoPrompt: !f.IsPromptEnabled(), + IdOrName: args[0], + DeleteFlags: deleteFlags, + } + + return deleteRun(opts) + }, + } + + question.RegisterDeleteFlag(cmd, &deleteFlags.Confirm.Value, "project") + + return cmd +} + +func deleteRun(opts *DeleteOptions) error { + if !opts.NoPrompt { + if err := PromptMissing(opts); err != nil { + return err + } + } + + itemToDelete, err := opts.Client.Projects.GetByIdOrName(opts.IdOrName) + if err != nil { + return err + } + + if opts.DeleteFlags.Confirm.Value { + return delete(opts.Client, itemToDelete) + } else { + return question.DeleteWithConfirmation(opts.Ask, "project", itemToDelete.Name, itemToDelete.ID, func() error { + return delete(opts.Client, itemToDelete) + }) + } +} + +func PromptMissing(opts *DeleteOptions) error { + if opts.IdOrName == "" { + existingProjects, err := opts.Client.Projects.GetAll() + if err != nil { + return err + } + itemToDelete, err := selectors.ByNameOrID(opts.Ask, existingProjects, "Select the project you wish to delete:") + if err != nil { + return err + } + opts.IdOrName = itemToDelete.GetID() + } + + return nil +} + +func delete(client *client.Client, project *projects.Project) error { + return client.Projects.DeleteByID(project.GetID()) +} diff --git a/pkg/cmd/project/project.go b/pkg/cmd/project/project.go index 4496c1ad..84f02a9d 100644 --- a/pkg/cmd/project/project.go +++ b/pkg/cmd/project/project.go @@ -3,6 +3,7 @@ package project import ( "fmt" "github.com/MakeNowJust/heredoc/v2" + cmdDelete "github.com/OctopusDeploy/cli/pkg/cmd/project/delete" cmdList "github.com/OctopusDeploy/cli/pkg/cmd/project/list" cmdView "github.com/OctopusDeploy/cli/pkg/cmd/project/view" "github.com/OctopusDeploy/cli/pkg/constants" @@ -28,6 +29,7 @@ func NewCmdProject(f factory.Factory) *cobra.Command { cmd.AddCommand(cmdList.NewCmdList(f)) cmd.AddCommand(cmdView.NewCmdView(f)) + cmd.AddCommand(cmdDelete.NewCmdList(f)) return cmd } diff --git a/pkg/cmd/space/delete/delete.go b/pkg/cmd/space/delete/delete.go index c037c35a..ca7ee41b 100644 --- a/pkg/cmd/space/delete/delete.go +++ b/pkg/cmd/space/delete/delete.go @@ -16,6 +16,7 @@ import ( ) func NewCmdDelete(f factory.Factory) *cobra.Command { + var alreadyConfirmed bool cmd := &cobra.Command{ Use: "delete { | }", Short: "Delete a space in an instance of Octopus Deploy", @@ -32,11 +33,6 @@ func NewCmdDelete(f factory.Factory) *cobra.Command { itemIDOrName := args[0] - alreadyConfirmed, err := cmd.Flags().GetBool("confirm") - if err != nil { - return err - } - client, err := f.GetSystemClient() if err != nil { return err @@ -59,8 +55,8 @@ func NewCmdDelete(f factory.Factory) *cobra.Command { return nil }, } - // TODO confirm might want to be a global flag? - cmd.Flags().BoolP("confirm", "y", false, "Don't ask for confirmation before deleting the space.") + + question.RegisterDeleteFlag(cmd, &alreadyConfirmed, "space") return cmd } diff --git a/pkg/question/input.go b/pkg/question/input.go index 7e981470..b0d44f45 100644 --- a/pkg/question/input.go +++ b/pkg/question/input.go @@ -2,11 +2,28 @@ package question import ( "fmt" - "github.com/AlecAivazis/survey/v2" "github.com/OctopusDeploy/cli/pkg/output" + "github.com/OctopusDeploy/cli/pkg/util/flag" + "github.com/spf13/cobra" ) +const FlagConfirm = "confirm" + +type DeleteFlags struct { + Confirm *flag.Flag[bool] +} + +func NewDeleteFlags() *DeleteFlags { + return &DeleteFlags{ + Confirm: flag.New[bool](FlagConfirm, false), + } +} + +func RegisterDeleteFlag(cmd *cobra.Command, value *bool, resourceDescription string) { + cmd.Flags().BoolVarP(value, FlagConfirm, "y", false, fmt.Sprintf("Don't ask for confirmation before deleting the %s.", resourceDescription)) +} + func DeleteWithConfirmation(ask Asker, itemType string, itemName string, itemID string, doDelete func() error) error { var enteredName string if err := ask(&survey.Input{