diff --git a/command/v7/push_command.go b/command/v7/push_command.go index c18d98430c6..4d6b48019e6 100644 --- a/command/v7/push_command.go +++ b/command/v7/push_command.go @@ -10,6 +10,7 @@ import ( "code.cloudfoundry.org/cli/actor/sharedaction" "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/actor/v7pushaction" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" "code.cloudfoundry.org/cli/cf/errors" "code.cloudfoundry.org/cli/command" @@ -111,6 +112,7 @@ type PushCommand struct { CWD string ManifestLocator ManifestLocator ManifestParser ManifestParser + DiffDisplayer DiffDisplayer stopStreamingFunc func() } @@ -132,6 +134,7 @@ func (cmd *PushCommand) Setup(config command.Config, ui command.UI) error { cmd.ManifestLocator = manifestparser.NewLocator() cmd.ManifestParser = manifestparser.ManifestParser{} + cmd.DiffDisplayer = shared.NewManifestDiffDisplayer(ui) return err } @@ -182,10 +185,30 @@ func (cmd PushCommand) Execute(args []string) error { hasManifest := transformedManifest.PathToManifest != "" + spaceGUID := cmd.Config.TargetedSpace().GUID if hasManifest { cmd.UI.DisplayText("Applying manifest file {{.Path}}...", map[string]interface{}{ "Path": transformedManifest.PathToManifest, }) + + diff, warnings, err := cmd.Actor.DiffSpaceManifest(spaceGUID, transformedRawManifest) + + cmd.UI.DisplayWarnings(warnings) + if err != nil { + if _, isUnexpectedError := err.(ccerror.V3UnexpectedResponseError); isUnexpectedError { + cmd.UI.DisplayWarning("Unable to generate diff. Continuing to apply manifest...") + } else { + return err + } + } else { + cmd.UI.DisplayNewline() + cmd.UI.DisplayText("Updating with these attributes...") + + err = cmd.DiffDisplayer.DisplayDiff(transformedRawManifest, diff) + if err != nil { + return err + } + } } v7ActionWarnings, err := cmd.VersionActor.SetSpaceManifest( diff --git a/command/v7/push_command_test.go b/command/v7/push_command_test.go index 14273806aae..eba133c0599 100644 --- a/command/v7/push_command_test.go +++ b/command/v7/push_command_test.go @@ -10,6 +10,7 @@ import ( "code.cloudfoundry.org/cli/actor/sharedaction/sharedactionfakes" "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/actor/v7pushaction" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" "code.cloudfoundry.org/cli/command/commandfakes" "code.cloudfoundry.org/cli/command/flag" @@ -84,6 +85,8 @@ var _ = Describe("push Command", func() { fakeConfig *commandfakes.FakeConfig fakeSharedActor *commandfakes.FakeSharedActor fakeActor *v7fakes.FakePushActor + fakeDiffActor *v7fakes.FakeActor + fakeDiffDisplayer *v7fakes.FakeDiffDisplayer fakeVersionActor *v7fakes.FakeV7ActorForPush fakeProgressBar *v7fakes.FakeProgressBar fakeLogCacheClient *sharedactionfakes.FakeLogCacheClient @@ -106,6 +109,8 @@ var _ = Describe("push Command", func() { fakeConfig = new(commandfakes.FakeConfig) fakeSharedActor = new(commandfakes.FakeSharedActor) fakeActor = new(v7fakes.FakePushActor) + fakeDiffActor = new(v7fakes.FakeActor) + fakeDiffDisplayer = new(v7fakes.FakeDiffDisplayer) fakeVersionActor = new(v7fakes.FakeV7ActorForPush) fakeProgressBar = new(v7fakes.FakeProgressBar) fakeLogCacheClient = new(sharedactionfakes.FakeLogCacheClient) @@ -127,6 +132,7 @@ var _ = Describe("push Command", func() { SharedActor: fakeSharedActor, UI: testUI, Config: fakeConfig, + Actor: fakeDiffActor, }, PushActor: fakeActor, VersionActor: fakeVersionActor, @@ -135,6 +141,7 @@ var _ = Describe("push Command", func() { CWD: pwd, ManifestLocator: fakeManifestLocator, ManifestParser: fakeManifestParser, + DiffDisplayer: fakeDiffDisplayer, } }) @@ -324,6 +331,81 @@ var _ = Describe("push Command", func() { Expect(actualManifestBytes).To(Equal([]byte("our-manifest"))) }) + When("the manifest is successfully parsed", func() { + var expectedDiff resources.ManifestDiff + + BeforeEach(func() { + fakeActor.HandleFlagOverridesReturns( + manifestparser.Manifest{ + PathToManifest: "path/to/manifest", + }, + nil, + ) + expectedDiff = resources.ManifestDiff{ + Diffs: []resources.Diff{ + {Op: resources.AddOperation, Path: "/path/to/field", Value: "hello"}, + }, + } + + fakeVersionActor.SetSpaceManifestReturns( + v7action.Warnings{"some-manifest-warning"}, + nil, + ) + + fakeDiffActor.DiffSpaceManifestReturns( + expectedDiff, + nil, + nil, + ) + }) + + It("shows the manifest diff and sets the manifest", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(testUI.Out).To(Say("Applying manifest file %s...", ("path/to/manifest"))) + Expect(testUI.Err).To(Say("some-manifest-warning")) + + Expect(fakeDiffActor.DiffSpaceManifestCallCount()).To(Equal(1)) + spaceGUID, manifestBytes := fakeDiffActor.DiffSpaceManifestArgsForCall(0) + Expect(spaceGUID).To(Equal("some-space-guid")) + Expect(manifestBytes).To(Equal([]byte("our-manifest"))) + + Expect(fakeDiffDisplayer.DisplayDiffCallCount()).To(Equal(1)) + manifestBytes, diff := fakeDiffDisplayer.DisplayDiffArgsForCall(0) + Expect(manifestBytes).To(Equal([]byte("our-manifest"))) + Expect(diff).To(Equal(expectedDiff)) + + Expect(fakeVersionActor.SetSpaceManifestCallCount()).To(Equal(1)) + spaceGUIDArg, actualBytes := fakeVersionActor.SetSpaceManifestArgsForCall(0) + Expect(actualBytes).To(Equal([]byte("our-manifest"))) + Expect(spaceGUIDArg).To(Equal("some-space-guid")) + }) + + When("the manifest diff fails", func() { + BeforeEach(func() { + fakeDiffActor.DiffSpaceManifestReturns(resources.ManifestDiff{}, v7action.Warnings{}, ccerror.V3UnexpectedResponseError{}) + }) + + It("reports the 500, does not display the diff, but still applies the manifest", func() { + Expect(executeErr).ToNot(HaveOccurred()) + + Expect(testUI.Err).To(Say("Unable to generate diff. Continuing to apply manifest...")) + Expect(fakeDiffDisplayer.DisplayDiffCallCount()).To(Equal(0)) + Expect(fakeVersionActor.SetSpaceManifestCallCount()).To(Equal(1)) + }) + }) + + When("displaying the manifest diff fails", func() { + BeforeEach(func() { + fakeDiffDisplayer.DisplayDiffReturns(errors.New("diff failed")) + }) + + It("returns the diff error", func() { + Expect(executeErr).To(MatchError("diff failed")) + Expect(fakeVersionActor.SetSpaceManifestCallCount()).To(Equal(0)) + }) + }) + }) + When("applying the manifest fails", func() { BeforeEach(func() { fakeVersionActor.SetSpaceManifestReturns(v7action.Warnings{"apply-manifest-warnings"}, errors.New("apply-manifest-error"))