diff --git a/actor/actionerror/buildpack_not_found_error.go b/actor/actionerror/buildpack_not_found_error.go index 88da77ed3ac..0bd411bfac6 100644 --- a/actor/actionerror/buildpack_not_found_error.go +++ b/actor/actionerror/buildpack_not_found_error.go @@ -6,8 +6,9 @@ import "fmt" type BuildpackNotFoundError struct { BuildpackName string StackName string + Lifecycle string } func (e BuildpackNotFoundError) Error() string { - return fmt.Sprintf("Buildpack not found - Name: '%s'; Stack: '%s'", e.BuildpackName, e.StackName) + return fmt.Sprintf("Buildpack not found - Name: '%s'; Stack: '%s', Lifecyle: '%s'", e.BuildpackName, e.StackName, e.Lifecycle) } diff --git a/actor/v7action/buildpack.go b/actor/v7action/buildpack.go index 0fc3eab27cd..522881dc761 100644 --- a/actor/v7action/buildpack.go +++ b/actor/v7action/buildpack.go @@ -21,52 +21,60 @@ type Downloader interface { Download(url string, tmpDirPath string) (string, error) } -func (actor Actor) GetBuildpacks(labelSelector string) ([]resources.Buildpack, Warnings, error) { - queries := []ccv3.Query{ccv3.Query{Key: ccv3.OrderBy, Values: []string{ccv3.PositionOrder}}} +func (actor Actor) GetBuildpacks(labelSelector string, lifecycle string) ([]resources.Buildpack, Warnings, error) { + queries := []ccv3.Query{} if labelSelector != "" { queries = append(queries, ccv3.Query{Key: ccv3.LabelSelectorFilter, Values: []string{labelSelector}}) } + if lifecycle != "" { + queries = append(queries, ccv3.Query{Key: ccv3.LifecycleFilter, Values: []string{lifecycle}}) + } + buildpacks, warnings, err := actor.CloudControllerClient.GetBuildpacks(queries...) return buildpacks, Warnings(warnings), err } -// GetBuildpackByNameAndStack returns a buildpack with the provided name and -// stack. If `buildpackStack` is not specified, and there are multiple +// GetBuildpackByNameAndStackAndLifecycle returns a buildpack with the provided name, stack, +// and lifecycle. If `buildpackStack` is not specified, and there are multiple // buildpacks with the same name, it will return the one with no stack, if -// present. -func (actor Actor) GetBuildpackByNameAndStack(buildpackName string, buildpackStack string) (resources.Buildpack, Warnings, error) { +// present. If `buildpackLifecycle` is not specified and there are multiple buildpacks with +// the same name, it will return the one with the default_app_lifecycle, if present. +func (actor Actor) GetBuildpackByNameAndStackAndLifecycle(buildpackName string, buildpackStack string, buildpackLifecycle string) (resources.Buildpack, Warnings, error) { var ( buildpacks []resources.Buildpack warnings ccv3.Warnings err error ) - if buildpackStack == "" { - buildpacks, warnings, err = actor.CloudControllerClient.GetBuildpacks(ccv3.Query{ - Key: ccv3.NameFilter, - Values: []string{buildpackName}, + queries := []ccv3.Query{{ + Key: ccv3.NameFilter, + Values: []string{buildpackName}, + }} + + if buildpackStack != "" { + queries = append(queries, ccv3.Query{ + Key: ccv3.StackFilter, + Values: []string{buildpackStack}, }) - } else { - buildpacks, warnings, err = actor.CloudControllerClient.GetBuildpacks( - ccv3.Query{ - Key: ccv3.NameFilter, - Values: []string{buildpackName}, - }, - ccv3.Query{ - Key: ccv3.StackFilter, - Values: []string{buildpackStack}, - }, - ) } + if buildpackLifecycle != "" { + queries = append(queries, ccv3.Query{ + Key: ccv3.LifecycleFilter, + Values: []string{buildpackLifecycle}, + }) + } + + buildpacks, warnings, err = actor.CloudControllerClient.GetBuildpacks(queries...) + if err != nil { return resources.Buildpack{}, Warnings(warnings), err } if len(buildpacks) == 0 { - return resources.Buildpack{}, Warnings(warnings), actionerror.BuildpackNotFoundError{BuildpackName: buildpackName, StackName: buildpackStack} + return resources.Buildpack{}, Warnings(warnings), actionerror.BuildpackNotFoundError{BuildpackName: buildpackName, StackName: buildpackStack, Lifecycle: buildpackLifecycle} } if len(buildpacks) > 1 { @@ -87,9 +95,9 @@ func (actor Actor) CreateBuildpack(buildpack resources.Buildpack) (resources.Bui return buildpack, Warnings(warnings), err } -func (actor Actor) UpdateBuildpackByNameAndStack(buildpackName string, buildpackStack string, buildpack resources.Buildpack) (resources.Buildpack, Warnings, error) { +func (actor Actor) UpdateBuildpackByNameAndStackAndLifecycle(buildpackName string, buildpackStack string, buildpackLifecycle string, buildpack resources.Buildpack) (resources.Buildpack, Warnings, error) { var warnings Warnings - foundBuildpack, getWarnings, err := actor.GetBuildpackByNameAndStack(buildpackName, buildpackStack) + foundBuildpack, getWarnings, err := actor.GetBuildpackByNameAndStackAndLifecycle(buildpackName, buildpackStack, buildpackLifecycle) warnings = append(warnings, getWarnings...) if err != nil { @@ -250,9 +258,9 @@ func Zipit(source, target, prefix string) error { return err } -func (actor Actor) DeleteBuildpackByNameAndStack(buildpackName string, buildpackStack string) (Warnings, error) { +func (actor Actor) DeleteBuildpackByNameAndStackAndLifecycle(buildpackName string, buildpackStack string, buildpackLifecycle string) (Warnings, error) { var allWarnings Warnings - buildpack, getBuildpackWarnings, err := actor.GetBuildpackByNameAndStack(buildpackName, buildpackStack) + buildpack, getBuildpackWarnings, err := actor.GetBuildpackByNameAndStackAndLifecycle(buildpackName, buildpackStack, buildpackLifecycle) allWarnings = append(allWarnings, getBuildpackWarnings...) if err != nil { return allWarnings, err diff --git a/actor/v7action/buildpack_test.go b/actor/v7action/buildpack_test.go index 8af4b5078e2..e8dfc034a64 100644 --- a/actor/v7action/buildpack_test.go +++ b/actor/v7action/buildpack_test.go @@ -28,23 +28,24 @@ var _ = Describe("Buildpack", func() { actor, fakeCloudControllerClient, _, _, _, _, _ = NewTestActor() }) - Describe("GetBuildpackByNameAndStack", func() { + Describe("GetBuildpackByNameAndStackAndLifecycle", func() { var ( - buildpackName = "buildpack-1" - buildpackStack = "stack-name" - buildpack resources.Buildpack - warnings Warnings - executeErr error + buildpackName = "buildpack-1" + buildpackStack = "stack-name" + buildpackLifecycle = "buildpack" + buildpack resources.Buildpack + warnings Warnings + executeErr error ) JustBeforeEach(func() { - buildpack, warnings, executeErr = actor.GetBuildpackByNameAndStack(buildpackName, buildpackStack) + buildpack, warnings, executeErr = actor.GetBuildpackByNameAndStackAndLifecycle(buildpackName, buildpackStack, buildpackLifecycle) }) When("getting buildpacks fails", func() { BeforeEach(func() { - buildpackStack = "real-good-stack" + buildpackLifecycle = "some-lifecycle" fakeCloudControllerClient.GetBuildpacksReturns( nil, ccv3.Warnings{"some-warning-1", "some-warning-2"}, @@ -65,6 +66,10 @@ var _ = Describe("Buildpack", func() { Key: ccv3.StackFilter, Values: []string{buildpackStack}, }, + ccv3.Query{ + Key: ccv3.LifecycleFilter, + Values: []string{buildpackLifecycle}, + }, )) }) }) @@ -120,15 +125,16 @@ var _ = Describe("Buildpack", func() { }) It("returns warnings and a BuildpackNotFoundError", func() { - Expect(executeErr).To(MatchError(actionerror.BuildpackNotFoundError{BuildpackName: buildpackName, StackName: buildpackStack})) + Expect(executeErr).To(MatchError(actionerror.BuildpackNotFoundError{BuildpackName: buildpackName, StackName: buildpackStack, Lifecycle: buildpackLifecycle})) Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2")) }) }) When("getting buildpacks is successful", func() { - When("No stack is specified", func() { + When("No stack or lifecycle is specified", func() { BeforeEach(func() { buildpackStack = "" + buildpackLifecycle = "" buildpackName = "my-buildpack" ccBuildpack := resources.Buildpack{Name: "my-buildpack", GUID: "some-guid"} @@ -144,7 +150,7 @@ var _ = Describe("Buildpack", func() { Expect(buildpack).To(Equal(resources.Buildpack{Name: "my-buildpack", GUID: "some-guid"})) }) - It("Does not pass a stack query to the client", func() { + It("Does not pass a stack or lifecycle query to the client", func() { Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1)) queries := fakeCloudControllerClient.GetBuildpacksArgsForCall(0) Expect(queries).To(ConsistOf( @@ -156,10 +162,11 @@ var _ = Describe("Buildpack", func() { }) }) - When("A stack is specified", func() { + When("only a stack is specified", func() { BeforeEach(func() { buildpackStack = "good-stack" buildpackName = "my-buildpack" + buildpackLifecycle = "" ccBuildpack := resources.Buildpack{Name: "my-buildpack", GUID: "some-guid", Stack: "good-stack"} fakeCloudControllerClient.GetBuildpacksReturns( @@ -174,7 +181,7 @@ var _ = Describe("Buildpack", func() { Expect(buildpack).To(Equal(resources.Buildpack{Name: "my-buildpack", GUID: "some-guid", Stack: "good-stack"})) }) - It("Does pass a stack query to the client", func() { + It("Only passes a stack query to the client", func() { Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1)) queries := fakeCloudControllerClient.GetBuildpacksArgsForCall(0) Expect(queries).To(ConsistOf( @@ -189,6 +196,78 @@ var _ = Describe("Buildpack", func() { )) }) }) + When("only a lifecycle is specified", func() { + BeforeEach(func() { + buildpackLifecycle = "good-lifecycle" + buildpackStack = "" + buildpackName = "my-buildpack" + + ccBuildpack := resources.Buildpack{Name: "my-buildpack", GUID: "some-guid", Lifecycle: "good-lifecycle"} + fakeCloudControllerClient.GetBuildpacksReturns( + []resources.Buildpack{ccBuildpack}, + ccv3.Warnings{"some-warning-1", "some-warning-2"}, + nil) + }) + + It("Returns the proper buildpack", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2")) + Expect(buildpack).To(Equal(resources.Buildpack{Name: "my-buildpack", GUID: "some-guid", Lifecycle: "good-lifecycle"})) + }) + + It("Only passes a lifecycle query to the client", func() { + Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1)) + queries := fakeCloudControllerClient.GetBuildpacksArgsForCall(0) + Expect(queries).To(ConsistOf( + ccv3.Query{ + Key: ccv3.NameFilter, + Values: []string{buildpackName}, + }, + ccv3.Query{ + Key: ccv3.LifecycleFilter, + Values: []string{buildpackLifecycle}, + }, + )) + }) + }) + When("When stack and lifecycle are specified", func() { + BeforeEach(func() { + buildpackLifecycle = "good-lifecycle" + buildpackStack = "good-stack" + buildpackName = "my-buildpack" + + ccBuildpack := resources.Buildpack{Name: "my-buildpack", GUID: "some-guid", Lifecycle: "good-lifecycle", Stack: "good-stack"} + fakeCloudControllerClient.GetBuildpacksReturns( + []resources.Buildpack{ccBuildpack}, + ccv3.Warnings{"some-warning-1", "some-warning-2"}, + nil) + }) + + It("Returns the proper buildpack", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(warnings).To(ConsistOf("some-warning-1", "some-warning-2")) + Expect(buildpack).To(Equal(resources.Buildpack{Name: "my-buildpack", GUID: "some-guid", Lifecycle: "good-lifecycle", Stack: "good-stack"})) + }) + + It("Only passes a lifecycle query to the client", func() { + Expect(fakeCloudControllerClient.GetBuildpacksCallCount()).To(Equal(1)) + queries := fakeCloudControllerClient.GetBuildpacksArgsForCall(0) + Expect(queries).To(ConsistOf( + ccv3.Query{ + Key: ccv3.NameFilter, + Values: []string{buildpackName}, + }, + ccv3.Query{ + Key: ccv3.LifecycleFilter, + Values: []string{buildpackLifecycle}, + }, + ccv3.Query{ + Key: ccv3.StackFilter, + Values: []string{buildpackStack}, + }, + )) + }) + }) }) }) @@ -198,10 +277,11 @@ var _ = Describe("Buildpack", func() { warnings Warnings executeErr error labelSelector string + lifecycle string ) JustBeforeEach(func() { - buildpacks, warnings, executeErr = actor.GetBuildpacks(labelSelector) + buildpacks, warnings, executeErr = actor.GetBuildpacks(labelSelector, lifecycle) }) It("calls CloudControllerClient.GetBuildpacks()", func() { @@ -211,10 +291,10 @@ var _ = Describe("Buildpack", func() { When("a label selector is not provided", func() { BeforeEach(func() { labelSelector = "" + lifecycle = "" }) - It("only passes through a OrderBy query to the CloudControllerClient", func() { - positionQuery := ccv3.Query{Key: ccv3.OrderBy, Values: []string{ccv3.PositionOrder}} - Expect(fakeCloudControllerClient.GetBuildpacksArgsForCall(0)).To(ConsistOf(positionQuery)) + It("does not pass a query to the CloudControllerClient", func() { + Expect(fakeCloudControllerClient.GetBuildpacksArgsForCall(0)).To(BeEmpty()) }) }) @@ -265,6 +345,25 @@ var _ = Describe("Buildpack", func() { })) }) }) + + When("lifecycle flag is provided", func() { + BeforeEach(func() { + ccBuildpacks := []resources.Buildpack{ + {Name: "cnb-1", Position: types.NullInt{Value: 1, IsSet: true}, Lifecycle: "cnb"}, + {Name: "cnb-2", Position: types.NullInt{Value: 2, IsSet: true}, Lifecycle: "cnb"}, + } + fakeCloudControllerClient.GetBuildpacksReturns( + ccBuildpacks, + ccv3.Warnings{}, + nil) + lifecycle = "cnb" + }) + + It("passes the lifecycle as a query", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(fakeCloudControllerClient.GetBuildpacksArgsForCall(0)).To(ContainElement(ccv3.Query{Key: ccv3.LifecycleFilter, Values: []string{"cnb"}})) + }) + }) }) Describe("CreateBuildpack", func() { @@ -318,9 +417,10 @@ var _ = Describe("Buildpack", func() { Describe("UpdateBuildpackByNameAndStack", func() { var ( - buildpackName = "my-buildpack" - buildpackStack = "my-stack" - buildpack = resources.Buildpack{ + buildpackName = "my-buildpack" + buildpackStack = "my-stack" + buildpackLifecycle = "cnb" + buildpack = resources.Buildpack{ Stack: "new-stack", } @@ -330,7 +430,7 @@ var _ = Describe("Buildpack", func() { ) JustBeforeEach(func() { - retBuildpack, warnings, executeErr = actor.UpdateBuildpackByNameAndStack(buildpackName, buildpackStack, buildpack) + retBuildpack, warnings, executeErr = actor.UpdateBuildpackByNameAndStackAndLifecycle(buildpackName, buildpackStack, buildpackLifecycle, buildpack) }) When("it is successful", func() { @@ -357,6 +457,10 @@ var _ = Describe("Buildpack", func() { Key: ccv3.StackFilter, Values: []string{buildpackStack}, }, + ccv3.Query{ + Key: ccv3.LifecycleFilter, + Values: []string{buildpackLifecycle}, + }, )) paramBuildpack := fakeCloudControllerClient.UpdateBuildpackArgsForCall(0) @@ -631,18 +735,19 @@ var _ = Describe("Buildpack", func() { }) }) - Describe("DeleteBuildpackByNameAndStack", func() { + Describe("DeleteBuildpackByNameAndStackAndLifecycle", func() { var ( - buildpackName = "buildpack-name" - buildpackStack = "buildpack-stack" - buildpackGUID = "buildpack-guid" - jobURL = "buildpack-delete-job-url" - warnings Warnings - executeErr error + buildpackName = "buildpack-name" + buildpackStack = "buildpack-stack" + buildpackLifecycle = "buildpack-stack" + buildpackGUID = "buildpack-guid" + jobURL = "buildpack-delete-job-url" + warnings Warnings + executeErr error ) JustBeforeEach(func() { - warnings, executeErr = actor.DeleteBuildpackByNameAndStack(buildpackName, buildpackStack) + warnings, executeErr = actor.DeleteBuildpackByNameAndStackAndLifecycle(buildpackName, buildpackStack, buildpackLifecycle) }) When("getting the buildpack fails", func() { @@ -666,6 +771,10 @@ var _ = Describe("Buildpack", func() { Key: ccv3.StackFilter, Values: []string{buildpackStack}, }, + ccv3.Query{ + Key: ccv3.LifecycleFilter, + Values: []string{buildpackLifecycle}, + }, )) }) }) diff --git a/actor/v7action/label.go b/actor/v7action/label.go index 5ed9845e869..7a19f889573 100644 --- a/actor/v7action/label.go +++ b/actor/v7action/label.go @@ -56,8 +56,8 @@ func (actor *Actor) GetStackLabels(stackName string) (map[string]types.NullStrin return actor.extractLabels(resource.Metadata, warnings, err) } -func (actor *Actor) GetBuildpackLabels(buildpackName string, buildpackStack string) (map[string]types.NullString, Warnings, error) { - resource, warnings, err := actor.GetBuildpackByNameAndStack(buildpackName, buildpackStack) +func (actor *Actor) GetBuildpackLabels(buildpackName string, buildpackStack string, buildpackLifecycle string) (map[string]types.NullString, Warnings, error) { + resource, warnings, err := actor.GetBuildpackByNameAndStackAndLifecycle(buildpackName, buildpackStack, buildpackLifecycle) return actor.extractLabels(resource.Metadata, warnings, err) } @@ -81,8 +81,8 @@ func (actor *Actor) UpdateApplicationLabelsByApplicationName(appName string, spa return actor.updateResourceMetadata("app", app.GUID, resources.Metadata{Labels: labels}, warnings) } -func (actor *Actor) UpdateBuildpackLabelsByBuildpackNameAndStack(buildpackName string, stack string, labels map[string]types.NullString) (Warnings, error) { - buildpack, warnings, err := actor.GetBuildpackByNameAndStack(buildpackName, stack) +func (actor *Actor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycle(buildpackName string, stack string, lifecycle string, labels map[string]types.NullString) (Warnings, error) { + buildpack, warnings, err := actor.GetBuildpackByNameAndStackAndLifecycle(buildpackName, stack, lifecycle) if err != nil { return warnings, err } diff --git a/api/cloudcontroller/ccv3/query.go b/api/cloudcontroller/ccv3/query.go index 6e1069aea3f..6c0cec48b37 100644 --- a/api/cloudcontroller/ccv3/query.go +++ b/api/cloudcontroller/ccv3/query.go @@ -17,6 +17,8 @@ const ( GUIDFilter QueryKey = "guids" // LabelSelectorFilter is a query parameter for listing objects by label LabelSelectorFilter QueryKey = "label_selector" + // LifecycleFilter is a query parameter for listing buildpacks by lifecycle + LifecycleFilter QueryKey = "lifecycle" // NameFilter is a query parameter for listing objects by name. NameFilter QueryKey = "names" // NoRouteFilter is a query parameter for skipping route creation and unmapping existing routes. diff --git a/api/cloudcontroller/ccversion/minimum_version.go b/api/cloudcontroller/ccversion/minimum_version.go index 94e07ea7bfa..c82da7ae60e 100644 --- a/api/cloudcontroller/ccversion/minimum_version.go +++ b/api/cloudcontroller/ccversion/minimum_version.go @@ -13,5 +13,7 @@ const ( MinVersionLogRateLimitingV3 = "3.125.0" MinVersionPerRouteOpts = "3.183.0" + MinVersionBuildpackLifecycleQuery = "3.194.0" + MinVersionCanarySteps = "3.189.0" ) diff --git a/command/translatableerror/buildpack_not_found_error.go b/command/translatableerror/buildpack_not_found_error.go index 1f6e666fb21..0b562847e6c 100644 --- a/command/translatableerror/buildpack_not_found_error.go +++ b/command/translatableerror/buildpack_not_found_error.go @@ -1,20 +1,28 @@ package translatableerror +import "fmt" + type BuildpackNotFoundError struct { BuildpackName string StackName string + Lifecycle string } func (e BuildpackNotFoundError) Error() string { - if len(e.StackName) == 0 { - return "Buildpack '{{.BuildpackName}}' not found" + message := fmt.Sprintf("Buildpack '%s'", e.BuildpackName) + if len(e.StackName) != 0 { + message = fmt.Sprintf("%s with stack '%s'", message, e.StackName) + } + if len(e.Lifecycle) != 0 { + message = fmt.Sprintf("%s with lifecycle '%s'", message, e.Lifecycle) } - return "Buildpack '{{.BuildpackName}}' with stack '{{.StackName}}' not found" + return message + " not found" } func (e BuildpackNotFoundError) Translate(translate func(string, ...interface{}) string) string { return translate(e.Error(), map[string]interface{}{ "BuildpackName": e.BuildpackName, "StackName": e.StackName, + "Lifecycle": e.Lifecycle, }) } diff --git a/command/translatableerror/multiple_buildpacks_found_error.go b/command/translatableerror/multiple_buildpacks_found_error.go index 724b94543e7..c1785a6eb08 100644 --- a/command/translatableerror/multiple_buildpacks_found_error.go +++ b/command/translatableerror/multiple_buildpacks_found_error.go @@ -5,7 +5,7 @@ type MultipleBuildpacksFoundError struct { } func (MultipleBuildpacksFoundError) Error() string { - return "Multiple buildpacks named {{.BuildpackName}} found. Specify a stack name by using a '-s' flag." + return "Multiple buildpacks named {{.BuildpackName}} found. Specify a stack name by using a '-s' flag and/or lifecycle using a '-l' flag." } func (e MultipleBuildpacksFoundError) Translate(translate func(string, ...interface{}) string) string { diff --git a/command/v7/actor.go b/command/v7/actor.go index 3e79637fac9..d573454db89 100644 --- a/command/v7/actor.go +++ b/command/v7/actor.go @@ -58,7 +58,7 @@ type Actor interface { CreateUser(username string, password string, origin string) (resources.User, v7action.Warnings, error) CreateUserProvidedServiceInstance(instance resources.ServiceInstance) (v7action.Warnings, error) DeleteApplicationByNameAndSpace(name, spaceGUID string, deleteRoutes bool) (v7action.Warnings, error) - DeleteBuildpackByNameAndStack(buildpackName string, buildpackStack string) (v7action.Warnings, error) + DeleteBuildpackByNameAndStackAndLifecycle(buildpackName string, buildpackStack string, buildpackLifecycle string) (v7action.Warnings, error) DeleteDomain(domain resources.Domain) (v7action.Warnings, error) DeleteInstanceByApplicationNameSpaceProcessTypeAndIndex(appName string, spaceGUID string, processType string, instanceIndex int) (v7action.Warnings, error) DeleteOrgRole(roleType constant.RoleType, orgGUID string, userNameOrGUID string, userOrigin string, isClient bool) (v7action.Warnings, error) @@ -99,8 +99,8 @@ type Actor interface { GetApplicationRoutes(appGUID string) ([]resources.Route, v7action.Warnings, error) GetApplicationTasks(appName string, sortOrder v7action.SortOrder) ([]resources.Task, v7action.Warnings, error) GetApplicationsByNamesAndSpace(appNames []string, spaceGUID string) ([]resources.Application, v7action.Warnings, error) - GetBuildpackLabels(buildpackName string, buildpackStack string) (map[string]types.NullString, v7action.Warnings, error) - GetBuildpacks(labelSelector string) ([]resources.Buildpack, v7action.Warnings, error) + GetBuildpackLabels(buildpackName string, buildpackStack string, buildpackLifecycle string) (map[string]types.NullString, v7action.Warnings, error) + GetBuildpacks(labelSelector string, lifecycle string) ([]resources.Buildpack, v7action.Warnings, error) GetCurrentUser() (configv3.User, error) GetDefaultDomain(orgGUID string) (resources.Domain, v7action.Warnings, error) GetDetailedAppSummary(appName string, spaceGUID string, withObfuscatedValues bool) (v7action.DetailedApplicationSummary, v7action.Warnings, error) @@ -237,8 +237,8 @@ type Actor interface { UpdateAppFeature(app resources.Application, enabled bool, featureName string) (v7action.Warnings, error) UpdateApplication(app resources.Application) (resources.Application, v7action.Warnings, error) UpdateApplicationLabelsByApplicationName(string, string, map[string]types.NullString) (v7action.Warnings, error) - UpdateBuildpackByNameAndStack(buildpackName string, buildpackStack string, buildpack resources.Buildpack) (resources.Buildpack, v7action.Warnings, error) - UpdateBuildpackLabelsByBuildpackNameAndStack(string, string, map[string]types.NullString) (v7action.Warnings, error) + UpdateBuildpackByNameAndStackAndLifecycle(buildpackName string, buildpackStack string, buildpackLifecycle string, buildpack resources.Buildpack) (resources.Buildpack, v7action.Warnings, error) + UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycle(string, string, string, map[string]types.NullString) (v7action.Warnings, error) UpdateDestination(string, string, string) (v7action.Warnings, error) UpdateDomainLabelsByDomainName(string, map[string]types.NullString) (v7action.Warnings, error) UpdateManagedServiceInstance(params v7action.UpdateManagedServiceInstanceParams) (chan v7action.PollJobEvent, v7action.Warnings, error) diff --git a/command/v7/buildpacks_command.go b/command/v7/buildpacks_command.go index 0aeb3a0a010..7ab3e670fc8 100644 --- a/command/v7/buildpacks_command.go +++ b/command/v7/buildpacks_command.go @@ -3,6 +3,8 @@ package v7 import ( "strconv" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" + "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/resources" "code.cloudfoundry.org/cli/util/ui" ) @@ -10,9 +12,10 @@ import ( type BuildpacksCommand struct { BaseCommand - usage interface{} `usage:"CF_NAME buildpacks [--labels SELECTOR]\n\nEXAMPLES:\n CF_NAME buildpacks\n CF_NAME buildpacks --labels 'environment in (production,staging),tier in (backend)'\n CF_NAME buildpacks --labels 'env=dev,!chargeback-code,tier in (backend,worker)'"` + usage interface{} `usage:"CF_NAME buildpacks [--labels SELECTOR] [--lifecycle buildpack|cnb]\n\nEXAMPLES:\n CF_NAME buildpacks\n CF_NAME buildpacks --labels 'environment in (production,staging),tier in (backend)'\n CF_NAME buildpacks --labels 'env=dev,!chargeback-code,tier in (backend,worker)'\n CF_NAME buildpacks --lifecycle cnb"` relatedCommands interface{} `related_commands:"create-buildpack, delete-buildpack, rename-buildpack, update-buildpack"` Labels string `long:"labels" description:"Selector to filter buildpacks by labels"` + Lifecycle string `long:"lifecycle" description:"Filter buildpacks by lifecycle ('buildpack' or 'cnb')"` } func (cmd BuildpacksCommand) Execute(args []string) error { @@ -26,12 +29,19 @@ func (cmd BuildpacksCommand) Execute(args []string) error { return err } + if cmd.Lifecycle != "" { + err = command.MinimumCCAPIVersionCheck(cmd.Config.APIVersion(), ccversion.MinVersionBuildpackLifecycleQuery, "--lifecycle") + if err != nil { + return err + } + } + cmd.UI.DisplayTextWithFlavor("Getting buildpacks as {{.Username}}...", map[string]interface{}{ "Username": user.Name, }) cmd.UI.DisplayNewline() - buildpacks, warnings, err := cmd.Actor.GetBuildpacks(cmd.Labels) + buildpacks, warnings, err := cmd.Actor.GetBuildpacks(cmd.Labels, cmd.Lifecycle) cmd.UI.DisplayWarnings(warnings) if err != nil { return err @@ -48,8 +58,9 @@ func (cmd BuildpacksCommand) Execute(args []string) error { func (cmd BuildpacksCommand) displayTable(buildpacks []resources.Buildpack) { if len(buildpacks) > 0 { var keyValueTable = [][]string{ - {"position", "name", "stack", "enabled", "locked", "state", "filename"}, + {"position", "name", "stack", "enabled", "locked", "state", "filename", "lifecycle"}, } + for _, buildpack := range buildpacks { keyValueTable = append(keyValueTable, []string{ strconv.Itoa(buildpack.Position.Value), @@ -59,6 +70,7 @@ func (cmd BuildpacksCommand) displayTable(buildpacks []resources.Buildpack) { strconv.FormatBool(buildpack.Locked.Value), buildpack.State, buildpack.Filename, + buildpack.Lifecycle, }) } diff --git a/command/v7/buildpacks_command_test.go b/command/v7/buildpacks_command_test.go index 0cb54667243..a2e879e429a 100644 --- a/command/v7/buildpacks_command_test.go +++ b/command/v7/buildpacks_command_test.go @@ -10,6 +10,7 @@ import ( "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant" "code.cloudfoundry.org/cli/command/commandfakes" + "code.cloudfoundry.org/cli/command/translatableerror" . "code.cloudfoundry.org/cli/command/v7" "code.cloudfoundry.org/cli/command/v7/v7fakes" "code.cloudfoundry.org/cli/util/configv3" @@ -35,6 +36,7 @@ var _ = Describe("buildpacks Command", func() { BeforeEach(func() { testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) fakeConfig = new(commandfakes.FakeConfig) + fakeConfig.APIVersionReturns("4.0.0") fakeSharedActor = new(commandfakes.FakeSharedActor) fakeActor = new(v7fakes.FakeActor) args = nil @@ -87,11 +89,32 @@ var _ = Describe("buildpacks Command", func() { }) It("passes the label selector to the actor", func() { - labelSelector := fakeActor.GetBuildpacksArgsForCall(0) + labelSelector, _ := fakeActor.GetBuildpacksArgsForCall(0) Expect(labelSelector).To(Equal("some-label-selector")) }) }) + When("the --lifecycle flag is used", func() { + BeforeEach(func() { + cmd.Lifecycle = "cnb" + }) + + It("passes the lifecycle to the actor", func() { + _, lifecycle := fakeActor.GetBuildpacksArgsForCall(0) + Expect(lifecycle).To(Equal("cnb")) + }) + It("fails when the cc version is below the minimum", func() { + fakeConfig.APIVersionReturns("3.193.0") + executeErr = cmd.Execute(nil) + + Expect(executeErr).To(MatchError(translatableerror.MinimumCFAPIVersionNotMetError{ + Command: "--lifecycle", + CurrentVersion: "3.193.0", + MinimumVersion: "3.194.0", + })) + }) + }) + When("getting buildpacks fails", func() { BeforeEach(func() { fakeActor.GetBuildpacksReturns(nil, v7action.Warnings{"some-warning-1", "some-warning-2"}, @@ -111,23 +134,35 @@ var _ = Describe("buildpacks Command", func() { BeforeEach(func() { buildpacks := []resources.Buildpack{ { - Name: "buildpack-1", - Position: types.NullInt{Value: 1, IsSet: true}, - Enabled: types.NullBool{Value: true, IsSet: true}, - Locked: types.NullBool{Value: false, IsSet: true}, - State: constant.BuildpackReady, - Filename: "buildpack-1.file", - Stack: "buildpack-1-stack", + Name: "buildpack-1", + Position: types.NullInt{Value: 1, IsSet: true}, + Enabled: types.NullBool{Value: true, IsSet: true}, + Locked: types.NullBool{Value: false, IsSet: true}, + State: constant.BuildpackReady, + Filename: "buildpack-1.file", + Stack: "buildpack-1-stack", + Lifecycle: "buildpack", }, { - Name: "buildpack-2", - Position: types.NullInt{Value: 2, IsSet: true}, - Enabled: types.NullBool{Value: false, IsSet: true}, - Locked: types.NullBool{Value: true, IsSet: true}, - State: constant.BuildpackAwaitingUpload, - Filename: "buildpack-2.file", - Stack: "", + Name: "buildpack-2", + Position: types.NullInt{Value: 2, IsSet: true}, + Enabled: types.NullBool{Value: false, IsSet: true}, + Locked: types.NullBool{Value: true, IsSet: true}, + State: constant.BuildpackAwaitingUpload, + Filename: "buildpack-2.file", + Stack: "", + Lifecycle: "buildpack", + }, + { + Name: "cnb-1", + Position: types.NullInt{Value: 1, IsSet: true}, + Enabled: types.NullBool{Value: true, IsSet: true}, + Locked: types.NullBool{Value: false, IsSet: true}, + State: constant.BuildpackReady, + Filename: "cnb-1.cnb", + Stack: "cnb-1-stack", + Lifecycle: "cnb", }, } fakeActor.GetBuildpacksReturns(buildpacks, v7action.Warnings{"some-warning-1", "some-warning-2"}, nil) @@ -136,9 +171,10 @@ var _ = Describe("buildpacks Command", func() { Expect(executeErr).NotTo(HaveOccurred()) Expect(testUI.Err).To(Say("some-warning-1")) Expect(testUI.Err).To(Say("some-warning-2")) - Expect(testUI.Out).To(Say(`position\s+name\s+stack\s+enabled\s+locked\s+state\s+filename`)) - Expect(testUI.Out).To(Say(`1\s+buildpack-1\s+buildpack-1-stack\s+true\s+false\s+READY\s+buildpack-1.file`)) - Expect(testUI.Out).To(Say(`2\s+buildpack-2\s+false\s+true\s+AWAITING_UPLOAD\s+buildpack-2.file`)) + Expect(testUI.Out).To(Say(`position\s+name\s+stack\s+enabled\s+locked\s+state\s+filename\s+lifecycle`)) + Expect(testUI.Out).To(Say(`1\s+buildpack-1\s+buildpack-1-stack\s+true\s+false\s+READY\s+buildpack-1.file\s+buildpack`)) + Expect(testUI.Out).To(Say(`2\s+buildpack-2\s+false\s+true\s+AWAITING_UPLOAD\s+buildpack-2.file\s+buildpack`)) + Expect(testUI.Out).To(Say(`1\s+cnb-1\s+cnb-1-stack\s+true\s+false\s+READY\s+cnb-1.cnb\s+cnb`)) }) }) When("there are no buildpacks", func() { diff --git a/command/v7/create_buildpack_command.go b/command/v7/create_buildpack_command.go index 9b64dfbab36..815a1cd9cc2 100644 --- a/command/v7/create_buildpack_command.go +++ b/command/v7/create_buildpack_command.go @@ -6,6 +6,7 @@ import ( "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/flag" "code.cloudfoundry.org/cli/command/translatableerror" @@ -18,9 +19,10 @@ type CreateBuildpackCommand struct { BaseCommand RequiredArgs flag.CreateBuildpackArgs `positional-args:"Yes"` - usage interface{} `usage:"CF_NAME create-buildpack BUILDPACK PATH POSITION [--disable]\n\nTIP:\n Path should be a zip file, a url to a zip file, or a local directory. Position is a positive integer, sets priority, and is sorted from lowest to highest."` + usage interface{} `usage:"CF_NAME create-buildpack BUILDPACK PATH POSITION [--disable] [--lifecycle buildpack|cnb]\n\nTIP:\n When using the 'buildpack' lifecycle type, Path should be a zip file, a url to a zip file, or a local directory. When using the 'cnb' lifecycle, Path should be a cnb file or gzipped oci image. Position is a positive integer, sets priority, and is sorted from lowest to highest."` relatedCommands interface{} `related_commands:"buildpacks, push"` Disable bool `long:"disable" description:"Disable the buildpack from being used for staging"` + Lifecycle string `long:"lifecycle" short:"l" description:"Lifecycle that the buildpack will use ('buildpack' or 'cnb')"` ProgressBar v7action.SimpleProgressBar } @@ -41,6 +43,13 @@ func (cmd CreateBuildpackCommand) Execute(args []string) error { return err } + if cmd.Lifecycle != "" { + err = command.MinimumCCAPIVersionCheck(cmd.Config.APIVersion(), ccversion.MinVersionBuildpackLifecycleQuery, "--lifecycle") + if err != nil { + return err + } + } + cmd.UI.DisplayTextWithFlavor("Creating buildpack {{.BuildpackName}} as {{.Username}}...", map[string]interface{}{ "Username": user.Name, "BuildpackName": cmd.RequiredArgs.Buildpack, @@ -59,9 +68,10 @@ func (cmd CreateBuildpackCommand) Execute(args []string) error { } createdBuildpack, warnings, err := cmd.Actor.CreateBuildpack(resources.Buildpack{ - Name: cmd.RequiredArgs.Buildpack, - Position: types.NullInt{IsSet: true, Value: cmd.RequiredArgs.Position}, - Enabled: types.NullBool{IsSet: true, Value: !cmd.Disable}, + Name: cmd.RequiredArgs.Buildpack, + Position: types.NullInt{IsSet: true, Value: cmd.RequiredArgs.Position}, + Enabled: types.NullBool{IsSet: true, Value: !cmd.Disable}, + Lifecycle: cmd.Lifecycle, }) cmd.UI.DisplayWarnings(warnings) if err != nil { diff --git a/command/v7/create_buildpack_command_test.go b/command/v7/create_buildpack_command_test.go index e8d9556d804..06a31463fb5 100644 --- a/command/v7/create_buildpack_command_test.go +++ b/command/v7/create_buildpack_command_test.go @@ -39,6 +39,7 @@ var _ = Describe("create buildpack Command", func() { BeforeEach(func() { testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer()) fakeConfig = new(commandfakes.FakeConfig) + fakeConfig.APIVersionReturns("4.0.0") fakeSharedActor = new(commandfakes.FakeSharedActor) fakeActor = new(v7fakes.FakeActor) args = nil @@ -82,6 +83,23 @@ var _ = Describe("create buildpack Command", func() { }) }) + When("--lifecyle is provided", func() { + JustBeforeEach(func() { + cmd.Lifecycle = "some-lifecycle" + fakeConfig.APIVersionReturns("3.193.0") + }) + It("fails when the cc version is below the minimum", func() { + executeErr = cmd.Execute(nil) + + Expect(executeErr).To(MatchError(translatableerror.MinimumCFAPIVersionNotMetError{ + Command: "--lifecycle", + CurrentVersion: "3.193.0", + MinimumVersion: "3.194.0", + })) + }) + + }) + When("the environment is setup correctly", func() { BeforeEach(func() { fakeActor.GetCurrentUserReturns(configv3.User{Name: "the-user"}, nil) @@ -92,6 +110,17 @@ var _ = Describe("create buildpack Command", func() { Expect(testUI.Out).To(Say(`Creating buildpack %s as the-user\.\.\.`, buildpackName)) }) + When("passing in buildpack lifecycle", func() { + BeforeEach(func() { + cmd.Lifecycle = "cnb" + }) + + It("sets the correct lifecycle in the buildpack resource", func() { + Expect(fakeActor.CreateBuildpackCallCount()).To(Equal(1)) + Expect(fakeActor.CreateBuildpackArgsForCall(0).Lifecycle).To(Equal("cnb")) + }) + }) + When("preparing the buildpack bits fails", func() { BeforeEach(func() { fakeActor.PrepareBuildpackBitsReturns("some/invalid/path", errors.New("some-prepare-bp-error")) diff --git a/command/v7/delete_buildpack_command.go b/command/v7/delete_buildpack_command.go index c0d0e5f5717..125e13d9637 100644 --- a/command/v7/delete_buildpack_command.go +++ b/command/v7/delete_buildpack_command.go @@ -2,6 +2,8 @@ package v7 import ( "code.cloudfoundry.org/cli/actor/actionerror" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" + "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/flag" ) @@ -9,10 +11,11 @@ type DeleteBuildpackCommand struct { BaseCommand RequiredArgs flag.BuildpackName `positional-args:"yes"` - usage interface{} `usage:"CF_NAME delete-buildpack BUILDPACK [-f] [-s STACK]"` + usage interface{} `usage:"CF_NAME delete-buildpack BUILDPACK [-f] [-s STACK] [-l LIFECYCLE]"` relatedCommands interface{} `related_commands:"buildpacks"` Force bool `long:"force" short:"f" description:"Force deletion without confirmation"` Stack string `long:"stack" short:"s" description:"Specify stack to disambiguate buildpacks with the same name. Required when buildpack name is ambiguous"` + Lifecycle string `long:"lifecycle" short:"l" description:"Specify lifecycle to disambiguate buildpacks with the same name. Required when buildpack name is ambiguous"` } func (cmd DeleteBuildpackCommand) Execute(args []string) error { @@ -21,6 +24,13 @@ func (cmd DeleteBuildpackCommand) Execute(args []string) error { return err } + if cmd.Lifecycle != "" { + err = command.MinimumCCAPIVersionCheck(cmd.Config.APIVersion(), ccversion.MinVersionBuildpackLifecycleQuery, "--lifecycle") + if err != nil { + return err + } + } + if !cmd.Force { response, uiErr := cmd.UI.DisplayBoolPrompt(false, "Really delete the {{.ModelType}} {{.ModelName}}?", map[string]interface{}{ "ModelType": "buildpack", @@ -36,33 +46,14 @@ func (cmd DeleteBuildpackCommand) Execute(args []string) error { } } - if cmd.Stack == "" { - cmd.UI.DisplayTextWithFlavor("Deleting buildpack {{.BuildpackName}}...", map[string]interface{}{ - "BuildpackName": cmd.RequiredArgs.Buildpack, - }) - - } else { - cmd.UI.DisplayTextWithFlavor("Deleting buildpack {{.BuildpackName}} with stack {{.Stack}}...", map[string]interface{}{ - "BuildpackName": cmd.RequiredArgs.Buildpack, - "Stack": cmd.Stack, - }) - } - warnings, err := cmd.Actor.DeleteBuildpackByNameAndStack(cmd.RequiredArgs.Buildpack, cmd.Stack) + cmd.displayBuildpackDeletingMessage() + warnings, err := cmd.Actor.DeleteBuildpackByNameAndStackAndLifecycle(cmd.RequiredArgs.Buildpack, cmd.Stack, cmd.Lifecycle) cmd.UI.DisplayWarnings(warnings) if err != nil { switch err.(type) { case actionerror.BuildpackNotFoundError: - if cmd.Stack == "" { - cmd.UI.DisplayWarning("Buildpack '{{.BuildpackName}}' does not exist.", map[string]interface{}{ - "BuildpackName": cmd.RequiredArgs.Buildpack, - }) - } else { - cmd.UI.DisplayWarning("Buildpack '{{.BuildpackName}}' with stack '{{.Stack}}' not found.", map[string]interface{}{ - "BuildpackName": cmd.RequiredArgs.Buildpack, - "Stack": cmd.Stack, - }) - } + cmd.displayBuildpackNotFoundWarning() default: return err } @@ -72,3 +63,42 @@ func (cmd DeleteBuildpackCommand) Execute(args []string) error { return nil } + +func (cmd DeleteBuildpackCommand) displayBuildpackNotFoundWarning() { + warning := "Buildpack '{{.BuildpackName}}'" + if cmd.Stack != "" { + warning += " with stack '{{.Stack}}'" + } + + if cmd.Lifecycle != "" { + warning += " with lifecycle '{{.Lifecycle}}'" + } + + if cmd.Stack != "" && cmd.Lifecycle != "" { + warning += " does not exist." + } else { + warning += " not found." + } + cmd.UI.DisplayWarning(warning, map[string]interface{}{ + "BuildpackName": cmd.RequiredArgs.Buildpack, + "Stack": cmd.Stack, + "Lifecycle": cmd.Lifecycle, + }) +} + +func (cmd DeleteBuildpackCommand) displayBuildpackDeletingMessage() { + message := "Deleting buildpack {{.BuildpackName}}" + if cmd.Stack != "" { + message += " with stack {{.Stack}}" + } + + if cmd.Lifecycle != "" { + message += " with lifecycle {{.Lifecycle}}" + } + + cmd.UI.DisplayTextWithFlavor(message+"...", map[string]interface{}{ + "BuildpackName": cmd.RequiredArgs.Buildpack, + "Stack": cmd.Stack, + "Lifecycle": cmd.Lifecycle, + }) +} diff --git a/command/v7/delete_buildpack_command_test.go b/command/v7/delete_buildpack_command_test.go index ccd53b95b5d..a26d614eeba 100644 --- a/command/v7/delete_buildpack_command_test.go +++ b/command/v7/delete_buildpack_command_test.go @@ -6,6 +6,7 @@ import ( "code.cloudfoundry.org/cli/actor/actionerror" "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/command/commandfakes" + "code.cloudfoundry.org/cli/command/translatableerror" . "code.cloudfoundry.org/cli/command/v7" "code.cloudfoundry.org/cli/command/v7/v7fakes" "code.cloudfoundry.org/cli/util/ui" @@ -32,6 +33,7 @@ var _ = Describe("delete-buildpack Command", func() { input = NewBuffer() fakeActor = new(v7fakes.FakeActor) fakeConfig = new(commandfakes.FakeConfig) + fakeConfig.APIVersionReturns("4.0.0") fakeSharedActor = new(commandfakes.FakeSharedActor) testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer()) @@ -50,6 +52,23 @@ var _ = Describe("delete-buildpack Command", func() { cmd.Force = true }) + When("--lifecyle is provided", func() { + JustBeforeEach(func() { + cmd.Lifecycle = "some-lifecycle" + fakeConfig.APIVersionReturns("3.193.0") + }) + It("fails when the cc version is below the minimum", func() { + executeErr = cmd.Execute(nil) + + Expect(executeErr).To(MatchError(translatableerror.MinimumCFAPIVersionNotMetError{ + Command: "--lifecycle", + CurrentVersion: "3.193.0", + MinimumVersion: "3.194.0", + })) + }) + + }) + When("checking target fails", func() { BeforeEach(func() { fakeSharedActor.CheckTargetReturns(actionerror.NotLoggedInError{BinaryName: binaryName}) @@ -69,7 +88,7 @@ var _ = Describe("delete-buildpack Command", func() { When("the DeleteBuildpack actor completes successfully", func() { BeforeEach(func() { - fakeActor.DeleteBuildpackByNameAndStackReturns(nil, nil) + fakeActor.DeleteBuildpackByNameAndStackAndLifecycleReturns(nil, nil) }) JustBeforeEach(func() { executeErr = cmd.Execute(nil) @@ -137,12 +156,9 @@ var _ = Describe("delete-buildpack Command", func() { }) When("the buildpack does not exist", func() { - BeforeEach(func() { - fakeActor.DeleteBuildpackByNameAndStackReturns(v7action.Warnings{"a-warning"}, actionerror.BuildpackNotFoundError{BuildpackName: buildpackName, StackName: "stack!"}) - }) - When("deleting with a stack", func() { BeforeEach(func() { + fakeActor.DeleteBuildpackByNameAndStackAndLifecycleReturns(v7action.Warnings{"a-warning"}, actionerror.BuildpackNotFoundError{BuildpackName: buildpackName, StackName: "stack!"}) cmd.Stack = "stack!" executeErr = cmd.Execute(nil) }) @@ -153,34 +169,65 @@ var _ = Describe("delete-buildpack Command", func() { }) }) - When("deleting without a stack", func() { + When("deleting with a lifecycle", func() { + BeforeEach(func() { + fakeActor.DeleteBuildpackByNameAndStackAndLifecycleReturns(v7action.Warnings{"a-warning"}, actionerror.BuildpackNotFoundError{BuildpackName: buildpackName, Lifecycle: "cnb"}) + cmd.Lifecycle = "cnb" + executeErr = cmd.Execute(nil) + }) + + It("prints warnings and helpful error message (that includes the lifecycle name)", func() { + Expect(testUI.Err).To(Say("a-warning")) + Expect(testUI.Err).To(Say(`Buildpack 'the-buildpack' with lifecycle 'cnb' not found\.`)) + }) + + }) + When("deleting with a stack and lifecycle", func() { + BeforeEach(func() { + fakeActor.DeleteBuildpackByNameAndStackAndLifecycleReturns(v7action.Warnings{"a-warning"}, actionerror.BuildpackNotFoundError{BuildpackName: buildpackName, StackName: "stack!", Lifecycle: "cnb"}) + cmd.Stack = "stack!" + cmd.Lifecycle = "cnb" + executeErr = cmd.Execute(nil) + }) + + It("prints warnings and helpful error message (that includes both names)", func() { + Expect(testUI.Err).To(Say("a-warning")) + Expect(testUI.Err).To(Say(`Buildpack 'the-buildpack' with stack 'stack!' with lifecycle 'cnb' does not exist\.`)) + }) + + }) + When("deleting without a stack or lifecycle", func() { BeforeEach(func() { + fakeActor.DeleteBuildpackByNameAndStackAndLifecycleReturns(v7action.Warnings{"a-warning"}, actionerror.BuildpackNotFoundError{BuildpackName: buildpackName}) cmd.Stack = "" + cmd.Lifecycle = "" executeErr = cmd.Execute(nil) }) It("prints warnings and helpful error message", func() { Expect(testUI.Err).To(Say("a-warning")) - Expect(testUI.Err).To(Say(`Buildpack 'the-buildpack' does not exist\.`)) + Expect(testUI.Err).To(Say(`Buildpack 'the-buildpack' not found\.`)) }) }) }) It("delegates to the actor", func() { cmd.Stack = "the-stack" - fakeActor.DeleteBuildpackByNameAndStackReturns(nil, nil) + cmd.Lifecycle = "cnb" + fakeActor.DeleteBuildpackByNameAndStackAndLifecycleReturns(nil, nil) executeErr = cmd.Execute(nil) Expect(executeErr).ToNot(HaveOccurred()) - actualBuildpack, actualStack := fakeActor.DeleteBuildpackByNameAndStackArgsForCall(0) + actualBuildpack, actualStack, actualLifecycle := fakeActor.DeleteBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(actualBuildpack).To(Equal("the-buildpack")) Expect(actualStack).To(Equal("the-stack")) + Expect(actualLifecycle).To(Equal("cnb")) }) It("prints warnings", func() { cmd.Stack = "a-stack" - fakeActor.DeleteBuildpackByNameAndStackReturns(v7action.Warnings{"a-warning"}, nil) + fakeActor.DeleteBuildpackByNameAndStackAndLifecycleReturns(v7action.Warnings{"a-warning"}, nil) executeErr = cmd.Execute(nil) @@ -191,7 +238,7 @@ var _ = Describe("delete-buildpack Command", func() { It("returns error from the actor and prints the errors", func() { cmd.Stack = "a-stack" - fakeActor.DeleteBuildpackByNameAndStackReturns(v7action.Warnings{"a-warning"}, errors.New("some-error")) + fakeActor.DeleteBuildpackByNameAndStackAndLifecycleReturns(v7action.Warnings{"a-warning"}, errors.New("some-error")) executeErr = cmd.Execute(nil) diff --git a/command/v7/label_updater.go b/command/v7/label_updater.go index ce48fcd2854..e7b8a7b4640 100644 --- a/command/v7/label_updater.go +++ b/command/v7/label_updater.go @@ -17,7 +17,7 @@ import ( type SetLabelActor interface { GetCurrentUser() (configv3.User, error) UpdateApplicationLabelsByApplicationName(string, string, map[string]types.NullString) (v7action.Warnings, error) - UpdateBuildpackLabelsByBuildpackNameAndStack(string, string, map[string]types.NullString) (v7action.Warnings, error) + UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycle(string, string, string, map[string]types.NullString) (v7action.Warnings, error) UpdateDomainLabelsByDomainName(string, map[string]types.NullString) (v7action.Warnings, error) UpdateOrganizationLabelsByOrganizationName(string, map[string]types.NullString) (v7action.Warnings, error) UpdateRouteLabels(string, string, map[string]types.NullString) (v7action.Warnings, error) @@ -37,11 +37,12 @@ const ( ) type TargetResource struct { - ResourceType string - ResourceName string - BuildpackStack string - ServiceBroker string - ServiceOffering string + ResourceType string + ResourceName string + BuildpackStack string + BuildpackLifecycle string + ServiceBroker string + ServiceOffering string } type LabelUpdater struct { @@ -83,8 +84,8 @@ func (cmd *LabelUpdater) Execute(targetResource TargetResource, labels map[strin cmd.displayMessageWithOrgAndSpace() warnings, err = cmd.Actor.UpdateApplicationLabelsByApplicationName(cmd.targetResource.ResourceName, cmd.Config.TargetedSpace().GUID, cmd.labels) case Buildpack: - cmd.displayMessageWithStack() - warnings, err = cmd.Actor.UpdateBuildpackLabelsByBuildpackNameAndStack(cmd.targetResource.ResourceName, cmd.targetResource.BuildpackStack, cmd.labels) + cmd.displayMessageWithStackAndLifecycle() + warnings, err = cmd.Actor.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycle(cmd.targetResource.ResourceName, cmd.targetResource.BuildpackStack, cmd.targetResource.BuildpackLifecycle, cmd.labels) case Domain: cmd.displayMessageDefault() warnings, err = cmd.Actor.UpdateDomainLabelsByDomainName(cmd.targetResource.ResourceName, cmd.labels) @@ -189,17 +190,23 @@ func (cmd *LabelUpdater) displayMessageWithOrgAndSpace() { }) } -func (cmd *LabelUpdater) displayMessageWithStack() { - var template string - if cmd.targetResource.BuildpackStack == "" { - template = actionForResourceString(string(cmd.Action), cmd.targetResource.ResourceType) + " {{.ResourceName}} as {{.User}}..." - } else { - template = actionForResourceString(string(cmd.Action), cmd.targetResource.ResourceType) + " {{.ResourceName}} with stack {{.StackName}} as {{.User}}..." +func (cmd *LabelUpdater) displayMessageWithStackAndLifecycle() { + template := actionForResourceString(string(cmd.Action), cmd.targetResource.ResourceType) + " {{.ResourceName}}" + + if cmd.targetResource.BuildpackStack != "" { + template += " with stack {{.StackName}}" + } + + if cmd.targetResource.BuildpackLifecycle != "" { + template += " with lifecycle {{.Lifecycle}}" } + template += " as {{.User}}..." + cmd.UI.DisplayTextWithFlavor(template, map[string]interface{}{ "ResourceName": cmd.targetResource.ResourceName, "StackName": cmd.targetResource.BuildpackStack, + "Lifecycle": cmd.targetResource.BuildpackLifecycle, "User": cmd.Username, }) } diff --git a/command/v7/label_updater_test.go b/command/v7/label_updater_test.go index 94843b12d5a..3386ce51aec 100644 --- a/command/v7/label_updater_test.go +++ b/command/v7/label_updater_test.go @@ -348,7 +348,7 @@ var _ = Describe("LabelUpdater", func() { } labels = expectedMap - fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackReturns( + fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturns( v7action.Warnings([]string{"some-warning-1", "some-warning-2"}), nil, ) @@ -365,10 +365,11 @@ var _ = Describe("LabelUpdater", func() { }) It("passes the right parameters", func() { - Expect(fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackCallCount()).To(Equal(1)) - name, stack, labels := fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackArgsForCall(0) + Expect(fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleCallCount()).To(Equal(1)) + name, stack, lifecycle, labels := fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall(0) Expect(name).To(Equal(resourceName), "failed to pass buildpack name") Expect(stack).To(Equal("globinski"), "failed to pass stack name") + Expect(lifecycle).To(Equal(""), "failed to pass lifecycle name") Expect(labels).To(BeEquivalentTo(expectedMap)) }) @@ -379,12 +380,34 @@ var _ = Describe("LabelUpdater", func() { }) }) - When("the stack is not specified", func() { + When("the stack and lifecycle are not specified", func() { It("passes the right parameters", func() { - Expect(fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackCallCount()).To(Equal(1)) - name, stack, labels := fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackArgsForCall(0) + Expect(fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleCallCount()).To(Equal(1)) + name, stack, lifecycle, labels := fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall(0) Expect(name).To(Equal(resourceName), "failed to pass buildpack name") Expect(stack).To(Equal(""), "failed to pass stack name") + Expect(lifecycle).To(Equal(""), "failed to pass lifecycle name") + Expect(labels).To(BeEquivalentTo(expectedMap)) + }) + + It("prints all warnings and does not error ", func() { + Expect(executeErr).ToNot(HaveOccurred()) + Expect(testUI.Err).To(Say("some-warning-1")) + Expect(testUI.Err).To(Say("some-warning-2")) + }) + }) + + When("the lifecycle is specified", func() { + BeforeEach(func() { + targetResource.BuildpackLifecycle = "cnb" + }) + + It("passes the right parameters", func() { + Expect(fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleCallCount()).To(Equal(1)) + name, stack, lifecycle, labels := fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall(0) + Expect(name).To(Equal(resourceName), "failed to pass buildpack name") + Expect(stack).To(Equal(""), "failed to pass stack name") + Expect(lifecycle).To(Equal("cnb"), "failed to pass lifecycle name") Expect(labels).To(BeEquivalentTo(expectedMap)) }) @@ -399,9 +422,10 @@ var _ = Describe("LabelUpdater", func() { When("the resource type is not lowercase", func() { BeforeEach(func() { targetResource = TargetResource{ - ResourceType: "bUiLdPaCk", - ResourceName: resourceName, - BuildpackStack: "globinski", + ResourceType: "bUiLdPaCk", + ResourceName: resourceName, + BuildpackStack: "globinski", + BuildpackLifecycle: "cnb", } expectedMap = map[string]types.NullString{ "some-label": types.NewNullString("some-value"), @@ -411,7 +435,7 @@ var _ = Describe("LabelUpdater", func() { It("calls the right actor", func() { Expect(executeErr).ToNot(HaveOccurred()) - Expect(fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackCallCount()).To(Equal(1)) + Expect(fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleCallCount()).To(Equal(1)) }) It("displays a message in the right case", func() { @@ -422,7 +446,7 @@ var _ = Describe("LabelUpdater", func() { When("updating the buildpack labels fails", func() { BeforeEach(func() { - fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackReturns(v7action.Warnings{"some-warning-1", "some-warning-2"}, + fakeActor.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturns(v7action.Warnings{"some-warning-1", "some-warning-2"}, errors.New("api call failed")) }) @@ -448,11 +472,29 @@ var _ = Describe("LabelUpdater", func() { }) }) - When("stack is not passed", func() { + When("stack and lifecycle not passed", func() { It("shows 'Removing' as action", func() { Expect(testUI.Out).To(Say(regexp.QuoteMeta(`Removing label(s) for buildpack %s as some-user...`), resourceName)) }) }) + + When("lifecycle is passed", func() { + BeforeEach(func() { + targetResource.BuildpackLifecycle = "cnb" + }) + It("shows 'Removing' as action", func() { + Expect(testUI.Out).To(Say(regexp.QuoteMeta(`Removing label(s) for buildpack %s with lifecycle %s as some-user...`), resourceName, targetResource.BuildpackLifecycle)) + }) + }) + When("stack and lifecycle are passed", func() { + BeforeEach(func() { + targetResource.BuildpackLifecycle = "cnb" + targetResource.BuildpackStack = "globinski" + }) + It("shows 'Removing' as action", func() { + Expect(testUI.Out).To(Say(regexp.QuoteMeta(`Removing label(s) for buildpack %s with stack %s with lifecycle %s as some-user...`), resourceName, targetResource.BuildpackStack, targetResource.BuildpackLifecycle)) + }) + }) }) When("Setting labels", func() { @@ -470,11 +512,30 @@ var _ = Describe("LabelUpdater", func() { }) }) - When("stack is not passed", func() { + When("stack and lifecycle are not passed", func() { It("shows 'Setting' as action", func() { Expect(testUI.Out).To(Say(regexp.QuoteMeta(`Setting label(s) for buildpack %s as some-user...`), resourceName)) }) }) + + When("lifecycle is passed", func() { + BeforeEach(func() { + targetResource.BuildpackLifecycle = "cnb" + }) + It("shows 'Setting' as action", func() { + Expect(testUI.Out).To(Say(regexp.QuoteMeta(`Setting label(s) for buildpack %s with lifecycle %s as some-user...`), resourceName, targetResource.BuildpackLifecycle)) + }) + }) + + When("stack and lifecycle are passed", func() { + BeforeEach(func() { + targetResource.BuildpackLifecycle = "cnb" + targetResource.BuildpackStack = "globinski" + }) + It("shows 'Setting' as action", func() { + Expect(testUI.Out).To(Say(regexp.QuoteMeta(`Setting label(s) for buildpack %s with stack %s with lifecycle %s as some-user...`), resourceName, targetResource.BuildpackStack, targetResource.BuildpackLifecycle)) + }) + }) }) }) }) diff --git a/command/v7/labels_command.go b/command/v7/labels_command.go index 1899b43f83c..9a7f79a4d31 100644 --- a/command/v7/labels_command.go +++ b/command/v7/labels_command.go @@ -31,11 +31,12 @@ const ( type LabelsCommand struct { BaseCommand - RequiredArgs flag.LabelsArgs `positional-args:"yes"` - BuildpackStack string `long:"stack" short:"s" description:"Specify stack to disambiguate buildpacks with the same name"` - relatedCommands interface{} `related_commands:"set-label, unset-label"` - ServiceBroker string `long:"broker" short:"b" description:"Specify a service broker to disambiguate service offerings or service plans with the same name."` - ServiceOffering string `long:"offering" short:"e" description:"Specify a service offering to disambiguate service plans with the same name."` + RequiredArgs flag.LabelsArgs `positional-args:"yes"` + BuildpackStack string `long:"stack" short:"s" description:"Specify stack to disambiguate buildpacks with the same name"` + BuildpackLifecycle string `long:"lifecycle" short:"l" description:"Specify lifecycle to disambiguate buildpacks with the same name"` + relatedCommands interface{} `related_commands:"set-label, unset-label"` + ServiceBroker string `long:"broker" short:"b" description:"Specify a service broker to disambiguate service offerings or service plans with the same name."` + ServiceOffering string `long:"offering" short:"e" description:"Specify a service offering to disambiguate service plans with the same name."` username string } @@ -67,8 +68,8 @@ func (cmd LabelsCommand) Execute(args []string) error { cmd.displayMessageWithOrgAndSpace() labels, warnings, err = cmd.Actor.GetApplicationLabels(cmd.RequiredArgs.ResourceName, cmd.Config.TargetedSpace().GUID) case Buildpack: - cmd.displayMessageWithStack() - labels, warnings, err = cmd.Actor.GetBuildpackLabels(cmd.RequiredArgs.ResourceName, cmd.BuildpackStack) + cmd.displayMessageWithStackAndLifecycle() + labels, warnings, err = cmd.Actor.GetBuildpackLabels(cmd.RequiredArgs.ResourceName, cmd.BuildpackStack, cmd.BuildpackLifecycle) case Domain: cmd.displayMessageDefault() labels, warnings, err = cmd.Actor.GetDomainLabels(cmd.RequiredArgs.ResourceName) @@ -232,19 +233,17 @@ func (cmd LabelsCommand) displayMessageWithOrg() { }) } -func (cmd LabelsCommand) displayMessageWithStack() { - var template string - if cmd.BuildpackStack == "" { - template = fmt.Sprintf("Getting labels for %s {{.ResourceName}} as {{.User}}...", cmd.RequiredArgs.ResourceType) - } else { - template = fmt.Sprintf("Getting labels for %s {{.ResourceName}} with stack {{.StackName}} as {{.User}}...", cmd.RequiredArgs.ResourceType) +func (cmd LabelsCommand) displayMessageWithStackAndLifecycle() { + template := fmt.Sprintf("Getting labels for %s %s", cmd.RequiredArgs.ResourceType, cmd.RequiredArgs.ResourceName) + if cmd.BuildpackStack != "" { + template = fmt.Sprintf("%s with stack %s", template, cmd.BuildpackStack) + } + if cmd.BuildpackLifecycle != "" { + template = fmt.Sprintf("%s with lifecycle %s", template, cmd.BuildpackLifecycle) } - cmd.UI.DisplayTextWithFlavor(template, map[string]interface{}{ - "ResourceName": cmd.RequiredArgs.ResourceName, - "StackName": cmd.BuildpackStack, - "User": cmd.username, - }) + template = fmt.Sprintf("%s as %s...", template, cmd.username) + cmd.UI.DisplayTextWithFlavor(template) } func (cmd LabelsCommand) displayMessageForServiceCommands() { diff --git a/command/v7/labels_command_test.go b/command/v7/labels_command_test.go index e854d678704..3344d442292 100644 --- a/command/v7/labels_command_test.go +++ b/command/v7/labels_command_test.go @@ -752,13 +752,15 @@ var _ = Describe("labels command", func() { ResourceName: "oshkosh", } cmd.BuildpackStack = "cflinuxfs4" + cmd.BuildpackLifecycle = "cnb" }) It("retrieves the labels when resource type is buildpack", func() { Expect(executeErr).ToNot(HaveOccurred()) Expect(fakeLabelsActor.GetBuildpackLabelsCallCount()).To(Equal(1)) - buildpackName, stackName := fakeLabelsActor.GetBuildpackLabelsArgsForCall(0) + buildpackName, stackName, lifecycle := fakeLabelsActor.GetBuildpackLabelsArgsForCall(0) Expect(buildpackName).To(Equal("oshkosh")) Expect(stackName).To(Equal("cflinuxfs4")) + Expect(lifecycle).To(Equal("cnb")) }) }) }) diff --git a/command/v7/set_label_command.go b/command/v7/set_label_command.go index 06522547b4f..02de85c0cc2 100644 --- a/command/v7/set_label_command.go +++ b/command/v7/set_label_command.go @@ -18,11 +18,12 @@ type LabelSetter interface { type SetLabelCommand struct { BaseCommand - RequiredArgs flag.SetLabelArgs `positional-args:"yes"` - relatedCommands interface{} `related_commands:"labels, unset-label"` - BuildpackStack string `long:"stack" short:"s" description:"Specify stack to disambiguate buildpacks with the same name"` - ServiceBroker string `long:"broker" short:"b" description:"Specify a service broker to disambiguate service offerings or service plans with the same name."` - ServiceOffering string `long:"offering" short:"e" description:"Specify a service offering to disambiguate service plans with the same name."` + RequiredArgs flag.SetLabelArgs `positional-args:"yes"` + relatedCommands interface{} `related_commands:"labels, unset-label"` + BuildpackStack string `long:"stack" short:"s" description:"Specify stack to disambiguate buildpacks with the same name"` + BuildpackLifecycle string `long:"lifecycle" short:"l" description:"Specify lifecycle to disambiguate buildpacks with the same name"` + ServiceBroker string `long:"broker" short:"b" description:"Specify a service broker to disambiguate service offerings or service plans with the same name."` + ServiceOffering string `long:"offering" short:"e" description:"Specify a service offering to disambiguate service plans with the same name."` LabelSetter LabelSetter } diff --git a/command/v7/update_buildpack_command.go b/command/v7/update_buildpack_command.go index 8b71321d87d..978a36739ae 100644 --- a/command/v7/update_buildpack_command.go +++ b/command/v7/update_buildpack_command.go @@ -7,6 +7,7 @@ import ( "code.cloudfoundry.org/cli/actor/v7action" "code.cloudfoundry.org/cli/api/cloudcontroller/ccerror" "code.cloudfoundry.org/cli/api/cloudcontroller/ccv3" + "code.cloudfoundry.org/cli/api/cloudcontroller/ccversion" "code.cloudfoundry.org/cli/command" "code.cloudfoundry.org/cli/command/flag" "code.cloudfoundry.org/cli/command/translatableerror" @@ -27,7 +28,7 @@ type UpdateBuildpackCommand struct { BaseCommand RequiredArgs flag.BuildpackName `positional-args:"Yes"` - usage interface{} `usage:"CF_NAME update-buildpack BUILDPACK [-p PATH | -s STACK | --assign-stack NEW_STACK] [-i POSITION] [--rename NEW_NAME] [--enable|--disable] [--lock|--unlock]\n\nTIP:\nPath should be a zip file, a url to a zip file, or a local directory. Position is a positive integer, sets priority, and is sorted from lowest to highest.\n\nUse '--assign-stack' with caution. Associating a buildpack with a stack that it does not support may result in undefined behavior. Additionally, changing this association once made may require a local copy of the buildpack.\n\n"` + usage interface{} `usage:"CF_NAME update-buildpack BUILDPACK [-p PATH | -s STACK | --assign-stack NEW_STACK] [-i POSITION] [--rename NEW_NAME] [--enable|--disable] [--lock|--unlock]\n\nTIP:\nWhen using the 'buildpack' lifecycle type, Path should be a zip file, a url to a zip file, or a local directory. When using the 'cnb' lifecycle, Path should be a cnb file or gzipped oci image. Position is a positive integer, sets priority, and is sorted from lowest to highest.\n\nUse '--assign-stack' with caution. Associating a buildpack with a stack that it does not support may result in undefined behavior. Additionally, changing this association once made may require a local copy of the buildpack.\n\n"` relatedCommands interface{} `related_commands:"buildpacks, create-buildpack, delete-buildpack"` NewStack string `long:"assign-stack" description:"Assign a stack to a buildpack that does not have a stack association"` Disable bool `long:"disable" description:"Disable the buildpack from being used for staging"` @@ -37,6 +38,7 @@ type UpdateBuildpackCommand struct { Position types.NullInt `long:"position" short:"i" description:"The order in which the buildpacks are checked during buildpack auto-detection"` NewName string `long:"rename" description:"Rename an existing buildpack"` CurrentStack string `long:"stack" short:"s" description:"Specify stack to disambiguate buildpacks with the same name"` + Lifecycle string `long:"lifecycle" short:"l" description:"Specify lifecycle to disambiguate buildpacks with the same name"` Unlock bool `long:"unlock" description:"Unlock the buildpack to enable updates"` ProgressBar v7action.SimpleProgressBar @@ -55,6 +57,13 @@ func (cmd UpdateBuildpackCommand) Execute(args []string) error { return err } + if cmd.Lifecycle != "" { + err = command.MinimumCCAPIVersionCheck(cmd.Config.APIVersion(), ccversion.MinVersionBuildpackLifecycleQuery, "--lifecycle") + if err != nil { + return err + } + } + cmd.printInitialText(user.Name) if cmd.Path != "" { @@ -119,9 +128,10 @@ func (cmd UpdateBuildpackCommand) updateBuildpack() (resources.Buildpack, error) desiredBuildpack.Name = cmd.NewName } - updatedBuildpack, warnings, err := cmd.Actor.UpdateBuildpackByNameAndStack( + updatedBuildpack, warnings, err := cmd.Actor.UpdateBuildpackByNameAndStackAndLifecycle( cmd.RequiredArgs.Buildpack, cmd.CurrentStack, + cmd.Lifecycle, desiredBuildpack, ) cmd.UI.DisplayWarnings(warnings) @@ -181,32 +191,36 @@ func (cmd UpdateBuildpackCommand) printInitialText(userName string) { }) } - switch { - case cmd.NewStack != "": + if cmd.NewStack != "" { cmd.UI.DisplayTextWithFlavor("Assigning stack {{.Stack}} to {{.Buildpack}} as {{.CurrentUser}}...", map[string]interface{}{ "Buildpack": buildpackName, "CurrentUser": userName, "Stack": cmd.NewStack, }) if cmd.Position.IsSet || cmd.Lock || cmd.Unlock || cmd.Enable || cmd.Disable { - cmd.UI.DisplayTextWithFlavor("\nUpdating buildpack {{.Buildpack}} with stack {{.Stack}} as {{.CurrentUser}}...", map[string]interface{}{ - "Buildpack": buildpackName, - "CurrentUser": userName, - "Stack": cmd.NewStack, - }) + cmd.UI.DisplayNewline() + cmd.displayUpdatingBuildpackMessage(buildpackName, userName, cmd.NewStack) } - case cmd.CurrentStack == "": - cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} as {{.CurrentUser}}...", map[string]interface{}{ - "Buildpack": buildpackName, - "CurrentUser": userName, - }) - default: - cmd.UI.DisplayTextWithFlavor("Updating buildpack {{.Buildpack}} with stack {{.Stack}} as {{.CurrentUser}}...", map[string]interface{}{ - "Buildpack": buildpackName, - "CurrentUser": userName, - "Stack": cmd.CurrentStack, - }) + } else { + cmd.displayUpdatingBuildpackMessage(buildpackName, userName, cmd.CurrentStack) + } +} + +func (cmd UpdateBuildpackCommand) displayUpdatingBuildpackMessage(buildpackName, userName, stack string) { + message := "Updating buildpack {{.Buildpack}}" + if stack != "" { + message += " with stack {{.Stack}}" } + if cmd.Lifecycle != "" { + message += " with lifecycle {{.Lifecycle}}" + } + message += " as {{.CurrentUser}}..." + cmd.UI.DisplayTextWithFlavor(message, map[string]interface{}{ + "Buildpack": buildpackName, + "CurrentUser": userName, + "Stack": stack, + "Lifecycle": cmd.Lifecycle, + }) } func (cmd UpdateBuildpackCommand) validateFlagCombinations() error { diff --git a/command/v7/update_buildpack_command_test.go b/command/v7/update_buildpack_command_test.go index 834baffd403..5db627ab547 100644 --- a/command/v7/update_buildpack_command_test.go +++ b/command/v7/update_buildpack_command_test.go @@ -44,6 +44,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { testUI = ui.NewTestUI(input, NewBuffer(), NewBuffer()) fakeActor = new(v7fakes.FakeActor) fakeConfig = new(commandfakes.FakeConfig) + fakeConfig.APIVersionReturns("4.0.0") buildpackGUID = "some guid" cmd = UpdateBuildpackCommand{ @@ -173,7 +174,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { It("exits without updating if the path points to an empty directory", func() { Expect(executeErr).To(MatchError(emptyDirectoryError)) - Expect(fakeActor.UpdateBuildpackByNameAndStackCallCount()).To(Equal(0)) + Expect(fakeActor.UpdateBuildpackByNameAndStackAndLifecycleCallCount()).To(Equal(0)) }) }) @@ -182,7 +183,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { cmd.Path = "path/to/buildpack" fakeActor.PrepareBuildpackBitsReturns("path/to/prepared/bits", nil) expectedErr = errors.New("update-error") - fakeActor.UpdateBuildpackByNameAndStackReturns( + fakeActor.UpdateBuildpackByNameAndStackAndLifecycleReturns( resources.Buildpack{}, v7action.Warnings{"update-bp-warning1", "update-bp-warning2"}, expectedErr, @@ -204,7 +205,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { It("sets the locked value to true when updating the buildpack", func() { Expect(executeErr).ToNot(HaveOccurred()) - _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0) + _, _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(buildpack.Locked.IsSet).To(Equal(true)) Expect(buildpack.Locked.Value).To(Equal(true)) }) @@ -217,7 +218,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { It("sets the locked value to false when updating the buildpack", func() { Expect(executeErr).ToNot(HaveOccurred()) - _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0) + _, _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(buildpack.Locked.IsSet).To(Equal(true)) Expect(buildpack.Locked.Value).To(Equal(false)) }) @@ -230,7 +231,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { It("sets the enabled value to true when updating the buildpack", func() { Expect(executeErr).ToNot(HaveOccurred()) - _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0) + _, _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(buildpack.Enabled.IsSet).To(Equal(true)) Expect(buildpack.Enabled.Value).To(Equal(true)) }) @@ -243,7 +244,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { It("sets the enabled value to false when updating the buildpack", func() { Expect(executeErr).ToNot(HaveOccurred()) - _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0) + _, _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(buildpack.Enabled.IsSet).To(Equal(true)) Expect(buildpack.Enabled.Value).To(Equal(false)) }) @@ -256,7 +257,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { It("sets the new buildpack order when updating the buildpack", func() { Expect(executeErr).ToNot(HaveOccurred()) - _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0) + _, _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(buildpack.Position.IsSet).To(Equal(true)) Expect(buildpack.Position.Value).To(Equal(99)) }) @@ -269,7 +270,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { It("sets the new stack on the buildpack", func() { Expect(executeErr).ToNot(HaveOccurred()) - _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0) + _, _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(testUI.Out).ToNot(Say("Updating buildpack %s", buildpackName)) Expect(testUI.Out).To(Say("Assigning stack %s to %s as %s...", cmd.NewStack, buildpackName, userName)) Expect(buildpack.Stack).To(Equal("some-new-stack")) @@ -342,6 +343,28 @@ var _ = Describe("UpdateBuildpackCommand", func() { }) + When("the --lifecycle flag is provided", func() { + BeforeEach(func() { + cmd.Lifecycle = "some-lifecycle" + }) + It("is only used for getting the buildpack and does not update existing lifecycle", func() { + Expect(executeErr).ToNot(HaveOccurred()) + _, _, lifecycleQuery, buildpack := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) + Expect(buildpack.Lifecycle).To(BeEmpty()) + Expect(lifecycleQuery).To(Equal("some-lifecycle")) + }) + It("fails when the cc version is below the minimum", func() { + fakeConfig.APIVersionReturns("3.193.0") + executeErr = cmd.Execute(nil) + + Expect(executeErr).To(MatchError(translatableerror.MinimumCFAPIVersionNotMetError{ + Command: "--lifecycle", + CurrentVersion: "3.193.0", + MinimumVersion: "3.194.0", + })) + }) + }) + When("the --rename flag is provided", func() { BeforeEach(func() { cmd.NewName = "new-buildpack-name" @@ -349,7 +372,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { It("sets the new name on the buildpack", func() { Expect(executeErr).ToNot(HaveOccurred()) - _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0) + _, _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(buildpack.Name).To(Equal("new-buildpack-name")) Expect(testUI.Out).ToNot(Say("Updating buildpack %s", buildpackName)) @@ -365,7 +388,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { It("sets the new name/stack on the buildpack and refers to the new name going forward", func() { Expect(executeErr).ToNot(HaveOccurred()) - _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0) + _, _, _, buildpack := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(buildpack.Name).To(Equal("new-buildpack-name")) Expect(buildpack.Stack).To(Equal("new-stack")) @@ -384,7 +407,7 @@ var _ = Describe("UpdateBuildpackCommand", func() { When("updating the buildpack succeeds", func() { BeforeEach(func() { - fakeActor.UpdateBuildpackByNameAndStackReturns( + fakeActor.UpdateBuildpackByNameAndStackAndLifecycleReturns( resources.Buildpack{GUID: buildpackGUID}, v7action.Warnings{"update-bp-warning1", "update-bp-warning2"}, nil, @@ -393,14 +416,15 @@ var _ = Describe("UpdateBuildpackCommand", func() { When("no arguments are specified", func() { It("makes the actor call to update the buildpack", func() { - Expect(fakeActor.UpdateBuildpackByNameAndStackCallCount()).To(Equal(1)) - _, newStack, buildpack := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0) + Expect(fakeActor.UpdateBuildpackByNameAndStackAndLifecycleCallCount()).To(Equal(1)) + _, newStack, lifecycle, buildpack := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(buildpack.Name).To(Equal("")) Expect(buildpack.Stack).To(Equal("")) Expect(buildpack.Position.IsSet).To(BeFalse()) Expect(buildpack.Locked.IsSet).To(BeFalse()) Expect(buildpack.Enabled.IsSet).To(BeFalse()) Expect(newStack).To(Equal("")) + Expect(lifecycle).To(Equal("")) Expect(testUI.Err).To(Say("update-bp-warning1")) Expect(testUI.Err).To(Say("update-bp-warning2")) @@ -415,8 +439,8 @@ var _ = Describe("UpdateBuildpackCommand", func() { }) It("makes the call to update the buildpack", func() { - Expect(fakeActor.UpdateBuildpackByNameAndStackCallCount()).To(Equal(1)) - buildpackNameArg, _, _ := fakeActor.UpdateBuildpackByNameAndStackArgsForCall(0) + Expect(fakeActor.UpdateBuildpackByNameAndStackAndLifecycleCallCount()).To(Equal(1)) + buildpackNameArg, _, _, _ := fakeActor.UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(0) Expect(buildpackNameArg).To(Equal(buildpackName)) Expect(testUI.Err).To(Say("update-bp-warning1")) diff --git a/command/v7/v7fakes/fake_actor.go b/command/v7/v7fakes/fake_actor.go index 632fcf25207..a665170ffd0 100644 --- a/command/v7/v7fakes/fake_actor.go +++ b/command/v7/v7fakes/fake_actor.go @@ -572,17 +572,18 @@ type FakeActor struct { result1 v7action.Warnings result2 error } - DeleteBuildpackByNameAndStackStub func(string, string) (v7action.Warnings, error) - deleteBuildpackByNameAndStackMutex sync.RWMutex - deleteBuildpackByNameAndStackArgsForCall []struct { + DeleteBuildpackByNameAndStackAndLifecycleStub func(string, string, string) (v7action.Warnings, error) + deleteBuildpackByNameAndStackAndLifecycleMutex sync.RWMutex + deleteBuildpackByNameAndStackAndLifecycleArgsForCall []struct { arg1 string arg2 string + arg3 string } - deleteBuildpackByNameAndStackReturns struct { + deleteBuildpackByNameAndStackAndLifecycleReturns struct { result1 v7action.Warnings result2 error } - deleteBuildpackByNameAndStackReturnsOnCall map[int]struct { + deleteBuildpackByNameAndStackAndLifecycleReturnsOnCall map[int]struct { result1 v7action.Warnings result2 error } @@ -1194,11 +1195,12 @@ type FakeActor struct { result2 v7action.Warnings result3 error } - GetBuildpackLabelsStub func(string, string) (map[string]types.NullString, v7action.Warnings, error) + GetBuildpackLabelsStub func(string, string, string) (map[string]types.NullString, v7action.Warnings, error) getBuildpackLabelsMutex sync.RWMutex getBuildpackLabelsArgsForCall []struct { arg1 string arg2 string + arg3 string } getBuildpackLabelsReturns struct { result1 map[string]types.NullString @@ -1210,10 +1212,11 @@ type FakeActor struct { result2 v7action.Warnings result3 error } - GetBuildpacksStub func(string) ([]resources.Buildpack, v7action.Warnings, error) + GetBuildpacksStub func(string, string) ([]resources.Buildpack, v7action.Warnings, error) getBuildpacksMutex sync.RWMutex getBuildpacksArgsForCall []struct { arg1 string + arg2 string } getBuildpacksReturns struct { result1 []resources.Buildpack @@ -3283,35 +3286,37 @@ type FakeActor struct { result1 v7action.Warnings result2 error } - UpdateBuildpackByNameAndStackStub func(string, string, resources.Buildpack) (resources.Buildpack, v7action.Warnings, error) - updateBuildpackByNameAndStackMutex sync.RWMutex - updateBuildpackByNameAndStackArgsForCall []struct { + UpdateBuildpackByNameAndStackAndLifecycleStub func(string, string, string, resources.Buildpack) (resources.Buildpack, v7action.Warnings, error) + updateBuildpackByNameAndStackAndLifecycleMutex sync.RWMutex + updateBuildpackByNameAndStackAndLifecycleArgsForCall []struct { arg1 string arg2 string - arg3 resources.Buildpack + arg3 string + arg4 resources.Buildpack } - updateBuildpackByNameAndStackReturns struct { + updateBuildpackByNameAndStackAndLifecycleReturns struct { result1 resources.Buildpack result2 v7action.Warnings result3 error } - updateBuildpackByNameAndStackReturnsOnCall map[int]struct { + updateBuildpackByNameAndStackAndLifecycleReturnsOnCall map[int]struct { result1 resources.Buildpack result2 v7action.Warnings result3 error } - UpdateBuildpackLabelsByBuildpackNameAndStackStub func(string, string, map[string]types.NullString) (v7action.Warnings, error) - updateBuildpackLabelsByBuildpackNameAndStackMutex sync.RWMutex - updateBuildpackLabelsByBuildpackNameAndStackArgsForCall []struct { + UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleStub func(string, string, string, map[string]types.NullString) (v7action.Warnings, error) + updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex sync.RWMutex + updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall []struct { arg1 string arg2 string - arg3 map[string]types.NullString + arg3 string + arg4 map[string]types.NullString } - updateBuildpackLabelsByBuildpackNameAndStackReturns struct { + updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturns struct { result1 v7action.Warnings result2 error } - updateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall map[int]struct { + updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall map[int]struct { result1 v7action.Warnings result2 error } @@ -6125,19 +6130,20 @@ func (fake *FakeActor) DeleteApplicationByNameAndSpaceReturnsOnCall(i int, resul }{result1, result2} } -func (fake *FakeActor) DeleteBuildpackByNameAndStack(arg1 string, arg2 string) (v7action.Warnings, error) { - fake.deleteBuildpackByNameAndStackMutex.Lock() - ret, specificReturn := fake.deleteBuildpackByNameAndStackReturnsOnCall[len(fake.deleteBuildpackByNameAndStackArgsForCall)] - fake.deleteBuildpackByNameAndStackArgsForCall = append(fake.deleteBuildpackByNameAndStackArgsForCall, struct { +func (fake *FakeActor) DeleteBuildpackByNameAndStackAndLifecycle(arg1 string, arg2 string, arg3 string) (v7action.Warnings, error) { + fake.deleteBuildpackByNameAndStackAndLifecycleMutex.Lock() + ret, specificReturn := fake.deleteBuildpackByNameAndStackAndLifecycleReturnsOnCall[len(fake.deleteBuildpackByNameAndStackAndLifecycleArgsForCall)] + fake.deleteBuildpackByNameAndStackAndLifecycleArgsForCall = append(fake.deleteBuildpackByNameAndStackAndLifecycleArgsForCall, struct { arg1 string arg2 string - }{arg1, arg2}) - stub := fake.DeleteBuildpackByNameAndStackStub - fakeReturns := fake.deleteBuildpackByNameAndStackReturns - fake.recordInvocation("DeleteBuildpackByNameAndStack", []interface{}{arg1, arg2}) - fake.deleteBuildpackByNameAndStackMutex.Unlock() + arg3 string + }{arg1, arg2, arg3}) + stub := fake.DeleteBuildpackByNameAndStackAndLifecycleStub + fakeReturns := fake.deleteBuildpackByNameAndStackAndLifecycleReturns + fake.recordInvocation("DeleteBuildpackByNameAndStackAndLifecycle", []interface{}{arg1, arg2, arg3}) + fake.deleteBuildpackByNameAndStackAndLifecycleMutex.Unlock() if stub != nil { - return stub(arg1, arg2) + return stub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2 @@ -6145,46 +6151,46 @@ func (fake *FakeActor) DeleteBuildpackByNameAndStack(arg1 string, arg2 string) ( return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeActor) DeleteBuildpackByNameAndStackCallCount() int { - fake.deleteBuildpackByNameAndStackMutex.RLock() - defer fake.deleteBuildpackByNameAndStackMutex.RUnlock() - return len(fake.deleteBuildpackByNameAndStackArgsForCall) +func (fake *FakeActor) DeleteBuildpackByNameAndStackAndLifecycleCallCount() int { + fake.deleteBuildpackByNameAndStackAndLifecycleMutex.RLock() + defer fake.deleteBuildpackByNameAndStackAndLifecycleMutex.RUnlock() + return len(fake.deleteBuildpackByNameAndStackAndLifecycleArgsForCall) } -func (fake *FakeActor) DeleteBuildpackByNameAndStackCalls(stub func(string, string) (v7action.Warnings, error)) { - fake.deleteBuildpackByNameAndStackMutex.Lock() - defer fake.deleteBuildpackByNameAndStackMutex.Unlock() - fake.DeleteBuildpackByNameAndStackStub = stub +func (fake *FakeActor) DeleteBuildpackByNameAndStackAndLifecycleCalls(stub func(string, string, string) (v7action.Warnings, error)) { + fake.deleteBuildpackByNameAndStackAndLifecycleMutex.Lock() + defer fake.deleteBuildpackByNameAndStackAndLifecycleMutex.Unlock() + fake.DeleteBuildpackByNameAndStackAndLifecycleStub = stub } -func (fake *FakeActor) DeleteBuildpackByNameAndStackArgsForCall(i int) (string, string) { - fake.deleteBuildpackByNameAndStackMutex.RLock() - defer fake.deleteBuildpackByNameAndStackMutex.RUnlock() - argsForCall := fake.deleteBuildpackByNameAndStackArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 +func (fake *FakeActor) DeleteBuildpackByNameAndStackAndLifecycleArgsForCall(i int) (string, string, string) { + fake.deleteBuildpackByNameAndStackAndLifecycleMutex.RLock() + defer fake.deleteBuildpackByNameAndStackAndLifecycleMutex.RUnlock() + argsForCall := fake.deleteBuildpackByNameAndStackAndLifecycleArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } -func (fake *FakeActor) DeleteBuildpackByNameAndStackReturns(result1 v7action.Warnings, result2 error) { - fake.deleteBuildpackByNameAndStackMutex.Lock() - defer fake.deleteBuildpackByNameAndStackMutex.Unlock() - fake.DeleteBuildpackByNameAndStackStub = nil - fake.deleteBuildpackByNameAndStackReturns = struct { +func (fake *FakeActor) DeleteBuildpackByNameAndStackAndLifecycleReturns(result1 v7action.Warnings, result2 error) { + fake.deleteBuildpackByNameAndStackAndLifecycleMutex.Lock() + defer fake.deleteBuildpackByNameAndStackAndLifecycleMutex.Unlock() + fake.DeleteBuildpackByNameAndStackAndLifecycleStub = nil + fake.deleteBuildpackByNameAndStackAndLifecycleReturns = struct { result1 v7action.Warnings result2 error }{result1, result2} } -func (fake *FakeActor) DeleteBuildpackByNameAndStackReturnsOnCall(i int, result1 v7action.Warnings, result2 error) { - fake.deleteBuildpackByNameAndStackMutex.Lock() - defer fake.deleteBuildpackByNameAndStackMutex.Unlock() - fake.DeleteBuildpackByNameAndStackStub = nil - if fake.deleteBuildpackByNameAndStackReturnsOnCall == nil { - fake.deleteBuildpackByNameAndStackReturnsOnCall = make(map[int]struct { +func (fake *FakeActor) DeleteBuildpackByNameAndStackAndLifecycleReturnsOnCall(i int, result1 v7action.Warnings, result2 error) { + fake.deleteBuildpackByNameAndStackAndLifecycleMutex.Lock() + defer fake.deleteBuildpackByNameAndStackAndLifecycleMutex.Unlock() + fake.DeleteBuildpackByNameAndStackAndLifecycleStub = nil + if fake.deleteBuildpackByNameAndStackAndLifecycleReturnsOnCall == nil { + fake.deleteBuildpackByNameAndStackAndLifecycleReturnsOnCall = make(map[int]struct { result1 v7action.Warnings result2 error }) } - fake.deleteBuildpackByNameAndStackReturnsOnCall[i] = struct { + fake.deleteBuildpackByNameAndStackAndLifecycleReturnsOnCall[i] = struct { result1 v7action.Warnings result2 error }{result1, result2} @@ -8871,19 +8877,20 @@ func (fake *FakeActor) GetApplicationsByNamesAndSpaceReturnsOnCall(i int, result }{result1, result2, result3} } -func (fake *FakeActor) GetBuildpackLabels(arg1 string, arg2 string) (map[string]types.NullString, v7action.Warnings, error) { +func (fake *FakeActor) GetBuildpackLabels(arg1 string, arg2 string, arg3 string) (map[string]types.NullString, v7action.Warnings, error) { fake.getBuildpackLabelsMutex.Lock() ret, specificReturn := fake.getBuildpackLabelsReturnsOnCall[len(fake.getBuildpackLabelsArgsForCall)] fake.getBuildpackLabelsArgsForCall = append(fake.getBuildpackLabelsArgsForCall, struct { arg1 string arg2 string - }{arg1, arg2}) + arg3 string + }{arg1, arg2, arg3}) stub := fake.GetBuildpackLabelsStub fakeReturns := fake.getBuildpackLabelsReturns - fake.recordInvocation("GetBuildpackLabels", []interface{}{arg1, arg2}) + fake.recordInvocation("GetBuildpackLabels", []interface{}{arg1, arg2, arg3}) fake.getBuildpackLabelsMutex.Unlock() if stub != nil { - return stub(arg1, arg2) + return stub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2, ret.result3 @@ -8897,17 +8904,17 @@ func (fake *FakeActor) GetBuildpackLabelsCallCount() int { return len(fake.getBuildpackLabelsArgsForCall) } -func (fake *FakeActor) GetBuildpackLabelsCalls(stub func(string, string) (map[string]types.NullString, v7action.Warnings, error)) { +func (fake *FakeActor) GetBuildpackLabelsCalls(stub func(string, string, string) (map[string]types.NullString, v7action.Warnings, error)) { fake.getBuildpackLabelsMutex.Lock() defer fake.getBuildpackLabelsMutex.Unlock() fake.GetBuildpackLabelsStub = stub } -func (fake *FakeActor) GetBuildpackLabelsArgsForCall(i int) (string, string) { +func (fake *FakeActor) GetBuildpackLabelsArgsForCall(i int) (string, string, string) { fake.getBuildpackLabelsMutex.RLock() defer fake.getBuildpackLabelsMutex.RUnlock() argsForCall := fake.getBuildpackLabelsArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 } func (fake *FakeActor) GetBuildpackLabelsReturns(result1 map[string]types.NullString, result2 v7action.Warnings, result3 error) { @@ -8939,18 +8946,19 @@ func (fake *FakeActor) GetBuildpackLabelsReturnsOnCall(i int, result1 map[string }{result1, result2, result3} } -func (fake *FakeActor) GetBuildpacks(arg1 string) ([]resources.Buildpack, v7action.Warnings, error) { +func (fake *FakeActor) GetBuildpacks(arg1 string, arg2 string) ([]resources.Buildpack, v7action.Warnings, error) { fake.getBuildpacksMutex.Lock() ret, specificReturn := fake.getBuildpacksReturnsOnCall[len(fake.getBuildpacksArgsForCall)] fake.getBuildpacksArgsForCall = append(fake.getBuildpacksArgsForCall, struct { arg1 string - }{arg1}) + arg2 string + }{arg1, arg2}) stub := fake.GetBuildpacksStub fakeReturns := fake.getBuildpacksReturns - fake.recordInvocation("GetBuildpacks", []interface{}{arg1}) + fake.recordInvocation("GetBuildpacks", []interface{}{arg1, arg2}) fake.getBuildpacksMutex.Unlock() if stub != nil { - return stub(arg1) + return stub(arg1, arg2) } if specificReturn { return ret.result1, ret.result2, ret.result3 @@ -8964,17 +8972,17 @@ func (fake *FakeActor) GetBuildpacksCallCount() int { return len(fake.getBuildpacksArgsForCall) } -func (fake *FakeActor) GetBuildpacksCalls(stub func(string) ([]resources.Buildpack, v7action.Warnings, error)) { +func (fake *FakeActor) GetBuildpacksCalls(stub func(string, string) ([]resources.Buildpack, v7action.Warnings, error)) { fake.getBuildpacksMutex.Lock() defer fake.getBuildpacksMutex.Unlock() fake.GetBuildpacksStub = stub } -func (fake *FakeActor) GetBuildpacksArgsForCall(i int) string { +func (fake *FakeActor) GetBuildpacksArgsForCall(i int) (string, string) { fake.getBuildpacksMutex.RLock() defer fake.getBuildpacksMutex.RUnlock() argsForCall := fake.getBuildpacksArgsForCall[i] - return argsForCall.arg1 + return argsForCall.arg1, argsForCall.arg2 } func (fake *FakeActor) GetBuildpacksReturns(result1 []resources.Buildpack, result2 v7action.Warnings, result3 error) { @@ -18006,20 +18014,21 @@ func (fake *FakeActor) UpdateApplicationLabelsByApplicationNameReturnsOnCall(i i }{result1, result2} } -func (fake *FakeActor) UpdateBuildpackByNameAndStack(arg1 string, arg2 string, arg3 resources.Buildpack) (resources.Buildpack, v7action.Warnings, error) { - fake.updateBuildpackByNameAndStackMutex.Lock() - ret, specificReturn := fake.updateBuildpackByNameAndStackReturnsOnCall[len(fake.updateBuildpackByNameAndStackArgsForCall)] - fake.updateBuildpackByNameAndStackArgsForCall = append(fake.updateBuildpackByNameAndStackArgsForCall, struct { +func (fake *FakeActor) UpdateBuildpackByNameAndStackAndLifecycle(arg1 string, arg2 string, arg3 string, arg4 resources.Buildpack) (resources.Buildpack, v7action.Warnings, error) { + fake.updateBuildpackByNameAndStackAndLifecycleMutex.Lock() + ret, specificReturn := fake.updateBuildpackByNameAndStackAndLifecycleReturnsOnCall[len(fake.updateBuildpackByNameAndStackAndLifecycleArgsForCall)] + fake.updateBuildpackByNameAndStackAndLifecycleArgsForCall = append(fake.updateBuildpackByNameAndStackAndLifecycleArgsForCall, struct { arg1 string arg2 string - arg3 resources.Buildpack - }{arg1, arg2, arg3}) - stub := fake.UpdateBuildpackByNameAndStackStub - fakeReturns := fake.updateBuildpackByNameAndStackReturns - fake.recordInvocation("UpdateBuildpackByNameAndStack", []interface{}{arg1, arg2, arg3}) - fake.updateBuildpackByNameAndStackMutex.Unlock() + arg3 string + arg4 resources.Buildpack + }{arg1, arg2, arg3, arg4}) + stub := fake.UpdateBuildpackByNameAndStackAndLifecycleStub + fakeReturns := fake.updateBuildpackByNameAndStackAndLifecycleReturns + fake.recordInvocation("UpdateBuildpackByNameAndStackAndLifecycle", []interface{}{arg1, arg2, arg3, arg4}) + fake.updateBuildpackByNameAndStackAndLifecycleMutex.Unlock() if stub != nil { - return stub(arg1, arg2, arg3) + return stub(arg1, arg2, arg3, arg4) } if specificReturn { return ret.result1, ret.result2, ret.result3 @@ -18027,68 +18036,69 @@ func (fake *FakeActor) UpdateBuildpackByNameAndStack(arg1 string, arg2 string, a return fakeReturns.result1, fakeReturns.result2, fakeReturns.result3 } -func (fake *FakeActor) UpdateBuildpackByNameAndStackCallCount() int { - fake.updateBuildpackByNameAndStackMutex.RLock() - defer fake.updateBuildpackByNameAndStackMutex.RUnlock() - return len(fake.updateBuildpackByNameAndStackArgsForCall) +func (fake *FakeActor) UpdateBuildpackByNameAndStackAndLifecycleCallCount() int { + fake.updateBuildpackByNameAndStackAndLifecycleMutex.RLock() + defer fake.updateBuildpackByNameAndStackAndLifecycleMutex.RUnlock() + return len(fake.updateBuildpackByNameAndStackAndLifecycleArgsForCall) } -func (fake *FakeActor) UpdateBuildpackByNameAndStackCalls(stub func(string, string, resources.Buildpack) (resources.Buildpack, v7action.Warnings, error)) { - fake.updateBuildpackByNameAndStackMutex.Lock() - defer fake.updateBuildpackByNameAndStackMutex.Unlock() - fake.UpdateBuildpackByNameAndStackStub = stub +func (fake *FakeActor) UpdateBuildpackByNameAndStackAndLifecycleCalls(stub func(string, string, string, resources.Buildpack) (resources.Buildpack, v7action.Warnings, error)) { + fake.updateBuildpackByNameAndStackAndLifecycleMutex.Lock() + defer fake.updateBuildpackByNameAndStackAndLifecycleMutex.Unlock() + fake.UpdateBuildpackByNameAndStackAndLifecycleStub = stub } -func (fake *FakeActor) UpdateBuildpackByNameAndStackArgsForCall(i int) (string, string, resources.Buildpack) { - fake.updateBuildpackByNameAndStackMutex.RLock() - defer fake.updateBuildpackByNameAndStackMutex.RUnlock() - argsForCall := fake.updateBuildpackByNameAndStackArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +func (fake *FakeActor) UpdateBuildpackByNameAndStackAndLifecycleArgsForCall(i int) (string, string, string, resources.Buildpack) { + fake.updateBuildpackByNameAndStackAndLifecycleMutex.RLock() + defer fake.updateBuildpackByNameAndStackAndLifecycleMutex.RUnlock() + argsForCall := fake.updateBuildpackByNameAndStackAndLifecycleArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 } -func (fake *FakeActor) UpdateBuildpackByNameAndStackReturns(result1 resources.Buildpack, result2 v7action.Warnings, result3 error) { - fake.updateBuildpackByNameAndStackMutex.Lock() - defer fake.updateBuildpackByNameAndStackMutex.Unlock() - fake.UpdateBuildpackByNameAndStackStub = nil - fake.updateBuildpackByNameAndStackReturns = struct { +func (fake *FakeActor) UpdateBuildpackByNameAndStackAndLifecycleReturns(result1 resources.Buildpack, result2 v7action.Warnings, result3 error) { + fake.updateBuildpackByNameAndStackAndLifecycleMutex.Lock() + defer fake.updateBuildpackByNameAndStackAndLifecycleMutex.Unlock() + fake.UpdateBuildpackByNameAndStackAndLifecycleStub = nil + fake.updateBuildpackByNameAndStackAndLifecycleReturns = struct { result1 resources.Buildpack result2 v7action.Warnings result3 error }{result1, result2, result3} } -func (fake *FakeActor) UpdateBuildpackByNameAndStackReturnsOnCall(i int, result1 resources.Buildpack, result2 v7action.Warnings, result3 error) { - fake.updateBuildpackByNameAndStackMutex.Lock() - defer fake.updateBuildpackByNameAndStackMutex.Unlock() - fake.UpdateBuildpackByNameAndStackStub = nil - if fake.updateBuildpackByNameAndStackReturnsOnCall == nil { - fake.updateBuildpackByNameAndStackReturnsOnCall = make(map[int]struct { +func (fake *FakeActor) UpdateBuildpackByNameAndStackAndLifecycleReturnsOnCall(i int, result1 resources.Buildpack, result2 v7action.Warnings, result3 error) { + fake.updateBuildpackByNameAndStackAndLifecycleMutex.Lock() + defer fake.updateBuildpackByNameAndStackAndLifecycleMutex.Unlock() + fake.UpdateBuildpackByNameAndStackAndLifecycleStub = nil + if fake.updateBuildpackByNameAndStackAndLifecycleReturnsOnCall == nil { + fake.updateBuildpackByNameAndStackAndLifecycleReturnsOnCall = make(map[int]struct { result1 resources.Buildpack result2 v7action.Warnings result3 error }) } - fake.updateBuildpackByNameAndStackReturnsOnCall[i] = struct { + fake.updateBuildpackByNameAndStackAndLifecycleReturnsOnCall[i] = struct { result1 resources.Buildpack result2 v7action.Warnings result3 error }{result1, result2, result3} } -func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStack(arg1 string, arg2 string, arg3 map[string]types.NullString) (v7action.Warnings, error) { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Lock() - ret, specificReturn := fake.updateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall[len(fake.updateBuildpackLabelsByBuildpackNameAndStackArgsForCall)] - fake.updateBuildpackLabelsByBuildpackNameAndStackArgsForCall = append(fake.updateBuildpackLabelsByBuildpackNameAndStackArgsForCall, struct { +func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycle(arg1 string, arg2 string, arg3 string, arg4 map[string]types.NullString) (v7action.Warnings, error) { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Lock() + ret, specificReturn := fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall[len(fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall)] + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall = append(fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall, struct { arg1 string arg2 string - arg3 map[string]types.NullString - }{arg1, arg2, arg3}) - stub := fake.UpdateBuildpackLabelsByBuildpackNameAndStackStub - fakeReturns := fake.updateBuildpackLabelsByBuildpackNameAndStackReturns - fake.recordInvocation("UpdateBuildpackLabelsByBuildpackNameAndStack", []interface{}{arg1, arg2, arg3}) - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Unlock() + arg3 string + arg4 map[string]types.NullString + }{arg1, arg2, arg3, arg4}) + stub := fake.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleStub + fakeReturns := fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturns + fake.recordInvocation("UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycle", []interface{}{arg1, arg2, arg3, arg4}) + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Unlock() if stub != nil { - return stub(arg1, arg2, arg3) + return stub(arg1, arg2, arg3, arg4) } if specificReturn { return ret.result1, ret.result2 @@ -18096,46 +18106,46 @@ func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStack(arg1 string, return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackCallCount() int { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RLock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RUnlock() - return len(fake.updateBuildpackLabelsByBuildpackNameAndStackArgsForCall) +func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleCallCount() int { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RLock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RUnlock() + return len(fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall) } -func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackCalls(stub func(string, string, map[string]types.NullString) (v7action.Warnings, error)) { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Lock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Unlock() - fake.UpdateBuildpackLabelsByBuildpackNameAndStackStub = stub +func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleCalls(stub func(string, string, string, map[string]types.NullString) (v7action.Warnings, error)) { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Lock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Unlock() + fake.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleStub = stub } -func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackArgsForCall(i int) (string, string, map[string]types.NullString) { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RLock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RUnlock() - argsForCall := fake.updateBuildpackLabelsByBuildpackNameAndStackArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall(i int) (string, string, string, map[string]types.NullString) { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RLock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RUnlock() + argsForCall := fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 } -func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackReturns(result1 v7action.Warnings, result2 error) { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Lock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Unlock() - fake.UpdateBuildpackLabelsByBuildpackNameAndStackStub = nil - fake.updateBuildpackLabelsByBuildpackNameAndStackReturns = struct { +func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturns(result1 v7action.Warnings, result2 error) { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Lock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Unlock() + fake.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleStub = nil + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturns = struct { result1 v7action.Warnings result2 error }{result1, result2} } -func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall(i int, result1 v7action.Warnings, result2 error) { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Lock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Unlock() - fake.UpdateBuildpackLabelsByBuildpackNameAndStackStub = nil - if fake.updateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall == nil { - fake.updateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall = make(map[int]struct { +func (fake *FakeActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall(i int, result1 v7action.Warnings, result2 error) { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Lock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Unlock() + fake.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleStub = nil + if fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall == nil { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall = make(map[int]struct { result1 v7action.Warnings result2 error }) } - fake.updateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall[i] = struct { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall[i] = struct { result1 v7action.Warnings result2 error }{result1, result2} @@ -19880,8 +19890,8 @@ func (fake *FakeActor) Invocations() map[string][][]interface{} { defer fake.createUserProvidedServiceInstanceMutex.RUnlock() fake.deleteApplicationByNameAndSpaceMutex.RLock() defer fake.deleteApplicationByNameAndSpaceMutex.RUnlock() - fake.deleteBuildpackByNameAndStackMutex.RLock() - defer fake.deleteBuildpackByNameAndStackMutex.RUnlock() + fake.deleteBuildpackByNameAndStackAndLifecycleMutex.RLock() + defer fake.deleteBuildpackByNameAndStackAndLifecycleMutex.RUnlock() fake.deleteDomainMutex.RLock() defer fake.deleteDomainMutex.RUnlock() fake.deleteInstanceByApplicationNameSpaceProcessTypeAndIndexMutex.RLock() @@ -20238,10 +20248,10 @@ func (fake *FakeActor) Invocations() map[string][][]interface{} { defer fake.updateApplicationMutex.RUnlock() fake.updateApplicationLabelsByApplicationNameMutex.RLock() defer fake.updateApplicationLabelsByApplicationNameMutex.RUnlock() - fake.updateBuildpackByNameAndStackMutex.RLock() - defer fake.updateBuildpackByNameAndStackMutex.RUnlock() - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RLock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RUnlock() + fake.updateBuildpackByNameAndStackAndLifecycleMutex.RLock() + defer fake.updateBuildpackByNameAndStackAndLifecycleMutex.RUnlock() + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RLock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RUnlock() fake.updateDestinationMutex.RLock() defer fake.updateDestinationMutex.RUnlock() fake.updateDomainLabelsByDomainNameMutex.RLock() diff --git a/command/v7/v7fakes/fake_set_label_actor.go b/command/v7/v7fakes/fake_set_label_actor.go index 8eb74fcb505..7e3a6d27e74 100644 --- a/command/v7/v7fakes/fake_set_label_actor.go +++ b/command/v7/v7fakes/fake_set_label_actor.go @@ -38,18 +38,19 @@ type FakeSetLabelActor struct { result1 v7action.Warnings result2 error } - UpdateBuildpackLabelsByBuildpackNameAndStackStub func(string, string, map[string]types.NullString) (v7action.Warnings, error) - updateBuildpackLabelsByBuildpackNameAndStackMutex sync.RWMutex - updateBuildpackLabelsByBuildpackNameAndStackArgsForCall []struct { + UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleStub func(string, string, string, map[string]types.NullString) (v7action.Warnings, error) + updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex sync.RWMutex + updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall []struct { arg1 string arg2 string - arg3 map[string]types.NullString + arg3 string + arg4 map[string]types.NullString } - updateBuildpackLabelsByBuildpackNameAndStackReturns struct { + updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturns struct { result1 v7action.Warnings result2 error } - updateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall map[int]struct { + updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall map[int]struct { result1 v7action.Warnings result2 error } @@ -194,15 +195,16 @@ func (fake *FakeSetLabelActor) GetCurrentUser() (configv3.User, error) { ret, specificReturn := fake.getCurrentUserReturnsOnCall[len(fake.getCurrentUserArgsForCall)] fake.getCurrentUserArgsForCall = append(fake.getCurrentUserArgsForCall, struct { }{}) + stub := fake.GetCurrentUserStub + fakeReturns := fake.getCurrentUserReturns fake.recordInvocation("GetCurrentUser", []interface{}{}) fake.getCurrentUserMutex.Unlock() - if fake.GetCurrentUserStub != nil { - return fake.GetCurrentUserStub() + if stub != nil { + return stub() } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.getCurrentUserReturns return fakeReturns.result1, fakeReturns.result2 } @@ -252,15 +254,16 @@ func (fake *FakeSetLabelActor) UpdateApplicationLabelsByApplicationName(arg1 str arg2 string arg3 map[string]types.NullString }{arg1, arg2, arg3}) + stub := fake.UpdateApplicationLabelsByApplicationNameStub + fakeReturns := fake.updateApplicationLabelsByApplicationNameReturns fake.recordInvocation("UpdateApplicationLabelsByApplicationName", []interface{}{arg1, arg2, arg3}) fake.updateApplicationLabelsByApplicationNameMutex.Unlock() - if fake.UpdateApplicationLabelsByApplicationNameStub != nil { - return fake.UpdateApplicationLabelsByApplicationNameStub(arg1, arg2, arg3) + if stub != nil { + return stub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateApplicationLabelsByApplicationNameReturns return fakeReturns.result1, fakeReturns.result2 } @@ -309,66 +312,68 @@ func (fake *FakeSetLabelActor) UpdateApplicationLabelsByApplicationNameReturnsOn }{result1, result2} } -func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStack(arg1 string, arg2 string, arg3 map[string]types.NullString) (v7action.Warnings, error) { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Lock() - ret, specificReturn := fake.updateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall[len(fake.updateBuildpackLabelsByBuildpackNameAndStackArgsForCall)] - fake.updateBuildpackLabelsByBuildpackNameAndStackArgsForCall = append(fake.updateBuildpackLabelsByBuildpackNameAndStackArgsForCall, struct { +func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycle(arg1 string, arg2 string, arg3 string, arg4 map[string]types.NullString) (v7action.Warnings, error) { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Lock() + ret, specificReturn := fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall[len(fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall)] + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall = append(fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall, struct { arg1 string arg2 string - arg3 map[string]types.NullString - }{arg1, arg2, arg3}) - fake.recordInvocation("UpdateBuildpackLabelsByBuildpackNameAndStack", []interface{}{arg1, arg2, arg3}) - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Unlock() - if fake.UpdateBuildpackLabelsByBuildpackNameAndStackStub != nil { - return fake.UpdateBuildpackLabelsByBuildpackNameAndStackStub(arg1, arg2, arg3) + arg3 string + arg4 map[string]types.NullString + }{arg1, arg2, arg3, arg4}) + stub := fake.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleStub + fakeReturns := fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturns + fake.recordInvocation("UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycle", []interface{}{arg1, arg2, arg3, arg4}) + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Unlock() + if stub != nil { + return stub(arg1, arg2, arg3, arg4) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateBuildpackLabelsByBuildpackNameAndStackReturns return fakeReturns.result1, fakeReturns.result2 } -func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackCallCount() int { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RLock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RUnlock() - return len(fake.updateBuildpackLabelsByBuildpackNameAndStackArgsForCall) +func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleCallCount() int { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RLock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RUnlock() + return len(fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall) } -func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackCalls(stub func(string, string, map[string]types.NullString) (v7action.Warnings, error)) { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Lock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Unlock() - fake.UpdateBuildpackLabelsByBuildpackNameAndStackStub = stub +func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleCalls(stub func(string, string, string, map[string]types.NullString) (v7action.Warnings, error)) { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Lock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Unlock() + fake.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleStub = stub } -func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackArgsForCall(i int) (string, string, map[string]types.NullString) { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RLock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RUnlock() - argsForCall := fake.updateBuildpackLabelsByBuildpackNameAndStackArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3 +func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall(i int) (string, string, string, map[string]types.NullString) { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RLock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RUnlock() + argsForCall := fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleArgsForCall[i] + return argsForCall.arg1, argsForCall.arg2, argsForCall.arg3, argsForCall.arg4 } -func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackReturns(result1 v7action.Warnings, result2 error) { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Lock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Unlock() - fake.UpdateBuildpackLabelsByBuildpackNameAndStackStub = nil - fake.updateBuildpackLabelsByBuildpackNameAndStackReturns = struct { +func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturns(result1 v7action.Warnings, result2 error) { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Lock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Unlock() + fake.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleStub = nil + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturns = struct { result1 v7action.Warnings result2 error }{result1, result2} } -func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall(i int, result1 v7action.Warnings, result2 error) { - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Lock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.Unlock() - fake.UpdateBuildpackLabelsByBuildpackNameAndStackStub = nil - if fake.updateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall == nil { - fake.updateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall = make(map[int]struct { +func (fake *FakeSetLabelActor) UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall(i int, result1 v7action.Warnings, result2 error) { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Lock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.Unlock() + fake.UpdateBuildpackLabelsByBuildpackNameAndStackAndLifecycleStub = nil + if fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall == nil { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall = make(map[int]struct { result1 v7action.Warnings result2 error }) } - fake.updateBuildpackLabelsByBuildpackNameAndStackReturnsOnCall[i] = struct { + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleReturnsOnCall[i] = struct { result1 v7action.Warnings result2 error }{result1, result2} @@ -381,15 +386,16 @@ func (fake *FakeSetLabelActor) UpdateDomainLabelsByDomainName(arg1 string, arg2 arg1 string arg2 map[string]types.NullString }{arg1, arg2}) + stub := fake.UpdateDomainLabelsByDomainNameStub + fakeReturns := fake.updateDomainLabelsByDomainNameReturns fake.recordInvocation("UpdateDomainLabelsByDomainName", []interface{}{arg1, arg2}) fake.updateDomainLabelsByDomainNameMutex.Unlock() - if fake.UpdateDomainLabelsByDomainNameStub != nil { - return fake.UpdateDomainLabelsByDomainNameStub(arg1, arg2) + if stub != nil { + return stub(arg1, arg2) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateDomainLabelsByDomainNameReturns return fakeReturns.result1, fakeReturns.result2 } @@ -445,15 +451,16 @@ func (fake *FakeSetLabelActor) UpdateOrganizationLabelsByOrganizationName(arg1 s arg1 string arg2 map[string]types.NullString }{arg1, arg2}) + stub := fake.UpdateOrganizationLabelsByOrganizationNameStub + fakeReturns := fake.updateOrganizationLabelsByOrganizationNameReturns fake.recordInvocation("UpdateOrganizationLabelsByOrganizationName", []interface{}{arg1, arg2}) fake.updateOrganizationLabelsByOrganizationNameMutex.Unlock() - if fake.UpdateOrganizationLabelsByOrganizationNameStub != nil { - return fake.UpdateOrganizationLabelsByOrganizationNameStub(arg1, arg2) + if stub != nil { + return stub(arg1, arg2) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateOrganizationLabelsByOrganizationNameReturns return fakeReturns.result1, fakeReturns.result2 } @@ -510,15 +517,16 @@ func (fake *FakeSetLabelActor) UpdateRouteLabels(arg1 string, arg2 string, arg3 arg2 string arg3 map[string]types.NullString }{arg1, arg2, arg3}) + stub := fake.UpdateRouteLabelsStub + fakeReturns := fake.updateRouteLabelsReturns fake.recordInvocation("UpdateRouteLabels", []interface{}{arg1, arg2, arg3}) fake.updateRouteLabelsMutex.Unlock() - if fake.UpdateRouteLabelsStub != nil { - return fake.UpdateRouteLabelsStub(arg1, arg2, arg3) + if stub != nil { + return stub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateRouteLabelsReturns return fakeReturns.result1, fakeReturns.result2 } @@ -574,15 +582,16 @@ func (fake *FakeSetLabelActor) UpdateServiceBrokerLabelsByServiceBrokerName(arg1 arg1 string arg2 map[string]types.NullString }{arg1, arg2}) + stub := fake.UpdateServiceBrokerLabelsByServiceBrokerNameStub + fakeReturns := fake.updateServiceBrokerLabelsByServiceBrokerNameReturns fake.recordInvocation("UpdateServiceBrokerLabelsByServiceBrokerName", []interface{}{arg1, arg2}) fake.updateServiceBrokerLabelsByServiceBrokerNameMutex.Unlock() - if fake.UpdateServiceBrokerLabelsByServiceBrokerNameStub != nil { - return fake.UpdateServiceBrokerLabelsByServiceBrokerNameStub(arg1, arg2) + if stub != nil { + return stub(arg1, arg2) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateServiceBrokerLabelsByServiceBrokerNameReturns return fakeReturns.result1, fakeReturns.result2 } @@ -639,15 +648,16 @@ func (fake *FakeSetLabelActor) UpdateServiceInstanceLabels(arg1 string, arg2 str arg2 string arg3 map[string]types.NullString }{arg1, arg2, arg3}) + stub := fake.UpdateServiceInstanceLabelsStub + fakeReturns := fake.updateServiceInstanceLabelsReturns fake.recordInvocation("UpdateServiceInstanceLabels", []interface{}{arg1, arg2, arg3}) fake.updateServiceInstanceLabelsMutex.Unlock() - if fake.UpdateServiceInstanceLabelsStub != nil { - return fake.UpdateServiceInstanceLabelsStub(arg1, arg2, arg3) + if stub != nil { + return stub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateServiceInstanceLabelsReturns return fakeReturns.result1, fakeReturns.result2 } @@ -704,15 +714,16 @@ func (fake *FakeSetLabelActor) UpdateServiceOfferingLabels(arg1 string, arg2 str arg2 string arg3 map[string]types.NullString }{arg1, arg2, arg3}) + stub := fake.UpdateServiceOfferingLabelsStub + fakeReturns := fake.updateServiceOfferingLabelsReturns fake.recordInvocation("UpdateServiceOfferingLabels", []interface{}{arg1, arg2, arg3}) fake.updateServiceOfferingLabelsMutex.Unlock() - if fake.UpdateServiceOfferingLabelsStub != nil { - return fake.UpdateServiceOfferingLabelsStub(arg1, arg2, arg3) + if stub != nil { + return stub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateServiceOfferingLabelsReturns return fakeReturns.result1, fakeReturns.result2 } @@ -770,15 +781,16 @@ func (fake *FakeSetLabelActor) UpdateServicePlanLabels(arg1 string, arg2 string, arg3 string arg4 map[string]types.NullString }{arg1, arg2, arg3, arg4}) + stub := fake.UpdateServicePlanLabelsStub + fakeReturns := fake.updateServicePlanLabelsReturns fake.recordInvocation("UpdateServicePlanLabels", []interface{}{arg1, arg2, arg3, arg4}) fake.updateServicePlanLabelsMutex.Unlock() - if fake.UpdateServicePlanLabelsStub != nil { - return fake.UpdateServicePlanLabelsStub(arg1, arg2, arg3, arg4) + if stub != nil { + return stub(arg1, arg2, arg3, arg4) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateServicePlanLabelsReturns return fakeReturns.result1, fakeReturns.result2 } @@ -835,15 +847,16 @@ func (fake *FakeSetLabelActor) UpdateSpaceLabelsBySpaceName(arg1 string, arg2 st arg2 string arg3 map[string]types.NullString }{arg1, arg2, arg3}) + stub := fake.UpdateSpaceLabelsBySpaceNameStub + fakeReturns := fake.updateSpaceLabelsBySpaceNameReturns fake.recordInvocation("UpdateSpaceLabelsBySpaceName", []interface{}{arg1, arg2, arg3}) fake.updateSpaceLabelsBySpaceNameMutex.Unlock() - if fake.UpdateSpaceLabelsBySpaceNameStub != nil { - return fake.UpdateSpaceLabelsBySpaceNameStub(arg1, arg2, arg3) + if stub != nil { + return stub(arg1, arg2, arg3) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateSpaceLabelsBySpaceNameReturns return fakeReturns.result1, fakeReturns.result2 } @@ -899,15 +912,16 @@ func (fake *FakeSetLabelActor) UpdateStackLabelsByStackName(arg1 string, arg2 ma arg1 string arg2 map[string]types.NullString }{arg1, arg2}) + stub := fake.UpdateStackLabelsByStackNameStub + fakeReturns := fake.updateStackLabelsByStackNameReturns fake.recordInvocation("UpdateStackLabelsByStackName", []interface{}{arg1, arg2}) fake.updateStackLabelsByStackNameMutex.Unlock() - if fake.UpdateStackLabelsByStackNameStub != nil { - return fake.UpdateStackLabelsByStackNameStub(arg1, arg2) + if stub != nil { + return stub(arg1, arg2) } if specificReturn { return ret.result1, ret.result2 } - fakeReturns := fake.updateStackLabelsByStackNameReturns return fakeReturns.result1, fakeReturns.result2 } @@ -963,8 +977,8 @@ func (fake *FakeSetLabelActor) Invocations() map[string][][]interface{} { defer fake.getCurrentUserMutex.RUnlock() fake.updateApplicationLabelsByApplicationNameMutex.RLock() defer fake.updateApplicationLabelsByApplicationNameMutex.RUnlock() - fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RLock() - defer fake.updateBuildpackLabelsByBuildpackNameAndStackMutex.RUnlock() + fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RLock() + defer fake.updateBuildpackLabelsByBuildpackNameAndStackAndLifecycleMutex.RUnlock() fake.updateDomainLabelsByDomainNameMutex.RLock() defer fake.updateDomainLabelsByDomainNameMutex.RUnlock() fake.updateOrganizationLabelsByOrganizationNameMutex.RLock() diff --git a/integration/helpers/buildpack.go b/integration/helpers/buildpack.go index 0540c92cfe0..419fa08c898 100644 --- a/integration/helpers/buildpack.go +++ b/integration/helpers/buildpack.go @@ -1,6 +1,7 @@ package helpers import ( + "archive/tar" "encoding/json" "fmt" "os" @@ -68,15 +69,66 @@ func SetupBuildpackWithoutStack(buildpackName string) { SetupBuildpackWithStack(buildpackName, "") } +// CNB makes a simple cnb (using +// MakeCNBArchive) and yields it to the given function, removing the cnb file +// at the end. +func CNB(f func(buildpackArchive string)) { + cnbArchive := MakeCNBArchive() + defer os.Remove(cnbArchive) + + f(cnbArchive) +} + +// MakeCNBArchive makes a simple buildpack cnb file for a given stack. +func MakeCNBArchive() string { + archiveDir, err := os.MkdirTemp("", "cnb-archive-file-") + Expect(err).ToNot(HaveOccurred()) + + archiveFile, err := os.Create(filepath.Join(archiveDir, "buildpack.cnb")) + Expect(err).ToNot(HaveOccurred()) + defer archiveFile.Close() + + tarWriter := tar.NewWriter(archiveFile) + defer tarWriter.Close() + + manifestBytes := []byte(`{"schemaVersion": 2,"mediaType": "application/vnd.oci.image.index.v1+json","manifests": []}`) + err = tarWriter.WriteHeader(&tar.Header{ + Name: "index.json", + Mode: 0666, + Size: int64(len(manifestBytes)), + }) + Expect(err).ToNot(HaveOccurred()) + + _, err = tarWriter.Write(manifestBytes) + Expect(err).ToNot(HaveOccurred()) + + layoutBytes := []byte(`{"imageLayoutVersion": "1.0.0"}`) + err = tarWriter.WriteHeader(&tar.Header{ + Name: "oci-layout", + Mode: 0666, + Size: int64(len(layoutBytes)), + }) + Expect(err).ToNot(HaveOccurred()) + + _, err = tarWriter.Write(layoutBytes) + Expect(err).ToNot(HaveOccurred()) + + err = tarWriter.Flush() + Expect(err).ToNot(HaveOccurred()) + + return archiveFile.Name() +} + // BuildpackFields represents a buildpack, displayed in the 'cf buildpacks' // command. type BuildpackFields struct { - Position string - Name string - Enabled string - Locked string - Filename string - Stack string + Position string + Name string + Enabled string + Locked string + Filename string + Stack string + Lifecycle string } // DeleteBuildpackIfOnOldCCAPI deletes the buildpack if the CC API targeted diff --git a/integration/v7/global/create_buildpack_command_test.go b/integration/v7/global/create_buildpack_command_test.go index 474dab02cfd..d6369ab2d09 100644 --- a/integration/v7/global/create_buildpack_command_test.go +++ b/integration/v7/global/create_buildpack_command_test.go @@ -32,11 +32,12 @@ var _ = Describe("create buildpack command", func() { Eventually(session).Should(Say("NAME:")) Eventually(session).Should(Say("create-buildpack - Create a buildpack")) Eventually(session).Should(Say("USAGE:")) - Eventually(session).Should(Say(`cf create-buildpack BUILDPACK PATH POSITION \[--disable\]`)) + Eventually(session).Should(Say(`cf create-buildpack BUILDPACK PATH POSITION \[--disable\] \[--lifecycle buildpack|cnb\]`)) Eventually(session).Should(Say("TIP:")) - Eventually(session).Should(Say("Path should be a zip file, a url to a zip file, or a local directory. Position is a positive integer, sets priority, and is sorted from lowest to highest.")) + Eventually(session).Should(Say("When using the 'buildpack' lifecycle type, Path should be a zip file, a url to a zip file, or a local directory. When using the 'cnb' lifecycle, Path should be a cnb file or gzipped oci image. Position is a positive integer, sets priority, and is sorted from lowest to highest.")) Eventually(session).Should(Say("OPTIONS:")) Eventually(session).Should(Say(`--disable\s+Disable the buildpack from being used for staging`)) + Eventually(session).Should(Say(`--lifecycle, -l\s+Lifecycle that the buildpack will use`)) Eventually(session).Should(Say("SEE ALSO:")) Eventually(session).Should(Say("buildpacks, push")) Eventually(session).Should(Exit(0)) @@ -117,7 +118,7 @@ var _ = Describe("create buildpack command", func() { }) }) - When("uploading from a zip", func() { + When("uploading from a zip with lifecycle 'buildpack'", func() { var stacks []string BeforeEach(func() { @@ -295,15 +296,43 @@ var _ = Describe("create buildpack command", func() { }) }) }) + }) - When("specifying an invalid path", func() { - It("returns the appropriate error", func() { - session := helpers.CF("create-buildpack", buildpackName, "bogus-path", "1") + When("uploading from a cnb file with lifecycle 'buildpack'", func() { + BeforeEach(func() { + helpers.SkipIfVersionLessThan("3.194.0") + }) + When("specifying a valid path", func() { + When("the new buildpack is unique", func() { + When("the new buildpack has a nil stack", func() { + It("successfully uploads a buildpack", func() { + helpers.CNB(func(buildpackPath string) { + session := helpers.CF("create-buildpack", buildpackName, buildpackPath, "1", "--lifecycle=cnb") + Eventually(session).Should(Say(`Creating buildpack %s as %s\.\.\.`, buildpackName, username)) + Eventually(session).Should(Say("OK")) + Eventually(session).Should(Say(`Uploading buildpack %s as %s\.\.\.`, buildpackName, username)) + Eventually(session).Should(Say("OK")) + Eventually(session).Should(Exit(0)) + }) - Eventually(session.Err).Should(Say("Incorrect Usage: The specified path 'bogus-path' does not exist")) - Eventually(session).Should(Say("USAGE:")) - Eventually(session).Should(Exit(1)) + session := helpers.CF("buildpacks") + Eventually(session).Should(Say(helpers.BuildpacksOutputRegex(helpers.BuildpackFields{ + Name: buildpackName, Position: "1"}))) + Eventually(session).Should(Exit(0)) + }) + }) }) + + }) + }) + + When("specifying an invalid path", func() { + It("returns the appropriate error", func() { + session := helpers.CF("create-buildpack", buildpackName, "bogus-path", "1") + + Eventually(session.Err).Should(Say("Incorrect Usage: The specified path 'bogus-path' does not exist")) + Eventually(session).Should(Say("USAGE:")) + Eventually(session).Should(Exit(1)) }) }) diff --git a/integration/v7/global/delete_buildpack_command_test.go b/integration/v7/global/delete_buildpack_command_test.go index b00775a7ce4..620fe6a0b80 100644 --- a/integration/v7/global/delete_buildpack_command_test.go +++ b/integration/v7/global/delete_buildpack_command_test.go @@ -31,6 +31,7 @@ var _ = Describe("delete-buildpack command", func() { Eventually(session).Should(Say("OPTIONS:")) Eventually(session).Should(Say(`--force, -f\s+Force deletion without confirmation`)) Eventually(session).Should(Say(`--stack, -s\s+Specify stack to disambiguate buildpacks with the same name. Required when buildpack name is ambiguous`)) + Eventually(session).Should(Say(`--lifecycle, -l\s+Specify lifecycle to disambiguate buildpacks with the same name. Required when buildpack name is ambiguous`)) Eventually(session).Should(Say("\n")) Eventually(session).Should(Say("SEE ALSO:")) Eventually(session).Should(Say("buildpacks")) @@ -48,12 +49,12 @@ var _ = Describe("delete-buildpack command", func() { }) When("the buildpack doesn't exist", func() { - When("the user does not specify a stack", func() { + When("the user does not specify a stack or lifecycle", func() { It("displays a warning and exits 0", func() { session := helpers.CF("delete-buildpack", "-f", "nonexistent-buildpack") Eventually(session).Should(Say(`Deleting buildpack nonexistent-buildpack\.\.\.`)) Eventually(session).Should(Say("OK")) - Eventually(session.Err).Should(Say(`Buildpack 'nonexistent-buildpack' does not exist\.`)) + Eventually(session.Err).Should(Say(`Buildpack 'nonexistent-buildpack' not found\.`)) Eventually(session).Should(Exit(0)) }) }) @@ -71,6 +72,33 @@ var _ = Describe("delete-buildpack command", func() { Eventually(session).Should(Exit(0)) }) }) + + When("the user specifies a lifecycle", func() { + BeforeEach(func() { + helpers.SkipIfVersionLessThan("3.194.0") + }) + It("displays a warning and exits 0", func() { + session := helpers.CF("delete-buildpack", "-f", "nonexistent-buildpack", "-l", "buildpack") + Eventually(session).Should(Say(`Deleting buildpack nonexistent-buildpack with lifecycle buildpack\.\.\.`)) + Eventually(session).Should(Say("OK")) + Eventually(session.Err).Should(Say(`Buildpack 'nonexistent-buildpack' with lifecycle 'buildpack' not found\.`)) + Eventually(session).Should(Exit(0)) + }) + }) + When("the user specifies a stack and lifecycle", func() { + BeforeEach(func() { + helpers.SkipIfVersionLessThan("3.194.0") + stacks = helpers.FetchStacks() + }) + + It("displays a warning and exits 0", func() { + session := helpers.CF("delete-buildpack", "-f", "nonexistent-buildpack", "-s", stacks[0], "-l", "buildpack") + Eventually(session).Should(Say(`Deleting buildpack nonexistent-buildpack with stack %s with lifecycle buildpack\.\.\.`, stacks[0])) + Eventually(session).Should(Say("OK")) + Eventually(session.Err).Should(Say(`Buildpack 'nonexistent-buildpack' with stack '%s' with lifecycle 'buildpack' does not exist\.`, stacks[0])) + Eventually(session).Should(Exit(0)) + }) + }) }) Context("there is exactly one buildpack with the specified name", func() { @@ -121,7 +149,7 @@ var _ = Describe("delete-buildpack command", func() { By("failing when no stack specified") session := helpers.CF("delete-buildpack", buildpackName, "-f") - Eventually(session.Err).Should(Say("Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag.", buildpackName)) + Eventually(session.Err).Should(Say("Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag and/or lifecycle using a '-l' flag.", buildpackName)) Eventually(session).Should(Exit(1)) By("succeeding with warning when the buildpack name matches but the stack does not") diff --git a/integration/v7/global/update_buildpack_command_test.go b/integration/v7/global/update_buildpack_command_test.go index 8409fd6c447..a85a193059f 100644 --- a/integration/v7/global/update_buildpack_command_test.go +++ b/integration/v7/global/update_buildpack_command_test.go @@ -34,7 +34,7 @@ var _ = Describe("update-buildpack command", func() { Eventually(session).Should(Say("USAGE:")) Eventually(session).Should(Say(regexp.QuoteMeta(`cf update-buildpack BUILDPACK [-p PATH | -s STACK | --assign-stack NEW_STACK] [-i POSITION] [--rename NEW_NAME] [--enable|--disable] [--lock|--unlock]`))) Eventually(session).Should(Say("TIP:")) - Eventually(session).Should(Say("Path should be a zip file, a url to a zip file, or a local directory. Position is a positive integer, sets priority, and is sorted from lowest to highest.\n\n")) + Eventually(session).Should(Say("When using the 'buildpack' lifecycle type, Path should be a zip file, a url to a zip file, or a local directory. When using the 'cnb' lifecycle, Path should be a cnb file or gzipped oci image. Position is a positive integer, sets priority, and is sorted from lowest to highest.\n\n")) Eventually(session).Should(Say("Use '--assign-stack' with caution. Associating a buildpack with a stack that it does not support may result in undefined behavior. Additionally, changing this association once made may require a local copy of the buildpack.\n\n")) Eventually(session).Should(Say("OPTIONS:")) Eventually(session).Should(Say(`--assign-stack\s+Assign a stack to a buildpack that does not have a stack association`)) @@ -45,6 +45,7 @@ var _ = Describe("update-buildpack command", func() { Eventually(session).Should(Say(`--position, -i\s+The order in which the buildpacks are checked during buildpack auto-detection`)) Eventually(session).Should(Say(`--rename\s+Rename an existing buildpack`)) Eventually(session).Should(Say(`--stack, -s\s+Specify stack to disambiguate buildpacks with the same name`)) + Eventually(session).Should(Say(`--lifecycle, -l\s+Specify lifecycle to disambiguate buildpacks with the same name`)) Eventually(session).Should(Say(`--unlock\s+Unlock the buildpack to enable updates`)) Eventually(session).Should(Say("SEE ALSO:")) Eventually(session).Should(Say("buildpacks, create-buildpack, delete-buildpack")) @@ -170,7 +171,7 @@ var _ = Describe("update-buildpack command", func() { It("displays an error saying that multiple buildpacks were found", func() { session := helpers.CF("update-buildpack", buildpackName) - Eventually(session.Err).Should(Say(`Multiple buildpacks named %s found\. Specify a stack name by using a '-s' flag\.`, buildpackName)) + Eventually(session.Err).Should(Say(`Multiple buildpacks named %s found\. Specify a stack name by using a '-s' flag and/or lifecycle using a '-l' flag\.`, buildpackName)) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) diff --git a/integration/v7/isolated/labels_command_test.go b/integration/v7/isolated/labels_command_test.go index c8182e00285..90b25f50baa 100644 --- a/integration/v7/isolated/labels_command_test.go +++ b/integration/v7/isolated/labels_command_test.go @@ -247,14 +247,14 @@ var _ = Describe("labels command", func() { It("fails when no stack is given", func() { session := helpers.CF("labels", "buildpack", buildpackName) - Eventually(session.Err).Should(Say(fmt.Sprintf(`Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag.`, buildpackName))) + Eventually(session.Err).Should(Say(fmt.Sprintf(`Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag and/or lifecycle using a '-l' flag.`, buildpackName))) Eventually(session).Should(Say(`FAILED`)) Eventually(session).Should(Exit(1)) }) It("fails when an empty-string stack is given", func() { session := helpers.CF("labels", "buildpack", buildpackName, "--stack", "") - Eventually(session.Err).Should(Say(fmt.Sprintf(`Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag.`, buildpackName))) + Eventually(session.Err).Should(Say(fmt.Sprintf(`Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag and/or lifecycle using a '-l' flag.`, buildpackName))) Eventually(session).Should(Say(`FAILED`)) Eventually(session).Should(Exit(1)) }) diff --git a/integration/v7/isolated/set_label_command_test.go b/integration/v7/isolated/set_label_command_test.go index fac616d7a22..b5b921135ae 100644 --- a/integration/v7/isolated/set_label_command_test.go +++ b/integration/v7/isolated/set_label_command_test.go @@ -427,7 +427,7 @@ var _ = Describe("set-label command", func() { When("stack is not specified", func() { It("displays an error", func() { session := helpers.CF("set-label", "buildpack", buildpackName, "some-key=some-value") - Eventually(session.Err).Should(Say(fmt.Sprintf("Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag.", buildpackName))) + Eventually(session.Err).Should(Say(fmt.Sprintf("Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag and/or lifecycle using a '-l' flag.", buildpackName))) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) @@ -504,7 +504,7 @@ var _ = Describe("set-label command", func() { When("no stack is specified", func() { It("displays an error", func() { session := helpers.CF("set-label", "buildpack", buildpackName, "some-key=some-value") - Eventually(session.Err).Should(Say(fmt.Sprintf("Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag.", buildpackName))) + Eventually(session.Err).Should(Say(fmt.Sprintf("Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag and/or lifecycle using a '-l' flag.", buildpackName))) Eventually(session).Should(Say("FAILED")) Eventually(session).Should(Exit(1)) }) diff --git a/integration/v7/isolated/unset_label_command_test.go b/integration/v7/isolated/unset_label_command_test.go index 114e40e60ca..d8c508c5423 100644 --- a/integration/v7/isolated/unset_label_command_test.go +++ b/integration/v7/isolated/unset_label_command_test.go @@ -174,7 +174,7 @@ var _ = Describe("unset-label command", func() { It("displays an error", func() { session := helpers.CF("unset-label", "buildpack", buildpackName, "pci") Eventually(session).Should(Exit(1)) - Expect(session.Err).Should(Say(fmt.Sprintf("Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag.", buildpackName))) + Expect(session.Err).Should(Say(fmt.Sprintf("Multiple buildpacks named %s found. Specify a stack name by using a '-s' flag and/or lifecycle using a '-l' flag.", buildpackName))) Expect(session).Should(Say("FAILED")) }) }) diff --git a/resources/buildpack_resource.go b/resources/buildpack_resource.go index 04d29e271c2..50897f09b28 100644 --- a/resources/buildpack_resource.go +++ b/resources/buildpack_resource.go @@ -31,20 +31,24 @@ type Buildpack struct { Links APILinks // Metadata is used for custom tagging of API resources Metadata *Metadata + // Lifecycle is the lifecycle used with this buildpack + Lifecycle string } // MarshalJSON converts a Package into a Cloud Controller Package. func (buildpack Buildpack) MarshalJSON() ([]byte, error) { ccBuildpack := struct { - Name string `json:"name,omitempty"` - Stack string `json:"stack,omitempty"` - Position *int `json:"position,omitempty"` - Enabled *bool `json:"enabled,omitempty"` - Locked *bool `json:"locked,omitempty"` - Metadata *Metadata `json:"metadata,omitempty"` + Name string `json:"name,omitempty"` + Stack string `json:"stack,omitempty"` + Position *int `json:"position,omitempty"` + Enabled *bool `json:"enabled,omitempty"` + Locked *bool `json:"locked,omitempty"` + Metadata *Metadata `json:"metadata,omitempty"` + Lifecycle string `json:"lifecycle,omitempty"` }{ - Name: buildpack.Name, - Stack: buildpack.Stack, + Name: buildpack.Name, + Stack: buildpack.Stack, + Lifecycle: buildpack.Lifecycle, } if buildpack.Position.IsSet { @@ -62,16 +66,17 @@ func (buildpack Buildpack) MarshalJSON() ([]byte, error) { func (buildpack *Buildpack) UnmarshalJSON(data []byte) error { var ccBuildpack struct { - GUID string `json:"guid,omitempty"` - Links APILinks `json:"links,omitempty"` - Name string `json:"name,omitempty"` - Filename string `json:"filename,omitempty"` - Stack string `json:"stack,omitempty"` - State string `json:"state,omitempty"` - Enabled types.NullBool `json:"enabled"` - Locked types.NullBool `json:"locked"` - Position types.NullInt `json:"position"` - Metadata *Metadata `json:"metadata"` + GUID string `json:"guid,omitempty"` + Links APILinks `json:"links,omitempty"` + Name string `json:"name,omitempty"` + Filename string `json:"filename,omitempty"` + Stack string `json:"stack,omitempty"` + State string `json:"state,omitempty"` + Enabled types.NullBool `json:"enabled"` + Locked types.NullBool `json:"locked"` + Position types.NullInt `json:"position"` + Metadata *Metadata `json:"metadata"` + Lifecycle string `json:"lifecycle"` } err := cloudcontroller.DecodeJSON(data, &ccBuildpack) @@ -89,6 +94,7 @@ func (buildpack *Buildpack) UnmarshalJSON(data []byte) error { buildpack.State = ccBuildpack.State buildpack.Links = ccBuildpack.Links buildpack.Metadata = ccBuildpack.Metadata + buildpack.Lifecycle = ccBuildpack.Lifecycle return nil }