diff --git a/internal/prompt/prompt.go b/internal/prompt/prompt.go index 4735947305..07c004c9d4 100644 --- a/internal/prompt/prompt.go +++ b/internal/prompt/prompt.go @@ -15,17 +15,6 @@ import ( "github.com/ActiveState/cli/internal/output" ) -type ConfirmKind int - -const ( - // A confirm prompt was completed by the user. - User ConfirmKind = iota - // A confirm prompt was completed in non-interactive mode. - NonInteractive - // A confirm prompt was completed via --force. - Force -) - type EventDispatcher interface { EventWithLabel(category, action string, label string, dim ...*dimensions.Values) } @@ -35,11 +24,12 @@ type Prompter interface { Input(title, message string, defaultResponse *string, flags ...ValidatorFlag) (string, error) InputAndValidate(title, message string, defaultResponse *string, validator ValidatorFunc, flags ...ValidatorFlag) (string, error) Select(title, message string, choices []string, defaultResponse *string) (string, error) - Confirm(title, message string, defaultChoice *bool, forcedChoice *bool) (bool, ConfirmKind, error) + Confirm(title, message string, defaultChoice *bool, forcedChoice *bool) (bool, error) InputSecret(title, message string, flags ...ValidatorFlag) (string, error) IsInteractive() bool SetInteractive(bool) EnableForce() + IsForceEnabled() bool } // ValidatorFunc is a function pass to the Prompter to perform validation @@ -76,6 +66,10 @@ func (p *Prompt) EnableForce() { p.isForced = true } +func (p *Prompt) IsForceEnabled() bool { + return p.isForced +} + // ValidatorFlag represents flags for prompt functions to change their behavior on. type ValidatorFlag int @@ -183,21 +177,21 @@ func (p *Prompt) Select(title, message string, choices []string, defaultChoice * } // Confirm prompts user for yes or no response. -func (p *Prompt) Confirm(title, message string, defaultChoice *bool, forcedChoice *bool) (bool, ConfirmKind, error) { +func (p *Prompt) Confirm(title, message string, defaultChoice *bool, forcedChoice *bool) (bool, error) { if p.isForced { if forcedChoice == nil { - return false, Force, errs.New("No force option given for force-enabled prompt") + return false, errs.New("No force option given for force-enabled prompt") } logging.Debug("Prompt %s confirmed with choice %v in force mode", title, forcedChoice) - return *forcedChoice, Force, nil + return *forcedChoice, nil } if !p.isInteractive { if defaultChoice != nil { logging.Debug("Prompt %s confirmed with default choice %v in non-interactive mode", title, defaultChoice) - return *defaultChoice, NonInteractive, nil + return *defaultChoice, nil } - return false, NonInteractive, interactiveInputError(message) + return false, interactiveInputError(message) } if title != "" { p.out.Notice(output.Emphasize(title)) @@ -219,11 +213,11 @@ func (p *Prompt) Confirm(title, message string, defaultChoice *bool, forcedChoic if err == terminal.InterruptErr { p.analytics.EventWithLabel(constants.CatPrompt, title, "interrupt") } - return false, User, locale.NewInputError(err.Error()) + return false, locale.NewInputError(err.Error()) } p.analytics.EventWithLabel(constants.CatPrompt, title, translateConfirm(resp)) - return resp, User, nil + return resp, nil } func translateConfirm(confirm bool) string { diff --git a/internal/runbits/auth/keypair.go b/internal/runbits/auth/keypair.go index c92ee7974b..b91c44671b 100644 --- a/internal/runbits/auth/keypair.go +++ b/internal/runbits/auth/keypair.go @@ -116,14 +116,11 @@ func promptForPreviousPassphrase(prompt prompt.Prompter) (string, error) { func promptUserToRegenerateKeypair(passphrase string, cfg keypairs.Configurable, out output.Outputer, prmpt prompt.Prompter, auth *authentication.Auth) error { // previous passphrase is invalid, inform user and ask if they want to generate a new keypair out.Notice(locale.T("auth_generate_new_keypair_message")) - yes, kind, err := prmpt.Confirm("", locale.T("auth_confirm_generate_new_keypair_prompt"), ptr.To(false), nil) + yes, err := prmpt.Confirm("", locale.T("auth_confirm_generate_new_keypair_prompt"), ptr.To(false), nil) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !yes { - if kind == prompt.NonInteractive { - return locale.NewInputError("prompt_abort_non_interactive") - } return locale.NewInputError("auth_err_unrecoverable_keypair") } _, err = keypairs.GenerateAndSaveEncodedKeypair(cfg, secretsapi.Get(auth), passphrase, constants.DefaultRSABitLength, auth) diff --git a/internal/runbits/auth/login.go b/internal/runbits/auth/login.go index 785a759f02..ac902ef2aa 100644 --- a/internal/runbits/auth/login.go +++ b/internal/runbits/auth/login.go @@ -266,7 +266,7 @@ func authenticateWithBrowser(out output.Outputer, auth *authentication.Auth, pro var cont bool var err error for !cont { - cont, _, err = prompt.Confirm(locale.Tl("continue", "Continue?"), locale.T("auth_press_enter"), ptr.To(false), nil) + cont, err = prompt.Confirm(locale.Tl("continue", "Continue?"), locale.T("auth_press_enter"), ptr.To(false), nil) if err != nil { return errs.Wrap(err, "Prompt failed") } diff --git a/internal/runbits/cves/cves.go b/internal/runbits/cves/cves.go index 0ecb893c8f..a82649c489 100644 --- a/internal/runbits/cves/cves.go +++ b/internal/runbits/cves/cves.go @@ -12,7 +12,6 @@ import ( configMediator "github.com/ActiveState/cli/internal/mediators/config" "github.com/ActiveState/cli/internal/output" "github.com/ActiveState/cli/internal/primer" - "github.com/ActiveState/cli/internal/prompt" "github.com/ActiveState/cli/internal/rtutils/ptr" "github.com/ActiveState/cli/pkg/buildplan" vulnModel "github.com/ActiveState/cli/pkg/platform/api/vulnerabilities/model" @@ -106,12 +105,12 @@ func (c *CveReport) Report(newBuildPlan *buildplan.BuildPlan, oldBuildPlan *buil c.summarizeCVEs(vulnerabilities) - confirm, kind, err := c.prime.Prompt().Confirm("", locale.Tr("prompt_continue_pkg_operation"), ptr.To(false), ptr.To(true)) + confirm, err := c.prime.Prompt().Confirm("", locale.Tr("prompt_continue_pkg_operation"), ptr.To(false), ptr.To(true)) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !confirm { - if kind == prompt.NonInteractive { + if !c.prime.Prompt().IsInteractive() { return errs.AddTips( locale.NewInputError("prompt_abort_non_interactive"), locale.Tl("more_info_prompt", "To disable security prompting run: [ACTIONABLE]state config set security.prompt.enabled false[/RESET]"), @@ -119,7 +118,7 @@ func (c *CveReport) Report(newBuildPlan *buildplan.BuildPlan, oldBuildPlan *buil } return locale.NewInputError("err_pkgop_security_prompt", "Operation aborted by user") } - if kind == prompt.Force { + if c.prime.Prompt().IsForceEnabled() { c.prime.Output().Notice(locale.T("prompt_continue_force")) } c.prime.Output().Notice("") // Empty line diff --git a/internal/runners/clean/cache.go b/internal/runners/clean/cache.go index e8ca73adf4..bbb87ede43 100644 --- a/internal/runners/clean/cache.go +++ b/internal/runners/clean/cache.go @@ -71,14 +71,14 @@ func (c *Cache) Run(params *CacheParams) error { func (c *Cache) removeCache(path string) error { defaultValue := !c.prime.Prompt().IsInteractive() - ok, kind, err := c.prime.Prompt().Confirm(locale.T("confirm"), locale.T("clean_cache_confirm"), &defaultValue, nil) + ok, err := c.prime.Prompt().Confirm(locale.T("confirm"), locale.T("clean_cache_confirm"), &defaultValue, nil) if err != nil { return errs.Wrap(err, "Could not confirm") } if !ok { return locale.NewInputError("err_clean_cache_not_confirmed", "Cleaning of cache aborted by user") } - if kind == prompt.NonInteractive { + if !c.prime.Prompt().IsInteractive() { c.prime.Output().Notice(locale.T("prompt_continue_non_interactive")) } @@ -101,14 +101,14 @@ func (c *Cache) removeCache(path string) error { func (c *Cache) removeProjectCache(projectDir, namespace string) error { defaultValue := !c.prime.Prompt().IsInteractive() - ok, kind, err := c.prime.Prompt().Confirm(locale.T("confirm"), locale.Tr("clean_cache_artifact_confirm", namespace), &defaultValue, nil) + ok, err := c.prime.Prompt().Confirm(locale.T("confirm"), locale.Tr("clean_cache_artifact_confirm", namespace), &defaultValue, nil) if err != nil { return errs.Wrap(err, "Could not confirm") } if !ok { return locale.NewInputError("err_clean_cache_artifact_not_confirmed", "Cleaning of cached runtime aborted by user") } - if kind == prompt.NonInteractive { + if !c.prime.Prompt().IsInteractive() { c.prime.Output().Notice(locale.T("prompt_continue_non_interactive")) } diff --git a/internal/runners/clean/config.go b/internal/runners/clean/config.go index 6524b86371..c0aeebc2dd 100644 --- a/internal/runners/clean/config.go +++ b/internal/runners/clean/config.go @@ -54,17 +54,17 @@ func (c *Config) Run(params *ConfigParams) error { } defaultChoice := !c.confirm.IsInteractive() - ok, kind, err := c.confirm.Confirm(locale.T("confirm"), locale.T("clean_config_confirm"), &defaultChoice, ptr.To(true)) + ok, err := c.confirm.Confirm(locale.T("confirm"), locale.T("clean_config_confirm"), &defaultChoice, ptr.To(true)) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !ok { return locale.NewInputError("err_clean_config_aborted", "Cleaning of config aborted by user") } - switch kind { - case prompt.NonInteractive: + switch { + case !c.confirm.IsInteractive(): c.output.Notice(locale.T("prompt_continue_non_interactive")) - case prompt.Force: + case c.confirm.IsForceEnabled(): c.output.Notice(locale.T("prompt_continue_force")) } diff --git a/internal/runners/clean/uninstall.go b/internal/runners/clean/uninstall.go index 1b888697c1..d8c671cc44 100644 --- a/internal/runners/clean/uninstall.go +++ b/internal/runners/clean/uninstall.go @@ -83,17 +83,17 @@ func (u *Uninstall) Run(params *UninstallParams) error { if params.All { confirmMessage = locale.T("uninstall_confirm_all") } - ok, kind, err := u.prompt.Confirm(locale.T("confirm"), confirmMessage, &defaultChoice, ptr.To(true)) + ok, err := u.prompt.Confirm(locale.T("confirm"), confirmMessage, &defaultChoice, ptr.To(true)) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !ok { return locale.NewInputError("err_uninstall_aborted", "Uninstall aborted by user") } - switch kind { - case prompt.NonInteractive: + switch { + case !u.prompt.IsInteractive(): u.out.Notice(locale.T("prompt_continue_non_interactive")) - case prompt.Force: + case u.prompt.IsForceEnabled(): u.out.Notice(locale.T("prompt_continue_force")) } } diff --git a/internal/runners/projects/delete.go b/internal/runners/projects/delete.go index 20912814eb..6c1aae3a7e 100644 --- a/internal/runners/projects/delete.go +++ b/internal/runners/projects/delete.go @@ -38,14 +38,14 @@ func (d *Delete) Run(params *DeleteParams) error { } defaultChoice := !d.prompt.IsInteractive() - confirm, kind, err := d.prompt.Confirm("", locale.Tl("project_delete_confim", "Are you sure you want to delete the project {{.V0}}?", params.Project.String()), &defaultChoice, nil) + confirm, err := d.prompt.Confirm("", locale.Tl("project_delete_confim", "Are you sure you want to delete the project {{.V0}}?", params.Project.String()), &defaultChoice, nil) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !confirm { return locale.NewInputError("err_project_delete_aborted", "Delete aborted by user") } - if kind == prompt.NonInteractive { + if !d.prompt.IsInteractive() { d.out.Notice(locale.T("prompt_continue_non_interactive")) } diff --git a/internal/runners/projects/edit.go b/internal/runners/projects/edit.go index 8919008058..741d588f92 100644 --- a/internal/runners/projects/edit.go +++ b/internal/runners/projects/edit.go @@ -91,14 +91,14 @@ func (e *Edit) Run(params *EditParams) error { editMsg += locale.Tl("edit_prompt_confirm", "Continue?") defaultChoice := !e.prompt.IsInteractive() - edit, kind, err := e.prompt.Confirm("", editMsg, &defaultChoice, nil) + edit, err := e.prompt.Confirm("", editMsg, &defaultChoice, nil) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !edit { return locale.NewInputError("edit_cancelled", "Project edit cancelled") } - if kind == prompt.NonInteractive { + if !e.prompt.IsInteractive() { e.out.Notice(locale.T("prompt_continue_non_interactive")) } diff --git a/internal/runners/projects/move.go b/internal/runners/projects/move.go index fa9e7ed2a1..858dbead14 100644 --- a/internal/runners/projects/move.go +++ b/internal/runners/projects/move.go @@ -42,14 +42,14 @@ func (m *Move) Run(params *MoveParams) error { } defaultChoice := !m.prompt.IsInteractive() - move, kind, err := m.prompt.Confirm("", locale.Tr("move_prompt", params.Namespace.String(), params.NewOwner, params.Namespace.Project), &defaultChoice, nil) + move, err := m.prompt.Confirm("", locale.Tr("move_prompt", params.Namespace.String(), params.NewOwner, params.Namespace.Project), &defaultChoice, nil) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !move { return locale.NewInputError("move_cancelled", "Project move aborted by user") } - if kind == prompt.NonInteractive { + if !m.prompt.IsInteractive() { m.out.Notice(locale.T("prompt_continue_non_interactive")) } diff --git a/internal/runners/publish/publish.go b/internal/runners/publish/publish.go index 2b8af90997..239a5233bb 100644 --- a/internal/runners/publish/publish.go +++ b/internal/runners/publish/publish.go @@ -218,7 +218,7 @@ func (r *Runner) Run(params *Params) error { return errs.Wrap(err, "Could not marshal publish variables") } - cont, kind, err := r.prompt.Confirm( + cont, err := r.prompt.Confirm( "", locale.Tl("uploadingredient_confirm", `Prepared the following ingredient: @@ -232,7 +232,7 @@ Do you want to publish this ingredient? if !cont { return locale.NewInputError("uploadingredient_cancel", "Publish cancelled") } - if kind == prompt.NonInteractive { + if !r.prompt.IsInteractive() { r.out.Notice(locale.T("prompt_continue_non_interactive")) } diff --git a/internal/runners/push/push.go b/internal/runners/push/push.go index 10f935dfe8..d4db851d73 100644 --- a/internal/runners/push/push.go +++ b/internal/runners/push/push.go @@ -128,14 +128,14 @@ func (r *Push) Run(params PushParams) (rerr error) { // Ask to create a copy if the user does not have org permissions if intend&pushFromNoPermission > 0 && !params.Namespace.IsValid() { - createCopy, kind, err := r.prompt.Confirm("", locale.T("push_prompt_not_authorized"), ptr.To(true), nil) + createCopy, err := r.prompt.Confirm("", locale.T("push_prompt_not_authorized"), ptr.To(true), nil) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !createCopy { return nil } - if kind == prompt.NonInteractive { + if !r.prompt.IsInteractive() { r.out.Notice(locale.T("prompt_continue_non_interactive")) } } @@ -172,7 +172,7 @@ func (r *Push) Run(params PushParams) (rerr error) { // If the user didn't necessarily intend to create the project we should ask them for confirmation if intend&intendCreateProject == 0 { - createProject, kind, err := r.prompt.Confirm( + createProject, err := r.prompt.Confirm( locale.Tl("create_project", "Create Project"), locale.Tl("push_confirm_create_project", "You are about to create the project [NOTICE]{{.V0}}[/RESET]. Continue?", targetNamespace.String()), ptr.To(true), nil) @@ -182,7 +182,7 @@ func (r *Push) Run(params PushParams) (rerr error) { if !createProject { return rationalize.ErrActionAborted } - if kind == prompt.NonInteractive { + if !r.prompt.IsInteractive() { r.out.Notice(locale.T("prompt_continue_non_interactive")) } } diff --git a/internal/runners/reset/reset.go b/internal/runners/reset/reset.go index 944842bf67..2f27cd1931 100644 --- a/internal/runners/reset/reset.go +++ b/internal/runners/reset/reset.go @@ -117,14 +117,14 @@ func (r *Reset) Run(params *Params) error { r.out.Notice(locale.Tl("reset_commit", "Your project will be reset to [ACTIONABLE]{{.V0}}[/RESET]\n", commitID.String())) if commitID != localCommitID { defaultChoice := !r.prime.Prompt().IsInteractive() - confirm, kind, err := r.prime.Prompt().Confirm("", locale.Tl("reset_confim", "Resetting is destructive. You will lose any changes that were not pushed. Are you sure you want to do this?"), &defaultChoice, nil) + confirm, err := r.prime.Prompt().Confirm("", locale.Tl("reset_confim", "Resetting is destructive. You will lose any changes that were not pushed. Are you sure you want to do this?"), &defaultChoice, nil) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !confirm { return locale.NewInputError("err_reset_aborted", "Reset aborted by user") } - if kind == prompt.NonInteractive { + if !r.prime.Prompt().IsInteractive() { r.prime.Output().Notice(locale.T("prompt_continue_non_interactive")) } } diff --git a/internal/runners/revert/revert.go b/internal/runners/revert/revert.go index 335bab3af4..0618528826 100644 --- a/internal/runners/revert/revert.go +++ b/internal/runners/revert/revert.go @@ -139,14 +139,14 @@ func (r *Revert) Run(params *Params) (rerr error) { } defaultChoice := !r.prime.Prompt().IsInteractive() - revert, kind, err := r.prime.Prompt().Confirm("", locale.Tl("revert_confirm", "Continue?"), &defaultChoice, nil) + revert, err := r.prime.Prompt().Confirm("", locale.Tl("revert_confirm", "Continue?"), &defaultChoice, nil) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !revert { return locale.NewInputError("err_revert_aborted", "Revert aborted by user") } - if kind == prompt.NonInteractive { + if !r.prime.Prompt().IsInteractive() { r.prime.Output().Notice(locale.T("prompt_continue_non_interactive")) } diff --git a/internal/runners/scripts/edit.go b/internal/runners/scripts/edit.go index 3f3e04be19..59d74333c9 100644 --- a/internal/runners/scripts/edit.go +++ b/internal/runners/scripts/edit.go @@ -237,7 +237,7 @@ func startInteractive(sw *scriptWatcher, scriptName string, output output.Output go sw.run(scriptName, output, cfg, proj) for { - doneEditing, _, err := prompt.Confirm("", locale.T("prompt_done_editing"), ptr.To(true), nil) + doneEditing, err := prompt.Confirm("", locale.T("prompt_done_editing"), ptr.To(true), nil) if err != nil { return errs.Wrap(err, "Prompter returned with failure.") } diff --git a/internal/runners/update/lock.go b/internal/runners/update/lock.go index 707d01b8a7..9ad15b52b9 100644 --- a/internal/runners/update/lock.go +++ b/internal/runners/update/lock.go @@ -131,14 +131,14 @@ func confirmLock(prom prompt.Prompter, out output.Outputer) error { defaultChoice := !prom.IsInteractive() msg := locale.T("confirm_update_locked_version_prompt") - confirmed, kind, err := prom.Confirm(locale.T("confirm"), msg, &defaultChoice, nil) + confirmed, err := prom.Confirm(locale.T("confirm"), msg, &defaultChoice, nil) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !confirmed { return locale.NewInputError("err_update_lock_noconfirm", "Cancelling by your request.") } - if kind == prompt.NonInteractive { + if !prom.IsInteractive() { out.Notice(locale.T("prompt_continue_non_interactive")) } diff --git a/internal/runners/update/unlock.go b/internal/runners/update/unlock.go index 8eae02f42d..d3d5e99921 100644 --- a/internal/runners/update/unlock.go +++ b/internal/runners/update/unlock.go @@ -73,14 +73,14 @@ func confirmUnlock(prom prompt.Prompter, out output.Outputer) error { msg := locale.T("confirm_update_unlocked_version_prompt") defaultChoice := !prom.IsInteractive() - confirmed, kind, err := prom.Confirm(locale.T("confirm"), msg, &defaultChoice, nil) + confirmed, err := prom.Confirm(locale.T("confirm"), msg, &defaultChoice, nil) if err != nil { return errs.Wrap(err, "Unable to confirm") } if !confirmed { return locale.NewInputError("err_update_lock_noconfirm", "Cancelling by your request.") } - if kind == prompt.NonInteractive { + if !prom.IsInteractive() { out.Notice(locale.T("prompt_continue_non_interactive")) } diff --git a/internal/runners/upgrade/upgrade.go b/internal/runners/upgrade/upgrade.go index 22d8caeb2f..41f2207cf6 100644 --- a/internal/runners/upgrade/upgrade.go +++ b/internal/runners/upgrade/upgrade.go @@ -12,7 +12,6 @@ import ( "github.com/ActiveState/cli/internal/locale" "github.com/ActiveState/cli/internal/output" "github.com/ActiveState/cli/internal/primer" - "github.com/ActiveState/cli/internal/prompt" "github.com/ActiveState/cli/internal/rtutils/ptr" "github.com/ActiveState/cli/internal/runbits/commits_runbit" "github.com/ActiveState/cli/internal/runbits/rationalize" @@ -284,14 +283,14 @@ func (u *Upgrade) renderUserFacing(changes []structuredChange, expand bool) erro out.Print(tbl.Render()) out.Notice(" ") // Empty line (prompts use Notice) - confirm, kind, err := u.prime.Prompt().Confirm("", locale.Tr("upgrade_confirm"), ptr.To(true), nil) + confirm, err := u.prime.Prompt().Confirm("", locale.Tr("upgrade_confirm"), ptr.To(true), nil) if err != nil { return errs.Wrap(err, "confirmation failed") } if !confirm { return ErrAbort } - if kind == prompt.NonInteractive { + if !u.prime.Prompt().IsInteractive() { u.prime.Output().Notice(locale.T("prompt_continue_non_interactive")) } diff --git a/internal/runners/use/reset.go b/internal/runners/use/reset.go index 85e5b0283e..9fa5aa26e8 100644 --- a/internal/runners/use/reset.go +++ b/internal/runners/use/reset.go @@ -40,7 +40,7 @@ func (u *Reset) Run(params *ResetParams) error { } defaultChoice := !u.prompt.IsInteractive() - ok, kind, err := u.prompt.Confirm(locale.T("confirm"), + ok, err := u.prompt.Confirm(locale.T("confirm"), locale.Tl("use_reset_confirm", "You are about to stop using your project runtime. Continue?"), &defaultChoice, nil) if err != nil { return errs.Wrap(err, "Unable to confirm") @@ -48,7 +48,7 @@ func (u *Reset) Run(params *ResetParams) error { if !ok { return locale.NewInputError("err_reset_aborted", "Reset aborted by user") } - if kind == prompt.NonInteractive { + if !u.prompt.IsInteractive() { u.out.Notice(locale.T("prompt_continue_non_interactive")) }