diff --git a/.github/ops-files/replace-redis.yml b/.github/ops-files/replace-redis.yml new file mode 100644 index 00000000000..677e09ca8d6 --- /dev/null +++ b/.github/ops-files/replace-redis.yml @@ -0,0 +1,6 @@ +--- +- type: replace + path: /instance_groups/name=api/jobs/name=redis? + value: + name: valkey + release: capi \ No newline at end of file diff --git a/.github/workflows/tests-integration-reusable.yml b/.github/workflows/tests-integration-reusable.yml index f48692c70eb..dd3a3ea50c0 100644 --- a/.github/workflows/tests-integration-reusable.yml +++ b/.github/workflows/tests-integration-reusable.yml @@ -179,6 +179,7 @@ jobs: bosh -d cf manifest > /tmp/manifest.yml bosh interpolate /tmp/manifest.yml \ -o .github/ops-files/use-cflinuxfs3.yml \ + -o .github/ops-files/replace-redis.yml \ -o cf-deployment/operations/use-internal-lookup-for-route-services.yml \ -o cf-deployment/operations/add-persistent-isolation-segment-diego-cell.yml \ -o cli-ci/ci/infrastructure/operations/use-latest-capi.yml \ diff --git a/.github/workflows/tests-integration.yml b/.github/workflows/tests-integration.yml index 0fdc9e4714c..29a88978576 100644 --- a/.github/workflows/tests-integration.yml +++ b/.github/workflows/tests-integration.yml @@ -74,6 +74,5 @@ jobs: run-with-client-creds: false os: ubuntu-latest name: cats - is-pr: ${{ github.event_name != 'workflow_dispatch' }} secrets: inherit \ No newline at end of file diff --git a/actor/v7action/application_summary.go b/actor/v7action/application_summary.go index d33be9dd4e9..783720538af 100644 --- a/actor/v7action/application_summary.go +++ b/actor/v7action/application_summary.go @@ -1,6 +1,8 @@ package v7action import ( + "errors" + "code.cloudfoundry.org/cli/actor/actionerror" "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" @@ -18,6 +20,7 @@ type ApplicationSummary struct { type DetailedApplicationSummary struct { ApplicationSummary CurrentDroplet resources.Droplet + Deployment resources.Deployment } func (a ApplicationSummary) GetIsolationSegmentName() (string, bool) { @@ -120,6 +123,12 @@ func (actor Actor) GetDetailedAppSummary(appName, spaceGUID string, withObfuscat return DetailedApplicationSummary{}, allWarnings, err } + detailedSummary, warnings, err = actor.addDeployment(detailedSummary) + allWarnings = append(allWarnings, warnings...) + if err != nil { + return DetailedApplicationSummary{}, allWarnings, err + } + return detailedSummary, allWarnings, err } @@ -206,6 +215,19 @@ func (actor Actor) addDroplet(summary ApplicationSummary) (DetailedApplicationSu }, allWarnings, nil } +func (actor Actor) addDeployment(detailedSummary DetailedApplicationSummary) (DetailedApplicationSummary, Warnings, error) { + var allWarnings Warnings + + deployment, warnings, err := actor.GetLatestActiveDeploymentForApp(detailedSummary.GUID) + allWarnings = append(allWarnings, warnings...) + if err != nil && !errors.Is(err, actionerror.ActiveDeploymentNotFoundError{}) { + return DetailedApplicationSummary{}, allWarnings, err + } + + detailedSummary.Deployment = deployment + return detailedSummary, allWarnings, nil +} + func toAppGUIDs(apps []resources.Application) []string { guids := make([]string, len(apps)) diff --git a/actor/v7action/application_summary_test.go b/actor/v7action/application_summary_test.go index 351a06bb753..bf0a1e17259 100644 --- a/actor/v7action/application_summary_test.go +++ b/actor/v7action/application_summary_test.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" - "code.cloudfoundry.org/cli/actor/v7action" . "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/actor/v7action/v7actionfakes" "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" @@ -574,6 +573,115 @@ var _ = Describe("Application Summary Actions", func() { ) }) + When("getting application deployment succeeds", func() { + When("the deployment is active", func() { + When("the deployment strategy is rolling", func() { + When("the deployment is in progress", func() { + BeforeEach(func() { + fakeCloudControllerClient.GetDeploymentsReturns( + []resources.Deployment{ + { + GUID: "some-deployment-guid", + Strategy: "rolling", + StatusValue: "ACTIVE", + StatusReason: "DEPLOYING", + }, + }, + nil, + nil, + ) + }) + It("returns the deployment information", func() { + Expect(summary.Deployment).To(Equal(resources.Deployment{ + GUID: "some-deployment-guid", + Strategy: "rolling", + StatusValue: "ACTIVE", + StatusReason: "DEPLOYING", + })) + }) + }) + + When("the deployment is canceled", func() { + When("the deployment is in progress", func() { + BeforeEach(func() { + fakeCloudControllerClient.GetDeploymentsReturns( + []resources.Deployment{ + { + GUID: "some-deployment-guid", + Strategy: "rolling", + StatusValue: "ACTIVE", + StatusReason: "CANCELLING", + }, + }, + nil, + nil, + ) + }) + It("returns the deployment information", func() { + Expect(summary.Deployment).To(Equal(resources.Deployment{ + GUID: "some-deployment-guid", + Strategy: "rolling", + StatusValue: "ACTIVE", + StatusReason: "CANCELLING", + })) + }) + }) + }) + }) + }) + + When("the deployment is not active", func() { + BeforeEach(func() { + fakeCloudControllerClient.GetDeploymentsReturns( + []resources.Deployment{ + { + GUID: "", + Strategy: "", + StatusValue: "", + StatusReason: "", + }, + }, + nil, + nil, + ) + }) + It("returns no deployment information", func() { + Expect(summary.Deployment).To(Equal(resources.Deployment{ + GUID: "", + Strategy: "", + StatusValue: "", + StatusReason: "", + })) + }) + }) + }) + + When("getting application deployment fails", func() { + BeforeEach(func() { + fakeCloudControllerClient.GetDeploymentsReturns( + nil, + ccv3.Warnings{"get-deployments-warning"}, + errors.New("some-error"), + ) + }) + + It("returns the warnings and error", func() { + Expect(executeErr).To(MatchError("some-error")) + Expect(warnings).To(ConsistOf( + "get-apps-warning", + "get-app-processes-warning", + "get-process-by-type-warning", + "get-process-sidecars-warning", + "get-process-instances-warning", + "get-process-by-type-warning", + "get-process-sidecars-warning", + "get-process-instances-warning", + "get-app-droplet-warning", + "get-deployments-warning", + )) + }) + }) + When("getting application routes succeeds", func() { BeforeEach(func() { fakeCloudControllerClient.GetApplicationRoutesReturns( @@ -589,7 +697,7 @@ var _ = Describe("Application Summary Actions", func() { It("returns the summary and warnings with droplet information", func() { Expect(executeErr).ToNot(HaveOccurred()) Expect(summary).To(Equal(DetailedApplicationSummary{ - ApplicationSummary: v7action.ApplicationSummary{ + ApplicationSummary: ApplicationSummary{ Application: resources.Application{ Name: "some-app-name", GUID: "some-app-guid", @@ -733,7 +841,7 @@ var _ = Describe("Application Summary Actions", func() { It("returns the summary and warnings without droplet information", func() { Expect(executeErr).ToNot(HaveOccurred()) Expect(summary).To(Equal(DetailedApplicationSummary{ - ApplicationSummary: v7action.ApplicationSummary{ + ApplicationSummary: ApplicationSummary{ Application: resources.Application{ Name: "some-app-name", GUID: "some-app-guid", diff --git a/api/cloudcontroller/ccv3/constant/deployment.go b/api/cloudcontroller/ccv3/constant/deployment.go index d324cb9aafb..7927e3d1d7b 100644 --- a/api/cloudcontroller/ccv3/constant/deployment.go +++ b/api/cloudcontroller/ccv3/constant/deployment.go @@ -28,6 +28,12 @@ const ( type DeploymentStatusReason string const ( + // DeploymentStatusReasonDeploying means the deployment is in state 'DEPLOYING' + DeploymentStatusReasonDeploying DeploymentStatusReason = "DEPLOYING" + + // DeploymentCanceling means the deployment is in state 'CANCELING' + DeploymentStatusReasonCanceling DeploymentStatusReason = "CANCELING" + // DeploymentStatusReasonDeployed means the deployment's status.value is // 'DEPLOYED' DeploymentStatusReasonDeployed DeploymentStatusReason = "DEPLOYED" diff --git a/command/v7/shared/app_summary_displayer.go b/command/v7/shared/app_summary_displayer.go index 98ae553742a..6b3e71725fc 100644 --- a/command/v7/shared/app_summary_displayer.go +++ b/command/v7/shared/app_summary_displayer.go @@ -13,6 +13,8 @@ import ( "code.cloudfoundry.org/cli/types" "code.cloudfoundry.org/cli/util/ui" log "github.com/sirupsen/logrus" + "golang.org/x/text/cases" + "golang.org/x/text/language" ) type AppSummaryDisplayer struct { @@ -159,6 +161,13 @@ func (display AppSummaryDisplayer) displayProcessTable(summary v7action.Detailed } display.displayAppInstancesTable(process) } + + if summary.Deployment.StatusValue == constant.DeploymentStatusValueActive { + display.UI.DisplayNewline() + display.UI.DisplayText(fmt.Sprintf("%s deployment currently %s.", + cases.Title(language.English, cases.NoLower).String(string(summary.Deployment.Strategy)), + summary.Deployment.StatusReason)) + } } func (display AppSummaryDisplayer) getCreatedTime(summary v7action.DetailedApplicationSummary) string { diff --git a/command/v7/shared/app_summary_displayer_test.go b/command/v7/shared/app_summary_displayer_test.go index 7caf995d800..78da40d2e00 100644 --- a/command/v7/shared/app_summary_displayer_test.go +++ b/command/v7/shared/app_summary_displayer_test.go @@ -1,6 +1,7 @@ package shared_test import ( + "fmt" "time" "code.cloudfoundry.org/cli/actor/v7action" @@ -13,6 +14,8 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" . "github.com/onsi/gomega/gbytes" + "golang.org/x/text/cases" + "golang.org/x/text/language" ) var _ = Describe("app summary displayer", func() { @@ -652,5 +655,59 @@ var _ = Describe("app summary displayer", func() { Expect(testUI.Out).To(Say(`some-buildpack`)) }) }) + + When("there is an active deployment", func() { + When("the deployment strategy is rolling", func() { + When("the deployment is in progress", func() { + BeforeEach(func() { + summary = v7action.DetailedApplicationSummary{ + Deployment: resources.Deployment{ + Strategy: constant.DeploymentStrategyRolling, + StatusValue: constant.DeploymentStatusValueActive, + StatusReason: constant.DeploymentStatusReasonDeploying, + }, + } + }) + + It("displays the message", func() { + Expect(testUI.Out).To(Say("Rolling deployment currently DEPLOYING.")) + }) + }) + + When("the deployment is cancelled", func() { + BeforeEach(func() { + summary = v7action.DetailedApplicationSummary{ + Deployment: resources.Deployment{ + Strategy: constant.DeploymentStrategyRolling, + StatusValue: constant.DeploymentStatusValueActive, + StatusReason: constant.DeploymentStatusReasonCanceling, + }, + } + }) + + It("displays the message", func() { + Expect(testUI.Out).To(Say("Rolling deployment currently CANCELING.")) + }) + }) + }) + }) + + When("there is no active deployment", func() { + BeforeEach(func() { + summary = v7action.DetailedApplicationSummary{ + Deployment: resources.Deployment{ + Strategy: "", + StatusValue: "", + StatusReason: "", + }, + } + }) + + It("does not display deployment info", func() { + Expect(testUI.Out).NotTo(Say(fmt.Sprintf("%s deployment currently %s", + cases.Title(language.English, cases.NoLower).String(string(summary.Deployment.Strategy)), + summary.Deployment.StatusReason))) + }) + }) }) }) diff --git a/go.mod b/go.mod index 2a81b4798ab..984547183dd 100644 --- a/go.mod +++ b/go.mod @@ -20,19 +20,19 @@ require ( github.com/blang/semver/v4 v4.0.0 github.com/cloudfoundry/bosh-cli v6.4.1+incompatible github.com/creack/pty v1.1.21 - github.com/cyphar/filepath-securejoin v0.2.5 + github.com/cyphar/filepath-securejoin v0.3.1 github.com/distribution/reference v0.6.0 github.com/fatih/color v1.17.0 github.com/google/go-querystring v1.1.0 github.com/jessevdk/go-flags v1.6.1 github.com/lunixbochs/vtclean v1.0.0 github.com/mattn/go-colorable v0.1.13 - github.com/mattn/go-runewidth v0.0.15 + github.com/mattn/go-runewidth v0.0.16 github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1 github.com/moby/term v0.5.0 github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d - github.com/onsi/ginkgo/v2 v2.19.0 - github.com/onsi/gomega v1.33.1 + github.com/onsi/ginkgo/v2 v2.19.1 + github.com/onsi/gomega v1.34.0 github.com/pkg/errors v0.9.1 github.com/sabhiram/go-gitignore v0.0.0-20171017070213-362f9845770f github.com/sajari/fuzzy v1.0.0 @@ -40,13 +40,13 @@ require ( github.com/tedsuo/rata v1.0.1-0.20170830210128-07d200713958 github.com/vito/go-interact v0.0.0-20171111012221-fa338ed9e9ec golang.org/x/crypto v0.25.0 - golang.org/x/net v0.26.0 + golang.org/x/net v0.27.0 golang.org/x/term v0.22.0 golang.org/x/text v0.16.0 gopkg.in/cheggaaa/pb.v1 v1.0.28 gopkg.in/yaml.v2 v2.4.0 - k8s.io/apimachinery v0.30.2 - k8s.io/client-go v0.30.2 + k8s.io/apimachinery v0.30.3 + k8s.io/client-go v0.30.3 ) require ( @@ -88,7 +88,7 @@ require ( google.golang.org/genproto/googleapis/api v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240227224415-6ceb2ff114de // indirect google.golang.org/grpc v1.63.2 // indirect - google.golang.org/protobuf v1.33.0 // indirect + google.golang.org/protobuf v1.34.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect k8s.io/klog/v2 v2.120.1 // indirect diff --git a/go.sum b/go.sum index 8936d203939..f99370143e2 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/cppforlife/go-patch v0.1.0/go.mod h1:67a7aIi94FHDZdoeGSJRRFDp66l9MhaA github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= -github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= -github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= +github.com/cyphar/filepath-securejoin v0.3.1 h1:1V7cHiaW+C+39wEfpH6XlLBQo3j/PciWFrgfCLS8XrE= +github.com/cyphar/filepath-securejoin v0.3.1/go.mod h1:F7i41x/9cBF7lzCrVsYs9fuzwRZm4NQsGTBdpp6mETc= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -166,8 +166,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= -github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= +github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY= github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1 h1:NicmruxkeqHjDv03SfSxqmaLuisddudfP3h5wdXFbhM= github.com/maxbrunsfeld/counterfeiter/v6 v6.8.1/go.mod h1:eyp4DdUJAKkr9tvxR3jWhw2mDK7CWABMG5r9uyaKC7I= @@ -194,8 +194,8 @@ github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= github.com/onsi/ginkgo/v2 v2.1.4/go.mod h1:um6tUpWM/cxCK3/FK8BXqEiUMUwRgSM4JXG47RKZmLU= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= +github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= github.com/onsi/gomega v0.0.0-20171105031654-1eecca0ba8e6/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= @@ -204,8 +204,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro= github.com/onsi/gomega v1.20.0/go.mod h1:DtrZpjmvpn2mPm4YWQa0/ALMDj9v4YxLgojwPeREyVo= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os= +github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/openzipkin/zipkin-go v0.4.2 h1:zjqfqHjUpPmB3c1GlCvvgsM1G4LkvqQbBDueDOCg/jA= @@ -239,8 +239,8 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tedsuo/ifrit v0.0.0-20230516164442-7862c310ad26 h1:mWCRvpoEMVlslxEvvptKgIUb35va9yj9Oq5wGw/er5I= github.com/tedsuo/ifrit v0.0.0-20230516164442-7862c310ad26/go.mod h1:0uD3VMXkZ7Bw0ojGCwDzebBBzPBXtzEZeXai+56BLX4= github.com/tedsuo/rata v1.0.1-0.20170830210128-07d200713958 h1:mueRRuRjR35dEOkHdhpoRcruNgBz0ohG659HxxmcAwA= @@ -285,8 +285,8 @@ golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.17.0 h1:6m3ZPmLEFdVxKKWnKq4VqZ60gutO35zm+zrAHVmHyDQ= golang.org/x/oauth2 v0.17.0/go.mod h1:OzPDGQiuQMguemayvdylqddI7qcD9lnSDb+1FiwQ5HA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -374,8 +374,8 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= @@ -401,12 +401,12 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.4.0-0.dev/go.mod h1:vlRD9XErLMGT+mDuofSr0mMMquscM/1nQqtRSsh6m70= -k8s.io/api v0.30.2 h1:+ZhRj+28QT4UOH+BKznu4CBgPWgkXO7XAvMcMl0qKvI= -k8s.io/api v0.30.2/go.mod h1:ULg5g9JvOev2dG0u2hig4Z7tQ2hHIuS+m8MNZ+X6EmI= -k8s.io/apimachinery v0.30.2 h1:fEMcnBj6qkzzPGSVsAZtQThU62SmQ4ZymlXRC5yFSCg= -k8s.io/apimachinery v0.30.2/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= -k8s.io/client-go v0.30.2 h1:sBIVJdojUNPDU/jObC+18tXWcTJVcwyqS9diGdWHk50= -k8s.io/client-go v0.30.2/go.mod h1:JglKSWULm9xlJLx4KCkfLLQ7XwtlbflV6uFFSHTMgVs= +k8s.io/api v0.30.3 h1:ImHwK9DCsPA9uoU3rVh4QHAHHK5dTSv1nxJUapx8hoQ= +k8s.io/api v0.30.3/go.mod h1:GPc8jlzoe5JG3pb0KJCSLX5oAFIW3/qNJITlDj8BH04= +k8s.io/apimachinery v0.30.3 h1:q1laaWCmrszyQuSQCfNB8cFgCuDAoPszKY4ucAjDwHc= +k8s.io/apimachinery v0.30.3/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= +k8s.io/client-go v0.30.3 h1:bHrJu3xQZNXIi8/MoxYtZBBWQQXwy16zqJwloXXfD3k= +k8s.io/client-go v0.30.3/go.mod h1:8d4pf8vYu665/kUbsxWAQ/JDBNWqfFeZnvFiVdmx89U= k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw= k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= diff --git a/integration/v7/isolated/app_command_test.go b/integration/v7/isolated/app_command_test.go index a3109ceca54..b7e89fb1fad 100644 --- a/integration/v7/isolated/app_command_test.go +++ b/integration/v7/isolated/app_command_test.go @@ -253,6 +253,53 @@ applications: Eventually(session).Should(Exit(0)) }) }) + + When("there is an active deployment", func() { + BeforeEach(func() { + helpers.WithHelloWorldApp(func(appDir string) { + Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack")).Should(Exit(0)) + }) + }) + + When("the deployment strategy is rolling", func() { + When("the deployment is in progress", func() { + It("displays the message", func() { + session := helpers.CF("restart", appName, "--strategy", "rolling") + + session1 := helpers.CF("app", appName) + Eventually(session1).Should(Say("Rolling deployment currently DEPLOYING.")) + Eventually(session).Should(Exit(0)) + Eventually(session1).Should(Exit(0)) + }) + }) + When("the deployment is cancelled", func() { + It("displays the message", func() { + helpers.CF("restart", appName, "--strategy", "rolling") + Eventually(func() *Session { + return helpers.CF("cancel-deployment", appName).Wait() + }).Should(Exit(0)) + + session2 := helpers.CF("app", appName) + Eventually(session2).Should(Say("Rolling deployment currently CANCELING.")) + Eventually(session2).Should(Exit(0)) + }) + }) + }) + }) + + When("there is no active deployment", func() { + BeforeEach(func() { + helpers.WithHelloWorldApp(func(appDir string) { + Eventually(helpers.CF("push", appName, "-p", appDir, "-b", "staticfile_buildpack")).Should(Exit(0)) + }) + }) + + It("does not display the message", func() { + session := helpers.CF("app", appName) + Eventually(session).Should(Exit(0)) + Eventually(session).ShouldNot(Say(`\w+ deployment currently \w+`)) + }) + }) }) Describe("version independent display", func() { diff --git a/resources/deployment_resource.go b/resources/deployment_resource.go index 144ac076426..742b47429f4 100644 --- a/resources/deployment_resource.go +++ b/resources/deployment_resource.go @@ -18,6 +18,7 @@ type Deployment struct { UpdatedAt string Relationships Relationships NewProcesses []Process + Strategy constant.DeploymentStrategy } // MarshalJSON converts a Deployment into a Cloud Controller Deployment. @@ -59,9 +60,11 @@ func (d *Deployment) UnmarshalJSON(data []byte) error { Value constant.DeploymentStatusValue `json:"value"` Reason constant.DeploymentStatusReason `json:"reason"` } `json:"status"` - Droplet Droplet `json:"droplet,omitempty"` - NewProcesses []Process `json:"new_processes,omitempty"` + Droplet Droplet `json:"droplet,omitempty"` + NewProcesses []Process `json:"new_processes,omitempty"` + Strategy constant.DeploymentStrategy `json:"strategy"` } + err := cloudcontroller.DecodeJSON(data, &ccDeployment) if err != nil { return err @@ -75,6 +78,7 @@ func (d *Deployment) UnmarshalJSON(data []byte) error { d.StatusReason = ccDeployment.Status.Reason d.DropletGUID = ccDeployment.Droplet.GUID d.NewProcesses = ccDeployment.NewProcesses + d.Strategy = ccDeployment.Strategy return nil }