From 015745d6c8ee28a710da4d81eeb6e53c1c886e65 Mon Sep 17 00:00:00 2001 From: Enrique Encalada Date: Wed, 17 Feb 2021 18:10:00 +0100 Subject: [PATCH] Ensure proper code coverage This add new unit-tests to ensure a decent code coverage for all the different classes under the resource pkg of buildrun. --- pkg/reconciler/buildrun/controller.go | 5 - pkg/reconciler/buildrun/resources/build.go | 5 +- .../buildrun/resources/build_test.go | 118 +++++++++++++ .../buildrun/resources/conditions.go | 2 +- .../buildrun/resources/conditions_test.go | 162 ++++++++++++++++++ .../buildrun/resources/errors_test.go | 26 +++ .../resources/resources_suite_test.go | 3 + .../buildrun/resources/service_accounts.go | 4 +- .../resources/service_accounts_test.go | 61 +++++++ .../buildrun/resources/strategies.go | 6 +- .../buildrun/resources/strategies_test.go | 71 ++++++++ test/catalog.go | 70 ++++++++ 12 files changed, 518 insertions(+), 15 deletions(-) create mode 100644 pkg/reconciler/buildrun/resources/build_test.go create mode 100644 pkg/reconciler/buildrun/resources/errors_test.go create mode 100644 pkg/reconciler/buildrun/resources/service_accounts_test.go create mode 100644 pkg/reconciler/buildrun/resources/strategies_test.go diff --git a/pkg/reconciler/buildrun/controller.go b/pkg/reconciler/buildrun/controller.go index 3315171cb7..ac66a3e4bc 100644 --- a/pkg/reconciler/buildrun/controller.go +++ b/pkg/reconciler/buildrun/controller.go @@ -27,11 +27,6 @@ import ( "github.com/shipwright-io/build/pkg/ctxlog" ) -/** -* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller -* business logic. Delete these comments after modifying this file.* - */ - type setOwnerReferenceFunc func(owner, object metav1.Object, scheme *runtime.Scheme) error // Add creates a new BuildRun Controller and adds it to the Manager. The Manager will set fields on the Controller diff --git a/pkg/reconciler/buildrun/resources/build.go b/pkg/reconciler/buildrun/resources/build.go index ed814b2450..3bfb640e24 100644 --- a/pkg/reconciler/buildrun/resources/build.go +++ b/pkg/reconciler/buildrun/resources/build.go @@ -15,10 +15,7 @@ import ( // GetBuildObject retrieves an existing Build based on a name and namespace func GetBuildObject(ctx context.Context, client client.Client, objectName string, objectNS string, build *buildv1alpha1.Build) error { - if err := client.Get(ctx, types.NamespacedName{Name: objectName, Namespace: objectNS}, build); err != nil { - return err - } - return nil + return client.Get(ctx, types.NamespacedName{Name: objectName, Namespace: objectNS}, build) } // IsOwnedByBuild checks if the controllerReferences contains a well known owner Kind diff --git a/pkg/reconciler/buildrun/resources/build_test.go b/pkg/reconciler/buildrun/resources/build_test.go new file mode 100644 index 0000000000..3b076c17ff --- /dev/null +++ b/pkg/reconciler/buildrun/resources/build_test.go @@ -0,0 +1,118 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package resources_test + +import ( + "context" + "errors" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" + "github.com/shipwright-io/build/pkg/controller/fakes" + "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" + "github.com/shipwright-io/build/test" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" +) + +var _ = Describe("Build Resource", func() { + + var ( + client *fakes.FakeClient + ctl test.Catalog + buildName string + ) + + Context("Operating on Build resources", func() { + // init vars + buildName = "foobuild" + client = &fakes.FakeClient{} + + It("should be able to retrieve a build object if exists", func() { + buildSample := ctl.DefaultBuild(buildName, "foostrategy", build.ClusterBuildStrategyKind) + + // stub a GET API call with buildSample contents + getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error { + switch object := object.(type) { + case *build.Build: + buildSample.DeepCopyInto(object) + return nil + } + return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name) + } + + // fake the calls with the above stub definition + client.GetCalls(getClientStub) + + build := &build.Build{} + Expect(resources.GetBuildObject(context.TODO(), client, buildName, "default", build)).To(BeNil()) + }) + It("should not retrieve a missing build object when missing", func() { + // stub a GET API call with buildSample contents that returns "not found" + getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error { + switch object.(type) { + case *build.Build: + return errors.New("not found") + } + return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name) + } + // fake the calls with the above stub + client.GetCalls(getClientStub) + + build := &build.Build{} + Expect(resources.GetBuildObject(context.TODO(), client, buildName, "default", build)).ToNot(BeNil()) + }) + It("should be able to verify valid ownerships", func() { + managingController := true + + buildSample := &build.Build{ + TypeMeta: metav1.TypeMeta{ + Kind: "fakekind", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: buildName, + }, + } + // fake an instance of OwnerReference with a + // well known fake Kind and Name + fakeOwnerRef := []metav1.OwnerReference{ + { + Kind: "fakekind", + Name: buildName, + Controller: &managingController, + }, + } + // Assert that our Build is owned by an owner + Expect(resources.IsOwnedByBuild(buildSample, fakeOwnerRef)).To(BeTrue()) + }) + It("should be able to verify invalid ownerships", func() { + managingController := true + + buildSample := &build.Build{ + TypeMeta: metav1.TypeMeta{ + Kind: "notthatkind", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: buildName, + }, + } + // fake an instance of OwnerReference with a + // well known fake Kind and Name + fakeOwnerRef := []metav1.OwnerReference{ + { + Kind: "fakekind", + Name: buildName, + Controller: &managingController, + }, + } + // Assert that our Build is not owned by an owner + Expect(resources.IsOwnedByBuild(buildSample, fakeOwnerRef)).To(BeFalse()) + }) + }) +}) diff --git a/pkg/reconciler/buildrun/resources/conditions.go b/pkg/reconciler/buildrun/resources/conditions.go index 4a8484fe95..783f5e0c8e 100644 --- a/pkg/reconciler/buildrun/resources/conditions.go +++ b/pkg/reconciler/buildrun/resources/conditions.go @@ -28,7 +28,7 @@ func UpdateBuildRunUsingTaskRunCondition(ctx context.Context, client client.Clie case v1beta1.TaskRunReasonTimedOut: reason = "BuildRunTimeout" message = fmt.Sprintf("BuildRun %s failed to finish within %s", - taskRun.GetLabels()[buildv1alpha1.LabelBuildRun], + buildRun.Name, taskRun.Spec.Timeout.Duration, ) diff --git a/pkg/reconciler/buildrun/resources/conditions_test.go b/pkg/reconciler/buildrun/resources/conditions_test.go index 5d6df20808..4f26af1b1d 100644 --- a/pkg/reconciler/buildrun/resources/conditions_test.go +++ b/pkg/reconciler/buildrun/resources/conditions_test.go @@ -5,12 +5,22 @@ package resources_test import ( + "context" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" + "github.com/shipwright-io/build/pkg/controller/fakes" + "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" "github.com/shipwright-io/build/test" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "knative.dev/pkg/apis" ) var _ = Describe("Conditions", func() { @@ -101,5 +111,157 @@ var _ = Describe("Conditions", func() { condMsg := br.Status.GetCondition(build.Succeeded).GetMessage() Expect(condMsg).To(Equal("foobar was updated")) }) + + }) + Context("Operating with TaskRun Conditions", func() { + var ( + client *fakes.FakeClient + ctl test.Catalog + br *build.BuildRun + tr *v1beta1.TaskRun + ) + + tr = ctl.TaskRunWithStatus("foo", "bar") + br = ctl.DefaultBuildRun("foo", "bar") + client = &fakes.FakeClient{} + + It("updates BuildRun condition when TaskRun timeout", func() { + + fakeTRCondition := &apis.Condition{ + Type: apis.ConditionSucceeded, + Reason: "TaskRunTimeout", + Message: "not relevant", + } + + Expect(resources.UpdateBuildRunUsingTaskRunCondition( + context.TODO(), + client, + br, + tr, + fakeTRCondition, + )).To(BeNil()) + }) + + It("updates BuildRun condition when TaskRun fails and pod not found", func() { + + // stub a GET API call that fails with not found + getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error { + switch object.(type) { + case *corev1.Pod: + return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name) + } + return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name) + } + // fake the calls with the above stub + client.GetCalls(getClientStub) + + fakeTRCondition := &apis.Condition{ + Type: apis.ConditionSucceeded, + Reason: "Failed", + Message: "not relevant", + } + + Expect(resources.UpdateBuildRunUsingTaskRunCondition( + context.TODO(), + client, + br, + tr, + fakeTRCondition, + )).To(BeNil()) + }) + + It("updates a BuildRun condition when the related TaskRun fails and pod containers are available", func() { + + // generate a pod that have a single container and + // one entry in the ContainerStatuses field, with + // an exitCode + taskRunGeneratedPod := corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foopod", + }, + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "foobar-container", + }, + }, + }, + Status: corev1.PodStatus{ + ContainerStatuses: []corev1.ContainerStatus{ + { + Name: "foobar-container", + State: corev1.ContainerState{ + Terminated: &corev1.ContainerStateTerminated{ + Reason: "foobar", + ExitCode: 1, + }, + }, + }, + }, + }, + } + + // stub a GET API call with taskRunGeneratedPod + getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error { + switch object := object.(type) { + case *corev1.Pod: + taskRunGeneratedPod.DeepCopyInto(object) + return nil + } + return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name) + } + + // fake the calls with the above stub + client.GetCalls(getClientStub) + + fakeTRCondition := &apis.Condition{ + Type: apis.ConditionSucceeded, + Reason: "Failed", + Message: "not relevant", + } + + Expect(resources.UpdateBuildRunUsingTaskRunCondition( + context.TODO(), + client, + br, + tr, + fakeTRCondition, + )).To(BeNil()) + }) + + It("updates a BuildRun condition when the related TaskRun fails and pod containers are not available", func() { + + taskRunGeneratedPod := corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foobar", + }, + } + + // stub a GET API call with the above taskRunGeneratedPod spec + getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error { + switch object := object.(type) { + case *corev1.Pod: + taskRunGeneratedPod.DeepCopyInto(object) + return nil + } + return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name) + } + // fake the calls with the above stub + client.GetCalls(getClientStub) + + fakeTRCondition := &apis.Condition{ + Type: apis.ConditionSucceeded, + Reason: "Failed", + Message: "not relevant", + } + + Expect(resources.UpdateBuildRunUsingTaskRunCondition( + context.TODO(), + client, + br, + tr, + fakeTRCondition, + )).To(BeNil()) + }) }) }) diff --git a/pkg/reconciler/buildrun/resources/errors_test.go b/pkg/reconciler/buildrun/resources/errors_test.go new file mode 100644 index 0000000000..c4be5db77f --- /dev/null +++ b/pkg/reconciler/buildrun/resources/errors_test.go @@ -0,0 +1,26 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package resources_test + +import ( + "errors" + "fmt" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" +) + +var _ = Describe("Multiple errors", func() { + Context("Dealing with multiple errors", func() { + It("should handle multiple errors", func() { + error01 := errors.New("error01") + error02 := errors.New("error02") + msg := "handling multiple errors" + customError := resources.HandleError(msg, error01, error02) + Expect(customError).To(Equal(fmt.Errorf("errors: %s, %s, msg: %s", error01, error02, msg))) + }) + }) +}) diff --git a/pkg/reconciler/buildrun/resources/resources_suite_test.go b/pkg/reconciler/buildrun/resources/resources_suite_test.go index 3b4f1a6335..366c43c21c 100644 --- a/pkg/reconciler/buildrun/resources/resources_suite_test.go +++ b/pkg/reconciler/buildrun/resources/resources_suite_test.go @@ -1,3 +1,6 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 package resources_test import ( diff --git a/pkg/reconciler/buildrun/resources/service_accounts.go b/pkg/reconciler/buildrun/resources/service_accounts.go index 65be082e29..513edab652 100644 --- a/pkg/reconciler/buildrun/resources/service_accounts.go +++ b/pkg/reconciler/buildrun/resources/service_accounts.go @@ -38,7 +38,9 @@ func IsGeneratedServiceAccountUsed(buildRun *buildv1alpha1.BuildRun) bool { return buildRun.Spec.ServiceAccount != nil && buildRun.Spec.ServiceAccount.Generate } -// RetrieveServiceAccount ... +// RetrieveServiceAccount provides either a default sa with a referenced secret or it will generate a new sa on the fly. +// When not using the generate feature, it will modify and return the default sa from a k8s namespace, which is "default" +// or the default sa inside an openshift namespace, which is "pipeline". func RetrieveServiceAccount(ctx context.Context, client client.Client, build *buildv1alpha1.Build, buildRun *buildv1alpha1.BuildRun) (*corev1.ServiceAccount, error) { serviceAccount := &corev1.ServiceAccount{} diff --git a/pkg/reconciler/buildrun/resources/service_accounts_test.go b/pkg/reconciler/buildrun/resources/service_accounts_test.go new file mode 100644 index 0000000000..b9154f1f8a --- /dev/null +++ b/pkg/reconciler/buildrun/resources/service_accounts_test.go @@ -0,0 +1,61 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package resources_test + +import ( + "context" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/shipwright-io/build/pkg/controller/fakes" + "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" + "github.com/shipwright-io/build/test" + corev1 "k8s.io/api/core/v1" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" +) + +var _ = Describe("Operating service accounts", func() { + var ( + client *fakes.FakeClient + ctl test.Catalog + buildName, buildRunName string + ) + + Context("Retrieving service accounts", func() { + + // init vars + buildName = "foobuild" + buildRunName = "foobuildrun" + client = &fakes.FakeClient{} + buildRunSample := ctl.DefaultBuildRun(buildRunName, buildName) + + It("should return a modified one with a secret ref", func() { + + // stub a GET API call for a service account + getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error { + switch object := object.(type) { + case *corev1.ServiceAccount: + ctl.DefaultServiceAccount("foobar").DeepCopyInto(object) + return nil + } + return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name) + } + // fake the calls with the above stub + client.GetCalls(getClientStub) + + sa, err := resources.RetrieveServiceAccount(context.TODO(), client, ctl.BuildWithOutputSecret(buildName, "default", "foosecret"), buildRunSample) + Expect(err).To(BeNil()) + // assert the build output secret is defined in the default SA + Expect(len(sa.Secrets)).To(Equal(1)) + }) + + It("should provide a generated sa name", func() { + Expect(resources.GetGeneratedServiceAccountName(buildRunSample)).To(Equal(buildRunSample.Name + "-sa")) + }) + }) +}) diff --git a/pkg/reconciler/buildrun/resources/strategies.go b/pkg/reconciler/buildrun/resources/strategies.go index 44733a5099..cbebb58111 100644 --- a/pkg/reconciler/buildrun/resources/strategies.go +++ b/pkg/reconciler/buildrun/resources/strategies.go @@ -19,8 +19,7 @@ func RetrieveBuildStrategy(ctx context.Context, client client.Client, build *bui buildStrategyInstance := &buildv1alpha1.BuildStrategy{} ctxlog.Debug(ctx, "retrieving BuildStrategy", namespace, build.Namespace, name, build.Name) - err := client.Get(ctx, types.NamespacedName{Name: build.Spec.StrategyRef.Name, Namespace: build.Namespace}, buildStrategyInstance) - if err != nil { + if err := client.Get(ctx, types.NamespacedName{Name: build.Spec.StrategyRef.Name, Namespace: build.Namespace}, buildStrategyInstance); err != nil { return nil, err } return buildStrategyInstance, nil @@ -31,8 +30,7 @@ func RetrieveClusterBuildStrategy(ctx context.Context, client client.Client, bui clusterBuildStrategyInstance := &buildv1alpha1.ClusterBuildStrategy{} ctxlog.Debug(ctx, "retrieving ClusterBuildStrategy", namespace, build.Namespace, name, build.Name) - err := client.Get(ctx, types.NamespacedName{Name: build.Spec.StrategyRef.Name}, clusterBuildStrategyInstance) - if err != nil { + if err := client.Get(ctx, types.NamespacedName{Name: build.Spec.StrategyRef.Name}, clusterBuildStrategyInstance); err != nil { return nil, err } return clusterBuildStrategyInstance, nil diff --git a/pkg/reconciler/buildrun/resources/strategies_test.go b/pkg/reconciler/buildrun/resources/strategies_test.go new file mode 100644 index 0000000000..d144213295 --- /dev/null +++ b/pkg/reconciler/buildrun/resources/strategies_test.go @@ -0,0 +1,71 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package resources_test + +import ( + "context" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" + "github.com/shipwright-io/build/pkg/controller/fakes" + "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" + "github.com/shipwright-io/build/test" + k8serrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" +) + +var _ = Describe("Operating Build strategies", func() { + var ( + client *fakes.FakeClient + ctl test.Catalog + ) + + Context("Retrieving build strategies", func() { + client = &fakes.FakeClient{} + buildSample := ctl.BuildWithBuildStrategy("foobuild", "foostrategy", "foostrategy") + + It("should return a cluster buildstrategy", func() { + + // stub a GET API call with a cluster strategy + getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error { + switch object := object.(type) { + case *buildv1alpha1.ClusterBuildStrategy: + ctl.DefaultClusterBuildStrategy().DeepCopyInto(object) + return nil + } + return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name) + } + // fake the calls with the above stub + client.GetCalls(getClientStub) + + cbs, err := resources.RetrieveClusterBuildStrategy(context.TODO(), client, buildSample) + Expect(err).To(BeNil()) + Expect(cbs.Name).To(Equal("foobar")) + }) + + It("should return a namespaced buildstrategy", func() { + + // stub a GET API call with a namespace strategy + getClientStub := func(context context.Context, nn types.NamespacedName, object runtime.Object) error { + switch object := object.(type) { + case *buildv1alpha1.BuildStrategy: + ctl.DefaultNamespacedBuildStrategy().DeepCopyInto(object) + return nil + } + return k8serrors.NewNotFound(schema.GroupResource{}, nn.Name) + } + // fake the calls with the above stub + client.GetCalls(getClientStub) + + cbs, err := resources.RetrieveBuildStrategy(context.TODO(), client, buildSample) + Expect(err).To(BeNil()) + Expect(cbs.Name).To(Equal("foobar")) + }) + + }) +}) diff --git a/test/catalog.go b/test/catalog.go index d2aa964ea6..00803cdc1f 100644 --- a/test/catalog.go +++ b/test/catalog.go @@ -165,6 +165,26 @@ func (c *Catalog) BuildWithNilBuildStrategyKind(name string, ns string, strategy } } +// BuildWithOutputSecret .... +func (c *Catalog) BuildWithOutputSecret(name string, ns string, secretName string) *build.Build { + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + Spec: build.BuildSpec{ + Source: build.GitSource{ + URL: "https://github.com/qu1queee/taxi", + }, + Output: build.Image{ + SecretRef: &corev1.LocalObjectReference{ + Name: secretName, + }, + }, + }, + } +} + // ClusterBuildStrategy to support tests func (c *Catalog) ClusterBuildStrategy(name string) *build.ClusterBuildStrategy { return &build.ClusterBuildStrategy{ @@ -450,6 +470,41 @@ func (c *Catalog) StubBuildCRDsPodAndTaskRun( } } +// TaskRunWithStatus returns a minimal tekton TaskRun with an Status +func (c *Catalog) TaskRunWithStatus(trName string, ns string) *v1beta1.TaskRun { + return &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: trName, + Namespace: ns, + }, + Spec: v1beta1.TaskRunSpec{ + Timeout: &metav1.Duration{ + Duration: time.Minute * 2, + }, + }, + Status: v1beta1.TaskRunStatus{ + Status: knativev1beta1.Status{ + Conditions: knativev1beta1.Conditions{ + { + Type: apis.ConditionSucceeded, + Reason: "Unknown", + Status: corev1.ConditionUnknown, + }, + }, + }, + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + PodName: "foobar-pod", + StartTime: &metav1.Time{ + Time: time.Now(), + }, + CompletionTime: &metav1.Time{ + Time: time.Now(), + }, + }, + }, + } +} + // DefaultTaskRunWithStatus returns a minimal tekton TaskRun with an Status func (c *Catalog) DefaultTaskRunWithStatus(trName string, buildRunName string, ns string, status corev1.ConditionStatus, reason string) *v1beta1.TaskRun { return &v1beta1.TaskRun{ @@ -739,6 +794,21 @@ func (c *Catalog) DefaultServiceAccount(name string) *corev1.ServiceAccount { } } +// ServiceAccountWithControllerRef ... TODO +func (c *Catalog) ServiceAccountWithControllerRef(name string) *corev1.ServiceAccount { + return &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + OwnerReferences: []metav1.OwnerReference{ + { + Name: "ss", + Kind: "BuildRun", + }, + }, + }, + } +} + // DefaultClusterBuildStrategy returns a minimal ClusterBuildStrategy // object with a inmutable name func (c *Catalog) DefaultClusterBuildStrategy() *build.ClusterBuildStrategy {