From ccd958777ce03bffce844ae098189a210dc9fd65 Mon Sep 17 00:00:00 2001 From: Matt Ellis Date: Mon, 25 Mar 2019 13:45:12 -0700 Subject: [PATCH] Don't print `error` prefix when a confirmation prompt is declined Use `result.Result` in more places, so when a confirmation prompt is declined, we just return `result.Bail()` after printing a message without the `error: ` prefix. Fixes #2070 --- CHANGELOG.md | 10 ++++++---- cmd/cancel.go | 16 +++++++++------- cmd/stack_rm.go | 18 ++++++++++-------- cmd/state.go | 20 ++++++++++++-------- cmd/state_delete.go | 17 +++++++++-------- cmd/state_unprotect.go | 23 ++++++++++++----------- pkg/backend/apply.go | 11 ++++++----- 7 files changed, 64 insertions(+), 51 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3af903cd2..e11862142 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,10 @@ ## 0.17.4 (Unreleased) -## 0.17.3 (Released March 26, 2019) +## Improvements -- Add support for serializing JavaScript function that capture [BigInts](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt). -- Support serializing arrow-functions with deconstructed parameters. +- Don't print the `error:` prefix when Pulumi exists because of a declined confirmation prompt (fixes [pulumi/pulumi#458](https://github.com/pulumi/pulumi/issues/2070)) + +## 0.17.3 (Released March 26, 2019) ### Improvements @@ -12,7 +13,8 @@ - A bug in the previous version of the Pulumi CLI occasionally caused the Pulumi Engine to load the incorrect resource plugin when processing an update. This bug has been fixed in 0.17.3 by performing a deterministic selection of the best set of plugins available to the engine before starting up. See - [pulumi/pulumi#2579](https://github.com/pulumi/pulumi/issues/2579) for discussion on this issue. +- Add support for serializing JavaScript function that capture [BigInts](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt). +- Support serializing arrow-functions with deconstructed parameters. ## 0.17.2 (Released March 15, 2019) diff --git a/cmd/cancel.go b/cmd/cancel.go index f2fbe08bd..184e8add5 100644 --- a/cmd/cancel.go +++ b/cmd/cancel.go @@ -17,7 +17,8 @@ package cmd import ( "fmt" - "github.com/pkg/errors" + "github.com/pulumi/pulumi/pkg/util/result" + "github.com/spf13/cobra" "github.com/pulumi/pulumi/pkg/backend/display" @@ -41,11 +42,11 @@ func newCancelCmd() *cobra.Command { "\n" + "After this command completes successfully, the stack will be ready for further\n" + "updates.", - Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error { + Run: cmdutil.RunResultFunc(func(cmd *cobra.Command, args []string) result.Result { // Use the stack provided or, if missing, default to the current one. if len(args) > 0 { if stack != "" { - return errors.New("only one of --stack or argument stack name may be specified, not both") + return result.Error("only one of --stack or argument stack name may be specified, not both") } stack = args[0] @@ -57,25 +58,26 @@ func newCancelCmd() *cobra.Command { s, err := requireStack(stack, false, opts, true /*setCurrent*/) if err != nil { - return err + return result.FromError(err) } // Ensure that we are targeting the Pulumi cloud. backend, ok := s.Backend().(httpstate.Backend) if !ok { - return errors.New("the `cancel` command is not supported for local stacks") + return result.Error("the `cancel` command is not supported for local stacks") } // Ensure the user really wants to do this. stackName := string(s.Ref().Name()) prompt := fmt.Sprintf("This will irreversibly cancel the currently running update for '%s'!", stackName) if !yes && !confirmPrompt(prompt, stackName, opts) { - return errors.New("confirmation declined") + fmt.Println("confirmation declined") + return result.Bail() } // Cancel the update. if err := backend.CancelCurrentUpdate(commandContext(), s.Ref()); err != nil { - return err + return result.FromError(err) } msg := fmt.Sprintf( diff --git a/cmd/stack_rm.go b/cmd/stack_rm.go index 642071971..7f336f08d 100644 --- a/cmd/stack_rm.go +++ b/cmd/stack_rm.go @@ -18,7 +18,8 @@ import ( "fmt" "os" - "github.com/pkg/errors" + "github.com/pulumi/pulumi/pkg/util/result" + "github.com/spf13/cobra" "github.com/pulumi/pulumi/pkg/backend/display" @@ -44,11 +45,11 @@ func newStackRmCmd() *cobra.Command { "`destroy` command for removing a resources, as this is a distinct operation.\n" + "\n" + "After this command completes, the stack will no longer be available for updates.", - Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error { + Run: cmdutil.RunResultFunc(func(cmd *cobra.Command, args []string) result.Result { // Use the stack provided or, if missing, default to the current one. if len(args) > 0 { if stack != "" { - return errors.New("only one of --stack or argument stack name may be specified, not both") + return result.Error("only one of --stack or argument stack name may be specified, not both") } stack = args[0] } @@ -59,29 +60,30 @@ func newStackRmCmd() *cobra.Command { s, err := requireStack(stack, false, opts, true /*setCurrent*/) if err != nil { - return err + return result.FromError(err) } // Ensure the user really wants to do this. prompt := fmt.Sprintf("This will permanently remove the '%s' stack!", s.Ref()) if !yes && !confirmPrompt(prompt, s.Ref().String(), opts) { - return errors.New("confirmation declined") + fmt.Println("confirmation declined") + return result.Bail() } hasResources, err := s.Remove(commandContext(), force) if err != nil { if hasResources { - return errors.Errorf( + return result.Errorf( "'%s' still has resources; removal rejected; pass --force to override", s.Ref()) } - return err + return result.FromError(err) } if !preserveConfig { // Blow away stack specific settings if they exist. If we get an ENOENT error, ignore it. if path, err := workspace.DetectProjectStackPath(s.Ref().Name()); err == nil { if err = os.Remove(path); err != nil && !os.IsNotExist(err) { - return err + return result.FromError(err) } } } diff --git a/cmd/state.go b/cmd/state.go index bef2b558a..ca414b770 100644 --- a/cmd/state.go +++ b/cmd/state.go @@ -18,6 +18,8 @@ import ( "encoding/json" "fmt" + "github.com/pulumi/pulumi/pkg/util/result" + "github.com/pulumi/pulumi/pkg/util/contract" "github.com/pkg/errors" @@ -109,7 +111,7 @@ func locateStackResource(opts display.Options, snap *deploy.Snapshot, urn resour } // runStateEdit runs the given state edit function on a resource with the given URN in a given stack. -func runStateEdit(stackName string, urn resource.URN, operation edit.OperationFunc) error { +func runStateEdit(stackName string, urn resource.URN, operation edit.OperationFunc) result.Result { return runTotalStateEdit(stackName, func(opts display.Options, snap *deploy.Snapshot) error { res, err := locateStackResource(opts, snap, urn) if err != nil { @@ -122,17 +124,18 @@ func runStateEdit(stackName string, urn resource.URN, operation edit.OperationFu // runTotalStateEdit runs a snapshot-mutating function on the entirity of the given stack's snapshot. Before mutating // the snapshot, the user is prompted for confirmation if the current session is interactive. -func runTotalStateEdit(stackName string, operation func(opts display.Options, snap *deploy.Snapshot) error) error { +func runTotalStateEdit(stackName string, + operation func(opts display.Options, snap *deploy.Snapshot) error) result.Result { opts := display.Options{ Color: cmdutil.GetGlobalColorization(), } s, err := requireStack(stackName, true, opts, true /*setCurrent*/) if err != nil { - return err + return result.FromError(err) } snap, err := s.Snapshot(commandContext()) if err != nil { - return err + return result.FromError(err) } if cmdutil.Interactive() { @@ -145,7 +148,8 @@ func runTotalStateEdit(stackName string, operation func(opts display.Options, sn if err = survey.AskOne(&survey.Confirm{ Message: prompt, }, &confirm, nil); err != nil || !confirm { - return errors.New("confirmation declined") + fmt.Println("confirmation declined") + return result.Bail() } } @@ -154,7 +158,7 @@ func runTotalStateEdit(stackName string, operation func(opts display.Options, sn // before we mutated it, we'll assert that we didn't make it invalid by mutating it. stackIsAlreadyHosed := snap.VerifyIntegrity() != nil if err = operation(opts, snap); err != nil { - return err + return result.FromError(err) } // If the stack is already broken, don't bother verifying the integrity here. @@ -165,11 +169,11 @@ func runTotalStateEdit(stackName string, operation func(opts display.Options, sn // Once we've mutated the snapshot, import it back into the backend so that it can be persisted. bytes, err := json.Marshal(stack.SerializeDeployment(snap)) if err != nil { - return err + return result.FromError(err) } dep := apitype.UntypedDeployment{ Version: apitype.DeploymentSchemaVersionCurrent, Deployment: bytes, } - return s.ImportDeployment(commandContext(), &dep) + return result.WrapIfNonNil(s.ImportDeployment(commandContext(), &dep)) } diff --git a/cmd/state_delete.go b/cmd/state_delete.go index 908ef90e2..576241a40 100644 --- a/cmd/state_delete.go +++ b/cmd/state_delete.go @@ -17,13 +17,14 @@ package cmd import ( "fmt" + "github.com/pulumi/pulumi/pkg/util/result" + "github.com/pulumi/pulumi/pkg/diag" "github.com/pulumi/pulumi/pkg/resource" "github.com/pulumi/pulumi/pkg/resource/deploy" "github.com/pulumi/pulumi/pkg/resource/edit" "github.com/pulumi/pulumi/pkg/util/cmdutil" - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -42,9 +43,9 @@ by its Pulumi URN (use 'pulumi stack --show-urns' to get it). Resources can't be deleted if there exist other resources that depend on it or are parented to it. Protected resources will not be deleted unless it is specifically requested using the --force flag.`, Args: cmdutil.ExactArgs(1), - Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error { + Run: cmdutil.RunResultFunc(func(cmd *cobra.Command, args []string) result.Result { urn := resource.URN(args[0]) - err := runStateEdit(stack, urn, func(snap *deploy.Snapshot, res *resource.State) error { + res := runStateEdit(stack, urn, func(snap *deploy.Snapshot, res *resource.State) error { if !force { return edit.DeleteResource(snap, res) } @@ -56,8 +57,8 @@ will not be deleted unless it is specifically requested using the --force flag.` return edit.DeleteResource(snap, res) }) - if err != nil { - switch e := err.(type) { + if res != nil { + switch e := res.Error().(type) { case edit.ResourceHasDependenciesError: message := "This resource can't be safely deleted because the following resources depend on it:\n" for _, dependentResource := range e.Dependencies { @@ -66,13 +67,13 @@ will not be deleted unless it is specifically requested using the --force flag.` } message += "\nDelete those resources first before deleting this one." - return errors.New(message) + return result.Error(message) case edit.ResourceProtectedError: - return errors.New( + return result.Error( "This resource can't be safely deleted because it is protected. " + "Re-run this command with --force to force deletion") default: - return err + return res } } fmt.Println("Resource deleted successfully") diff --git a/cmd/state_unprotect.go b/cmd/state_unprotect.go index c33a6d033..f360b558d 100644 --- a/cmd/state_unprotect.go +++ b/cmd/state_unprotect.go @@ -17,9 +17,10 @@ package cmd import ( "fmt" + "github.com/pulumi/pulumi/pkg/util/result" + "github.com/pulumi/pulumi/pkg/util/contract" - "github.com/pkg/errors" "github.com/pulumi/pulumi/pkg/backend/display" "github.com/pulumi/pulumi/pkg/resource/deploy" @@ -41,13 +42,13 @@ func newStateUnprotectCommand() *cobra.Command { This command clears the 'protect' bit on one or more resources, allowing those resources to be deleted.`, Args: cmdutil.MaximumNArgs(1), - Run: cmdutil.RunFunc(func(cmd *cobra.Command, args []string) error { + Run: cmdutil.RunResultFunc(func(cmd *cobra.Command, args []string) result.Result { if unprotectAll { return unprotectAllResources(stack) } if len(args) != 1 { - return errors.New("must provide a URN corresponding to a resource") + return result.Error("must provide a URN corresponding to a resource") } urn := resource.URN(args[0]) @@ -62,8 +63,8 @@ This command clears the 'protect' bit on one or more resources, allowing those r return cmd } -func unprotectAllResources(stackName string) error { - err := runTotalStateEdit(stackName, func(_ display.Options, snap *deploy.Snapshot) error { +func unprotectAllResources(stackName string) result.Result { + res := runTotalStateEdit(stackName, func(_ display.Options, snap *deploy.Snapshot) error { for _, res := range snap.Resources { err := edit.UnprotectResource(snap, res) contract.AssertNoError(err) @@ -72,17 +73,17 @@ func unprotectAllResources(stackName string) error { return nil }) - if err != nil { - return err + if res != nil { + return res } fmt.Println("All resources successfully unprotected") return nil } -func unprotectResource(stackName string, urn resource.URN) error { - err := runStateEdit(stackName, urn, edit.UnprotectResource) - if err != nil { - return err +func unprotectResource(stackName string, urn resource.URN) result.Result { + res := runStateEdit(stackName, urn, edit.UnprotectResource) + if res != nil { + return res } fmt.Println("Resource successfully unprotected") return nil diff --git a/pkg/backend/apply.go b/pkg/backend/apply.go index 1cec2ccd9..1a18bd41e 100644 --- a/pkg/backend/apply.go +++ b/pkg/backend/apply.go @@ -123,14 +123,14 @@ func PreviewThenPrompt(ctx context.Context, kind apitype.UpdateKind, stack Stack } // Otherwise, ensure the user wants to proceed. - err := confirmBeforeUpdating(kind, stack, events, op.Opts) + res = confirmBeforeUpdating(kind, stack, events, op.Opts) close(eventsChannel) - return changes, result.WrapIfNonNil(err) + return changes, res } // confirmBeforeUpdating asks the user whether to proceed. A nil error means yes. func confirmBeforeUpdating(kind apitype.UpdateKind, stack Stack, - events []engine.Event, opts UpdateOptions) error { + events []engine.Event, opts UpdateOptions) result.Result { for { var response string @@ -167,11 +167,12 @@ func confirmBeforeUpdating(kind apitype.UpdateKind, stack Stack, Options: choices, Default: string(no), }, &response, nil); err != nil { - return errors.Wrapf(err, "confirmation cancelled, not proceeding with the %s", kind) + return result.FromError(errors.Wrapf(err, "confirmation cancelled, not proceeding with the %s", kind)) } if response == string(no) { - return errors.Errorf("confirmation declined, not proceeding with the %s", kind) + fmt.Printf("confirmation declined, not proceeding with the %s\n", kind) + return result.Bail() } if response == string(yes) {