From bf730234d7d2a78942b50b2fd882e9a3d92c0f2a Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 5 Nov 2024 13:16:38 +0200 Subject: [PATCH 1/5] feat: adopt delete app confirmation to new prompt util Signed-off-by: pashakostohrys --- cmd/argocd/commands/app.go | 49 ++++++++++-------------- cmd/argocd/commands/utils/prompt.go | 37 ++++++++++++++++++ cmd/argocd/commands/utils/prompt_test.go | 27 +++++++++++++ 3 files changed, 84 insertions(+), 29 deletions(-) diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index 29b3ee2df27da..da98a9dc3ee28 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -34,6 +34,8 @@ import ( "k8s.io/utils/ptr" "sigs.k8s.io/yaml" + "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/utils" + "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" "github.com/argoproj/argo-cd/v2/controller" @@ -1435,8 +1437,6 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. conn, appIf := acdClient.NewApplicationClientOrDie() defer argoio.Close(conn) var isTerminal bool = isatty.IsTerminal(os.Stdout.Fd()) || isatty.IsCygwinTerminal(os.Stdout.Fd()) - var isConfirmAll bool = false - numOfApps := len(args) promptFlag := c.Flag("yes") if promptFlag.Changed && promptFlag.Value.String() == "true" { noPrompt = true @@ -1449,6 +1449,14 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. appNames = args } + numOfApps := len(appNames) + + promptUtil := utils.NewPrompt(isTerminal && !noPrompt) + var ( + confirmAll = false + confirm bool = false + ) + for _, appFullName := range appNames { appName, appNs := argo.ParseFromQualifiedName(appFullName, appNamespace) appDeleteReq := application.ApplicationDeleteRequest{ @@ -1461,38 +1469,21 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. if c.Flag("propagation-policy").Changed { appDeleteReq.PropagationPolicy = &propagationPolicy } - if cascade && isTerminal && !noPrompt { - var lowercaseAnswer string - if numOfApps == 1 { - lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appFullName + "' and all its resources? [y/n] ") - } else { - if !isConfirmAll { - lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appFullName + "' and all its resources? [y/n/A] where 'A' is to delete all specified apps and their resources without prompting ") - if lowercaseAnswer == "a" { - lowercaseAnswer = "y" - isConfirmAll = true - } - } else { - lowercaseAnswer = "y" - } - } - if lowercaseAnswer == "y" { - _, err := appIf.Delete(ctx, &appDeleteReq) - errors.CheckError(err) - if wait { - checkForDeleteEvent(ctx, acdClient, appFullName) - } - fmt.Printf("application '%s' deleted\n", appFullName) - } else { - fmt.Println("The command to delete '" + appFullName + "' was cancelled.") - } - } else { + messageForSingle := "Are you sure you want to delete '" + appFullName + "' and all its resources? [y/n] " + messageForAll := "Are you sure you want to delete '" + appFullName + "' and all its resources? [y/n/a] where 'a' is to delete all specified apps and their resources without prompting " + + if !confirmAll { + confirm, confirmAll = promptUtil.ConfirmBaseOnCount(messageForSingle, messageForAll, numOfApps) + } + if confirm || confirmAll { _, err := appIf.Delete(ctx, &appDeleteReq) errors.CheckError(err) - if wait { checkForDeleteEvent(ctx, acdClient, appFullName) } + fmt.Printf("application '%s' deleted\n", appFullName) + } else { + fmt.Println("The command to delete '" + appFullName + "' was cancelled.") } } }, diff --git a/cmd/argocd/commands/utils/prompt.go b/cmd/argocd/commands/utils/prompt.go index 5c47750e3ee6c..2aa016ef1e0ff 100644 --- a/cmd/argocd/commands/utils/prompt.go +++ b/cmd/argocd/commands/utils/prompt.go @@ -21,3 +21,40 @@ func (p *Prompt) Confirm(message string) bool { return cli.AskToProceed(message) } + +// ConfirmAll asks the user to confirm an action. If prompts are disabled, it will return true. +// support y/n and A, which means all +// return if confirm and if all +func (p *Prompt) ConfirmAll(message string) (bool, bool) { + if !p.enabled { + return true, true + } + + result := cli.AskToProceedS(message) + + if result == "a" { + return true, true + } + + if result == "y" { + return true, false + } + + return false, false +} + +func (p *Prompt) ConfirmBaseOnCount(messageForSingle string, messageForArray string, count int) (bool, bool) { + if !p.enabled { + return true, true + } + + if count == 0 { + return true, true + } + + if count == 1 { + return p.Confirm(messageForSingle), true + } + + return p.ConfirmAll(messageForArray) +} diff --git a/cmd/argocd/commands/utils/prompt_test.go b/cmd/argocd/commands/utils/prompt_test.go index 1da0c66cb901f..b758f2b2f1c9a 100644 --- a/cmd/argocd/commands/utils/prompt_test.go +++ b/cmd/argocd/commands/utils/prompt_test.go @@ -20,3 +20,30 @@ func TestConfirm_PromptsEnabled_False(t *testing.T) { prompt := NewPrompt(false) assert.True(t, prompt.Confirm("Are you sure you want to run this command? (y/n) ")) } + +// Returns true, true when prompt is disabled +func TestConfirmAllPromptDisabled(t *testing.T) { + p := &Prompt{enabled: false} + result1, result2 := p.ConfirmAll("Proceed?") + if result1 != true || result2 != true { + t.Errorf("Expected (true, true), got (%v, %v)", result1, result2) + } +} + +func TestConfirmBaseOnCountPromptDisabled(t *testing.T) { + p := &Prompt{enabled: false} + result1, result2 := p.ConfirmBaseOnCount("Proceed?", "Process all?", 2) + + if result1 != true || result2 != true { + t.Errorf("Expected (true, true), got (%v, %v)", result1, result2) + } +} + +func TestConfirmBaseOnCountZeroApps(t *testing.T) { + p := &Prompt{enabled: true} + result1, result2 := p.ConfirmBaseOnCount("Proceed?", "Process all?", 0) + + if result1 != true || result2 != true { + t.Errorf("Expected (true, true), got (%v, %v)", result1, result2) + } +} From 93b2e77f9e4dd10ad4d88305ec8e1f6304a508e4 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 5 Nov 2024 13:41:29 +0200 Subject: [PATCH 2/5] feat: adopt delete app confirmation to new prompt util Signed-off-by: pashakostohrys --- cmd/argocd/commands/app.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index da98a9dc3ee28..c4f146983de45 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -34,9 +34,8 @@ import ( "k8s.io/utils/ptr" "sigs.k8s.io/yaml" - "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/utils" - "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/headless" + "github.com/argoproj/argo-cd/v2/cmd/argocd/commands/utils" cmdutil "github.com/argoproj/argo-cd/v2/cmd/util" "github.com/argoproj/argo-cd/v2/controller" argocdclient "github.com/argoproj/argo-cd/v2/pkg/apiclient" From 6d019467f0c1a76e9b6823b2f73e00676221fb03 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 5 Nov 2024 14:41:27 +0200 Subject: [PATCH 3/5] feat: adopt delete app confirmation to new prompt util Signed-off-by: pashakostohrys --- cmd/argocd/commands/app.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index c4f146983de45..4d5ae35bda46b 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -1450,7 +1450,9 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. numOfApps := len(appNames) - promptUtil := utils.NewPrompt(isTerminal && !noPrompt) + // This is for backward compatibility, + // before we showed the prompts only when condition cascade && isTerminal && !noPrompt is true + promptUtil := utils.NewPrompt(cascade && isTerminal && !noPrompt) var ( confirmAll = false confirm bool = false From 10e2166357e8625a8b61cc5e771a1008c6d71923 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 5 Nov 2024 14:51:55 +0200 Subject: [PATCH 4/5] feat: adopt delete app confirmation to new prompt util Signed-off-by: pashakostohrys --- cmd/argocd/commands/app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index 4d5ae35bda46b..9613684c6d0b9 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -1450,7 +1450,7 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. numOfApps := len(appNames) - // This is for backward compatibility, + // This is for backward compatibility, // before we showed the prompts only when condition cascade && isTerminal && !noPrompt is true promptUtil := utils.NewPrompt(cascade && isTerminal && !noPrompt) var ( From 5aa5112060f4027f4eecaf05440be2b3a8c8fc92 Mon Sep 17 00:00:00 2001 From: pashakostohrys Date: Tue, 5 Nov 2024 16:46:32 +0200 Subject: [PATCH 5/5] chore: remove type where it is not needed Signed-off-by: pashakostohrys --- cmd/argocd/commands/app.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/argocd/commands/app.go b/cmd/argocd/commands/app.go index 9613684c6d0b9..042459e6f05e3 100644 --- a/cmd/argocd/commands/app.go +++ b/cmd/argocd/commands/app.go @@ -1454,8 +1454,8 @@ func NewApplicationDeleteCommand(clientOpts *argocdclient.ClientOptions) *cobra. // before we showed the prompts only when condition cascade && isTerminal && !noPrompt is true promptUtil := utils.NewPrompt(cascade && isTerminal && !noPrompt) var ( - confirmAll = false - confirm bool = false + confirmAll = false + confirm = false ) for _, appFullName := range appNames {