Skip to content

Commit

Permalink
cover prompts with tests
Browse files Browse the repository at this point in the history
Signed-off-by: pashakostohrys <pavel@codefresh.io>
  • Loading branch information
pasha-codefresh committed Nov 5, 2024
1 parent 36ef563 commit 25ff8b2
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 106 deletions.
4 changes: 2 additions & 2 deletions cmd/argocd/commands/admin/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"

"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/utils"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
apiv1 "k8s.io/api/core/v1"
Expand All @@ -12,7 +13,6 @@ import (

cmdutil "github.com/argoproj/argo-cd/v2/cmd/util"
"github.com/argoproj/argo-cd/v2/common"
"github.com/argoproj/argo-cd/v2/util/cli"
"github.com/argoproj/argo-cd/v2/util/db"
"github.com/argoproj/argo-cd/v2/util/errors"
"github.com/argoproj/argo-cd/v2/util/git"
Expand Down Expand Up @@ -134,7 +134,7 @@ func NewGenRepoSpecCommand() *cobra.Command {
// If the user set a username, but didn't supply password via --password,
// then we prompt for it
if repoOpts.Repo.Username != "" && repoOpts.Repo.Password == "" {
repoOpts.Repo.Password = cli.PromptPassword(repoOpts.Repo.Password)
repoOpts.Repo.Password = utils.PromptPassword(repoOpts.Repo.Password)
}

argoCDCM := &apiv1.ConfigMap{
Expand Down
6 changes: 3 additions & 3 deletions cmd/argocd/commands/applicationset.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"reflect"
"text/tabwriter"

"github.com/argoproj/argo-cd/v2/cmd/argocd/commands/utils"
"github.com/mattn/go-isatty"
"github.com/spf13/cobra"
"google.golang.org/grpc/codes"
Expand All @@ -18,7 +19,6 @@ import (
"github.com/argoproj/argo-cd/v2/pkg/apiclient/applicationset"
arogappsetv1 "github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/v2/util/argo"
"github.com/argoproj/argo-cd/v2/util/cli"
"github.com/argoproj/argo-cd/v2/util/errors"
"github.com/argoproj/argo-cd/v2/util/grpc"
argoio "github.com/argoproj/argo-cd/v2/util/io"
Expand Down Expand Up @@ -362,10 +362,10 @@ func NewApplicationSetDeleteCommand(clientOpts *argocdclient.ClientOptions) *cob
if isTerminal && !noPrompt {
var lowercaseAnswer string
if numOfApps == 1 {
lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appSetQualifiedName + "' and all its Applications? [y/n] ")
lowercaseAnswer = utils.AskToProceedS("Are you sure you want to delete '" + appSetQualifiedName + "' and all its Applications? [y/n] ")
} else {
if !isConfirmAll {
lowercaseAnswer = cli.AskToProceedS("Are you sure you want to delete '" + appSetQualifiedName + "' and all its Applications? [y/n/A] where 'A' is to delete all specified ApplicationSets and their Applications without prompting")
lowercaseAnswer = utils.AskToProceedS("Are you sure you want to delete '" + appSetQualifiedName + "' and all its Applications? [y/n/A] where 'A' is to delete all specified ApplicationSets and their Applications without prompting")
if lowercaseAnswer == "a" || lowercaseAnswer == "all" {
lowercaseAnswer = "y"
isConfirmAll = true
Expand Down
144 changes: 137 additions & 7 deletions cmd/argocd/commands/utils/prompt.go
Original file line number Diff line number Diff line change
@@ -1,23 +1,153 @@
package utils

import (
"github.com/argoproj/argo-cd/v2/util/cli"
"bufio"
"fmt"
"os"
"strings"

"github.com/argoproj/pkg/errors"
log "github.com/sirupsen/logrus"
"golang.org/x/crypto/ssh/terminal"
)

type Prompt struct {
type Prompt interface {
Confirm(message string) bool
}

type PromptOpts struct {
// PromptsEnabled indicates whether prompts should be enabled
Enabled bool
}

type prompt struct {
enabled bool
}

func NewPrompt(promptsEnabled bool) *Prompt {
return &Prompt{
enabled: promptsEnabled,
func NewPrompt(opts... PromptOpts) Prompt {
enabled := false
if len(opts) > 0 {
enabled = opts[0].Enabled
}

return &prompt{
enabled: enabled,
}
}

func (p *Prompt) Confirm(message string) bool {
// Confirm prompts the user with a message (typically a yes or no question) and returns whether
// they responded in the affirmative or negative.
func (p *prompt) Confirm(message string) bool {
if !p.enabled {
return true
}

return cli.AskToProceed(message)
return askToProceed(message)
}


type AskToProcess interface {
AskToProceed(message string) bool
AskToProceedS(message string) string
}

type askToProcess struct{}

func NewAskToProcess() AskToProcess {
return &askToProcess{}
}


// AskToProceed prompts the user with a message (typically a yes or no question) and returns whether
// they responded in the affirmative or negative.
func (a *askToProcess) AskToProceed(message string) bool {
for {
fmt.Print(message)
reader := bufio.NewReader(os.Stdin)
proceedRaw, err := reader.ReadString('\n')
errors.CheckError(err)
switch strings.ToLower(strings.TrimSpace(proceedRaw)) {
case "y", "yes":
return true
case "n", "no":
return false
}
}
}

// AskToProceedS prompts the user with a message (typically a yes, no or all question) and returns string
// "a", "y" or "n".
func AskToProceedS(message string) string {
for {
fmt.Print(message)
reader := bufio.NewReader(os.Stdin)
proceedRaw, err := reader.ReadString('\n')
errors.CheckError(err)
switch strings.ToLower(strings.TrimSpace(proceedRaw)) {
case "y", "yes":
return "y"
case "n", "no":
return "n"
case "a", "all":
return "a"
}
}
}



// PromptCredentials is a helper to prompt the user for a username and password (unless already supplied)
func PromptCredentials(username, password string) (string, string) {
return PromptUsername(username), PromptPassword(password)
}

// PromptUsername prompts the user for a username value
func PromptUsername(username string) string {
return PromptMessage("Username", username)
}

// PromptMessage prompts the user for a value (unless already supplied)
func PromptMessage(message, value string) string {
for value == "" {
reader := bufio.NewReader(os.Stdin)
fmt.Print(message + ": ")
valueRaw, err := reader.ReadString('\n')
errors.CheckError(err)
value = strings.TrimSpace(valueRaw)
}
return value
}

// PromptPassword prompts the user for a password, without local echo. (unless already supplied)
func PromptPassword(password string) string {
for password == "" {
fmt.Print("Password: ")
passwordRaw, err := terminal.ReadPassword(int(os.Stdin.Fd()))
errors.CheckError(err)
password = string(passwordRaw)
fmt.Print("\n")
}
return password
}

// ReadAndConfirmPassword is a helper to read and confirm a password from stdin
func ReadAndConfirmPassword(username string) (string, error) {
for {
fmt.Printf("*** Enter new password for user %s: ", username)
password, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return "", err
}
fmt.Print("\n")
fmt.Printf("*** Confirm new password for user %s: ", username)
confirmPassword, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return "", err
}
fmt.Print("\n")
if string(password) == string(confirmPassword) {
return string(password), nil
}
log.Error("Passwords do not match")
}
}
94 changes: 0 additions & 94 deletions util/cli/cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
package cli

import (
"bufio"
"bytes"
"flag"
"fmt"
Expand All @@ -18,7 +17,6 @@ import (
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
terminal "golang.org/x/term"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"
Expand Down Expand Up @@ -79,98 +77,6 @@ func AddKubectlFlagsToSet(flags *pflag.FlagSet) clientcmd.ClientConfig {
return clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, &overrides, os.Stdin)
}

// PromptCredentials is a helper to prompt the user for a username and password (unless already supplied)
func PromptCredentials(username, password string) (string, string) {
return PromptUsername(username), PromptPassword(password)
}

// PromptUsername prompts the user for a username value
func PromptUsername(username string) string {
return PromptMessage("Username", username)
}

// PromptMessage prompts the user for a value (unless already supplied)
func PromptMessage(message, value string) string {
for value == "" {
reader := bufio.NewReader(os.Stdin)
fmt.Print(message + ": ")
valueRaw, err := reader.ReadString('\n')
errors.CheckError(err)
value = strings.TrimSpace(valueRaw)
}
return value
}

// PromptPassword prompts the user for a password, without local echo. (unless already supplied)
func PromptPassword(password string) string {
for password == "" {
fmt.Print("Password: ")
passwordRaw, err := terminal.ReadPassword(int(os.Stdin.Fd()))
errors.CheckError(err)
password = string(passwordRaw)
fmt.Print("\n")
}
return password
}

// AskToProceed prompts the user with a message (typically a yes or no question) and returns whether
// they responded in the affirmative or negative.
func AskToProceed(message string) bool {
for {
fmt.Print(message)
reader := bufio.NewReader(os.Stdin)
proceedRaw, err := reader.ReadString('\n')
errors.CheckError(err)
switch strings.ToLower(strings.TrimSpace(proceedRaw)) {
case "y", "yes":
return true
case "n", "no":
return false
}
}
}

// AskToProceedS prompts the user with a message (typically a yes, no or all question) and returns string
// "a", "y" or "n".
func AskToProceedS(message string) string {
for {
fmt.Print(message)
reader := bufio.NewReader(os.Stdin)
proceedRaw, err := reader.ReadString('\n')
errors.CheckError(err)
switch strings.ToLower(strings.TrimSpace(proceedRaw)) {
case "y", "yes":
return "y"
case "n", "no":
return "n"
case "a", "all":
return "a"
}
}
}

// ReadAndConfirmPassword is a helper to read and confirm a password from stdin
func ReadAndConfirmPassword(username string) (string, error) {
for {
fmt.Printf("*** Enter new password for user %s: ", username)
password, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return "", err
}
fmt.Print("\n")
fmt.Printf("*** Confirm new password for user %s: ", username)
confirmPassword, err := terminal.ReadPassword(int(os.Stdin.Fd()))
if err != nil {
return "", err
}
fmt.Print("\n")
if string(password) == string(confirmPassword) {
return string(password), nil
}
log.Error("Passwords do not match")
}
}

// SetLogFormat sets a logrus log format
func SetLogFormat(logFormat string) {
switch strings.ToLower(logFormat) {
Expand Down

0 comments on commit 25ff8b2

Please sign in to comment.