Skip to content

Commit

Permalink
Merge pull request #3595 from ActiveState/mitchell/dx-3166
Browse files Browse the repository at this point in the history
Update prompt to allow `--force` overrides.
  • Loading branch information
mitchell-as authored Nov 21, 2024
2 parents 2da0aa9 + 40b37ba commit d2ec9cd
Show file tree
Hide file tree
Showing 43 changed files with 345 additions and 321 deletions.
14 changes: 10 additions & 4 deletions cmd/state-installer/installer.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,17 @@ func (i *Installer) Install() (rerr error) {
if err != nil {
return errs.Wrap(err, "Could not determine if running as Windows administrator")
}
if isAdmin && !i.Params.force && !i.Params.isUpdate && !i.Params.nonInteractive {
prompter := prompt.New(true, i.an)
confirm, err := prompter.Confirm("", locale.T("installer_prompt_is_admin"), ptr.To(false))
if isAdmin && !i.Params.isUpdate {
prompter := prompt.New(i.out, i.an)
if i.Params.nonInteractive {
prompter.SetInteractive(false)
}
if i.Params.force {
prompter.SetForce(true)
}
confirm, err := prompter.Confirm("", locale.T("installer_prompt_is_admin"), ptr.To(false), ptr.To(true))
if err != nil {
return errs.Wrap(err, "Unable to confirm")
return errs.Wrap(err, "Not confirmed")
}
if !confirm {
return locale.NewInputError("installer_aborted", "Installation aborted by the user")
Expand Down
6 changes: 3 additions & 3 deletions cmd/state-remote-installer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func main() {
an = sync.New(anaConst.SrcStateRemoteInstaller, cfg, nil, out)

// Set up prompter
prompter := prompt.New(true, an)
prompter := prompt.New(out, an)

params := newParams()
cmd := captain.NewCommand(
Expand Down Expand Up @@ -174,9 +174,9 @@ func main() {
func execute(out output.Outputer, prompt prompt.Prompter, cfg *config.Instance, an analytics.Dispatcher, args []string, params *Params) error {
msg := locale.Tr("tos_disclaimer", constants.TermsOfServiceURLLatest)
msg += locale.Tr("tos_disclaimer_prompt", constants.TermsOfServiceURLLatest)
cont, err := prompt.Confirm(locale.Tr("install_remote_title"), msg, ptr.To(true))
cont, err := prompt.Confirm(locale.Tr("install_remote_title"), msg, ptr.To(true), nil)
if err != nil {
return errs.Wrap(err, "Could not prompt for confirmation")
return errs.Wrap(err, "Not confirmed")
}

if !cont {
Expand Down
23 changes: 5 additions & 18 deletions cmd/state/internal/cmdtree/clean.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,6 @@ func newCleanUninstallCommand(prime *primer.Values, globals *globalOptions) *cap
Description: locale.Tl("flag_state_clean_uninstall_all", "Also delete all associated config and cache files"),
Value: &params.All,
},
{
Name: "force",
Shorthand: "f",
Description: locale.T("flag_state_clean_uninstall_force_description"),
Value: &params.Force,
},
{
// This option is only used by the Windows uninstall shortcut to ask the user if they wish
// to delete everything or keep cache and config. The user is also asked to press Enter
Expand All @@ -59,13 +53,13 @@ func newCleanUninstallCommand(prime *primer.Values, globals *globalOptions) *cap
return err
}

params.NonInteractive = globals.NonInteractive // distinct from --force
params.Force = globals.Force
return runner.Run(&params)
},
)
}

func newCleanCacheCommand(prime *primer.Values, globals *globalOptions) *captain.Command {
func newCleanCacheCommand(prime *primer.Values) *captain.Command {
runner := clean.NewCache(prime)
params := clean.CacheParams{}
return captain.NewCommand(
Expand All @@ -83,30 +77,23 @@ func newCleanCacheCommand(prime *primer.Values, globals *globalOptions) *captain
},
},
func(ccmd *captain.Command, _ []string) error {
params.Force = globals.NonInteractive
return runner.Run(&params)
},
)
}

func newCleanConfigCommand(prime *primer.Values) *captain.Command {
func newCleanConfigCommand(prime *primer.Values, globals *globalOptions) *captain.Command {
runner := clean.NewConfig(prime)
params := clean.ConfigParams{}
return captain.NewCommand(
"config",
locale.Tl("clean_config_title", "Cleaning Configuration"),
locale.T("clean_config_description"),
prime,
[]*captain.Flag{
{
Name: "force",
Shorthand: "f",
Description: locale.T("flag_state_clean_config_force_description"),
Value: &params.Force,
},
},
[]*captain.Flag{},
[]*captain.Argument{},
func(ccmd *captain.Command, _ []string) error {
params.Force = globals.Force
return runner.Run(&params)
},
)
Expand Down
27 changes: 16 additions & 11 deletions cmd/state/internal/cmdtree/cmdtree.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,8 @@ func New(prime *primer.Values, args ...string) *CmdTree {
cleanCmd := newCleanCommand(prime)
cleanCmd.AddChildren(
newCleanUninstallCommand(prime, globals),
newCleanCacheCommand(prime, globals),
newCleanConfigCommand(prime),
newCleanCacheCommand(prime),
newCleanConfigCommand(prime, globals),
)

deployCmd := newDeployCommand(prime)
Expand Down Expand Up @@ -137,8 +137,8 @@ func New(prime *primer.Values, args ...string) *CmdTree {

updateCmd := newUpdateCommand(prime)
updateCmd.AddChildren(
newUpdateLockCommand(prime, globals),
newUpdateUnlockCommand(prime, globals))
newUpdateLockCommand(prime),
newUpdateUnlockCommand(prime))

branchCmd := newBranchCommand(prime)
branchCmd.AddChildren(
Expand All @@ -157,7 +157,7 @@ func New(prime *primer.Values, args ...string) *CmdTree {

useCmd := newUseCommand(prime)
useCmd.AddChildren(
newUseResetCommand(prime, globals),
newUseResetCommand(prime),
newUseShowCommand(prime),
)

Expand Down Expand Up @@ -204,8 +204,8 @@ func New(prime *primer.Values, args ...string) *CmdTree {
prepareCmd,
newProtocolCommand(prime),
newExecCommand(prime, args...),
newRevertCommand(prime, globals),
newResetCommand(prime, globals),
newRevertCommand(prime),
newResetCommand(prime),
secretsCmd,
branchCmd,
newLearnCommand(prime),
Expand Down Expand Up @@ -234,6 +234,7 @@ type globalOptions struct {
Output string
Monochrome bool
NonInteractive bool
Force bool
}

// Group instances are used to group command help output.
Expand Down Expand Up @@ -301,8 +302,16 @@ func newStateCommand(globals *globalOptions, prime *primer.Values) *captain.Comm
Description: locale.T("flag_state_non_interactive_description"),
Shorthand: "n",
Persist: true,
OnUse: func() { prime.Prompt().SetInteractive(false) },
Value: &globals.NonInteractive,
},
{
Name: "force",
Description: locale.T("flag_state_force_description"),
Persist: true,
OnUse: func() { prime.Prompt().SetForce(true) },
Value: &globals.Force,
},
{
Name: "version",
Description: locale.T("flag_state_version_description"),
Expand All @@ -318,10 +327,6 @@ func newStateCommand(globals *globalOptions, prime *primer.Values) *captain.Comm
},
[]*captain.Argument{},
func(ccmd *captain.Command, args []string) error {
if globals.Verbose {
logging.CurrentHandler().SetVerbose(true)
}

return runner.Run(ccmd.Usage)
},
)
Expand Down
3 changes: 1 addition & 2 deletions cmd/state/internal/cmdtree/reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/ActiveState/cli/internal/runners/reset"
)

func newResetCommand(prime *primer.Values, globals *globalOptions) *captain.Command {
func newResetCommand(prime *primer.Values) *captain.Command {
runner := reset.New(prime)
params := &reset.Params{}

Expand All @@ -25,7 +25,6 @@ func newResetCommand(prime *primer.Values, globals *globalOptions) *captain.Comm
},
},
func(ccmd *captain.Command, args []string) error {
params.Force = globals.NonInteractive
return runner.Run(params)
},
).SetGroup(VCSGroup).SetSupportsStructuredOutput()
Expand Down
3 changes: 1 addition & 2 deletions cmd/state/internal/cmdtree/revert.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"github.com/ActiveState/cli/internal/runners/revert"
)

func newRevertCommand(prime *primer.Values, globals *globalOptions) *captain.Command {
func newRevertCommand(prime *primer.Values) *captain.Command {
runner := revert.New(prime)
params := &revert.Params{}

Expand All @@ -32,7 +32,6 @@ func newRevertCommand(prime *primer.Values, globals *globalOptions) *captain.Com
},
},
func(ccmd *captain.Command, args []string) error {
params.Force = globals.NonInteractive
return runner.Run(params)
},
).SetGroup(VCSGroup).SetSupportsStructuredOutput()
Expand Down
6 changes: 2 additions & 4 deletions cmd/state/internal/cmdtree/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func newUpdateCommand(prime *primer.Values) *captain.Command {
return cmd
}

func newUpdateLockCommand(prime *primer.Values, globals *globalOptions) *captain.Command {
func newUpdateLockCommand(prime *primer.Values) *captain.Command {
runner := update.NewLock(prime)
params := update.LockParams{}

Expand All @@ -52,7 +52,6 @@ func newUpdateLockCommand(prime *primer.Values, globals *globalOptions) *captain
},
[]*captain.Argument{},
func(cmd *captain.Command, args []string) error {
params.NonInteractive = globals.NonInteractive
return runner.Run(&params)
},
)
Expand All @@ -61,7 +60,7 @@ func newUpdateLockCommand(prime *primer.Values, globals *globalOptions) *captain
return cmd
}

func newUpdateUnlockCommand(prime *primer.Values, globals *globalOptions) *captain.Command {
func newUpdateUnlockCommand(prime *primer.Values) *captain.Command {
runner := update.NewUnlock(prime)
params := update.UnlockParams{}

Expand All @@ -73,7 +72,6 @@ func newUpdateUnlockCommand(prime *primer.Values, globals *globalOptions) *capta
[]*captain.Flag{},
[]*captain.Argument{},
func(cmd *captain.Command, args []string) error {
params.NonInteractive = globals.NonInteractive
return runner.Run(&params)
},
)
Expand Down
3 changes: 1 addition & 2 deletions cmd/state/internal/cmdtree/use.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func newUseCommand(prime *primer.Values) *captain.Command {
return cmd
}

func newUseResetCommand(prime *primer.Values, globals *globalOptions) *captain.Command {
func newUseResetCommand(prime *primer.Values) *captain.Command {
params := &use.ResetParams{}

return captain.NewCommand(
Expand All @@ -44,7 +44,6 @@ func newUseResetCommand(prime *primer.Values, globals *globalOptions) *captain.C
[]*captain.Flag{},
[]*captain.Argument{},
func(_ *captain.Command, _ []string) error {
params.Force = globals.NonInteractive
return use.NewReset(prime).Run(params)
},
)
Expand Down
7 changes: 3 additions & 4 deletions cmd/state/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,8 @@ func main() {
// Set up our legacy outputer
setPrinterColors(outFlags)

isInteractive := strings.ToLower(os.Getenv(constants.NonInteractiveEnvVarName)) != "true" && out.Config().Interactive
// Run our main command logic, which is logic that defers to the error handling logic below
err = run(os.Args, isInteractive, cfg, out)
err = run(os.Args, cfg, out)
if err != nil {
exitCode, err = runbits_errors.ParseUserFacing(err)
if err != nil {
Expand All @@ -121,7 +120,7 @@ func main() {
}
}

func run(args []string, isInteractive bool, cfg *config.Instance, out output.Outputer) (rerr error) {
func run(args []string, cfg *config.Instance, out output.Outputer) (rerr error) {
defer profile.Measure("main:run", time.Now())

// Set up profiling
Expand Down Expand Up @@ -224,7 +223,7 @@ func run(args []string, isInteractive bool, cfg *config.Instance, out output.Out
}()

// Set up prompter
prompter := prompt.New(isInteractive, an)
prompter := prompt.New(out, an)

// Set up conditional, which accesses a lot of primer data
sshell := subshell.New(cfg)
Expand Down
3 changes: 3 additions & 0 deletions internal/captain/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,9 @@ func (c *Command) flagByName(name string, persistOnly bool) *Flag {
return flag
}
}
if c.parent != nil {
return c.parent.flagByName(name, persistOnly)
}
return nil
}

Expand Down
6 changes: 6 additions & 0 deletions internal/captain/rationalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/ActiveState/cli/internal/errs"
"github.com/ActiveState/cli/internal/locale"
"github.com/ActiveState/cli/internal/prompt"
"github.com/ActiveState/cli/internal/runbits/rationalize"
"github.com/ActiveState/cli/pkg/buildscript"
"github.com/ActiveState/cli/pkg/localcommit"
Expand Down Expand Up @@ -38,5 +39,10 @@ func rationalizeError(err *error) {
*err = errs.WrapUserFacing(*err,
locale.T("err_outdated_buildscript"),
errs.SetInput())

case errors.Is(*err, prompt.ErrNoForceOption):
*err = errs.WrapUserFacing(*err,
locale.T("err_prompt_no_force_option",
"This command has a prompt that does not support the '[ACTIONABLE]--force[/RESET]' flag."))
}
}
3 changes: 0 additions & 3 deletions internal/constants/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,6 @@ const OverrideSessionTokenEnvVarName = "ACTIVESTATE_OVERRIDE_SESSION_TOKEN"
// UpdateTagEnvVarName
const UpdateTagEnvVarName = "ACTIVESTATE_UPDATE_TAG"

// NonInteractiveEnvVarName is the name of the environment variable that specifies whether to run the State Tool without prompts
const NonInteractiveEnvVarName = "ACTIVESTATE_NONINTERACTIVE"

// E2ETestEnvVarName is the name of the environment variable that specifies that we are running under E2E tests
const E2ETestEnvVarName = "ACTIVESTATE_E2E_TEST"

Expand Down
18 changes: 13 additions & 5 deletions internal/locale/locales/en-us.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ flag_state_monochrome_output_description:
flag_state_output_description:
other: "Set the output method. Possible values: plain, simple, json, editor"
flag_state_non_interactive_description:
other: Run the State Tool without any prompts
other: Assume default values for any prompts
flag_state_force_description:
other: Disable prompts and perform the requested action regardless of defaults values (this can result in destructive or unsafe actions, such as installing packages with critical CVEs)
flag_state_version_description:
other: Show the version of our state executable
flag_state_activate_path_description:
Expand Down Expand Up @@ -755,12 +757,8 @@ cache_description:
other: Removes cached Runtime Environments
clean_config_description:
other: Removes global State Tool configuration. Project configuration will not be affected.
flag_state_clean_uninstall_force_description:
other: Run uninstall operation without prompts and ignoring any errors stopping running services
arg_state_clean_cache_project_description:
other: The project to be removed from the local cache.
flag_state_clean_config_force_description:
other: Run clean config operation without prompts and ignoring any errors stopping running services
err_uninstall_activated:
other: Cannot uninstall the State Tool while in an activated state. Please deactivate by entering [ACTIONABLE]exit[/RESET] or pressing [ACTIONABLE]Ctrl+D[/RESET] and then try again.
err_remove_cache:
Expand Down Expand Up @@ -1165,6 +1163,16 @@ warning_vulnerable_short:
prompt_continue_pkg_operation:
other: |
Do you want to continue installing this dependency despite its vulnerabilities?
prompt_continue_force:
other: "Continuing because the '[ACTIONABLE]--force[/RESET]' flag is set."
prompt_continue_non_interactive:
other: "Continuing because State Tool is running in non-interactive mode."
prompt_abort_non_interactive:
other: "Aborting because State Tool is running in non-interactive mode. To bypass you can use the '[ACTIONABLE]--force[/RESET]' flag."
prompt_using_force:
other: "Using '[ACTIONABLE]{{.V0}}[/RESET]' because the '[ACTIONABLE]--force[/RESET]' flag is set."
prompt_using_non_interactive:
other: "Using '[ACTIONABLE]{{.V0}}[/RESET]' because State Tool is running in non-interactive mode."
unstable_command_warning:
other: |
This command is still in beta. If you want to opt-in to unstable features, run the following command:
Expand Down
Loading

0 comments on commit d2ec9cd

Please sign in to comment.