From 6368064444877e350cd00e2c4db0676d65ee1bf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Moreno=20Garc=C3=ADa?= Date: Wed, 29 Nov 2023 12:04:17 +0100 Subject: [PATCH] feat(RHTAPREL-714): add Tekton utilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The utilities added in this commit come from the shared-utils repository. In addition, the RPA already references the new Pipeline struct. Signed-off-by: David Moreno GarcĂ­a --- api/v1alpha1/releaseplanadmission_types.go | 10 +- .../releaseplanadmission/webhook_test.go | 14 +- api/v1alpha1/zz_generated.deepcopy.go | 6 +- ...udio.redhat.com_releaseplanadmissions.yaml | 68 ++-- .../appstudio.redhat.com_releaseplans.yaml | 5 - controllers/release/adapter.go | 10 +- controllers/release/adapter_test.go | 46 ++- controllers/releaseplan/adapter_test.go | 16 +- .../releaseplanadmission/adapter_test.go | 16 +- .../utils/predicates/predicates_test.go | 64 +-- go.mod | 2 +- loader/loader_test.go | 14 +- tekton/pipeline_run_test.go | 24 +- tekton/utils/{pipeline_ref.go => pipeline.go} | 38 +- tekton/utils/pipeline_run_builder.go | 236 +++++++++++ tekton/utils/pipeline_run_builder_test.go | 371 ++++++++++++++++++ ...{pipeline_ref_test.go => pipeline_test.go} | 2 +- tekton/utils/suite_test.go | 5 +- tekton/utils/zz_generated.deepcopy.go | 37 ++ 19 files changed, 833 insertions(+), 151 deletions(-) rename tekton/utils/{pipeline_ref.go => pipeline.go} (69%) create mode 100644 tekton/utils/pipeline_run_builder.go create mode 100644 tekton/utils/pipeline_run_builder_test.go rename tekton/utils/{pipeline_ref_test.go => pipeline_test.go} (98%) diff --git a/api/v1alpha1/releaseplanadmission_types.go b/api/v1alpha1/releaseplanadmission_types.go index 0b1fadf7..7ccb36b9 100644 --- a/api/v1alpha1/releaseplanadmission_types.go +++ b/api/v1alpha1/releaseplanadmission_types.go @@ -49,20 +49,14 @@ type ReleasePlanAdmissionSpec struct { // +required Origin string `json:"origin"` - // PipelineRef is a reference to the Pipeline to be executed by the managed Release PipelineRun + // Pipeline contains all the information about the managed Pipeline // +required - PipelineRef *tektonutils.PipelineRef `json:"pipelineRef"` + Pipeline *tektonutils.Pipeline `json:"pipeline"` // Policy to validate before releasing an artifact // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ // +required Policy string `json:"policy"` - - // ServiceAccount is the name of the service account to use in the - // managed Release PipelineRun to gain elevated privileges - // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - // +optional - ServiceAccount string `json:"serviceAccount,omitempty"` } // MatchedReleasePlan defines the relevant information for a matched ReleasePlan. diff --git a/api/v1alpha1/webhooks/releaseplanadmission/webhook_test.go b/api/v1alpha1/webhooks/releaseplanadmission/webhook_test.go index 0454f45f..a38925f3 100644 --- a/api/v1alpha1/webhooks/releaseplanadmission/webhook_test.go +++ b/api/v1alpha1/webhooks/releaseplanadmission/webhook_test.go @@ -46,12 +46,14 @@ var _ = Describe("ReleasePlanAdmission webhook", func() { Applications: []string{"application"}, Origin: "default", Environment: "environment", - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "quay.io/some/bundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + {Name: "bundle", Value: "quay.io/some/bundle"}, + {Name: "name", Value: "release-pipeline"}, + {Name: "kind", Value: "pipeline"}, + }, }, }, Policy: "policy", diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 998f02d8..3f989b42 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -299,9 +299,9 @@ func (in *ReleasePlanAdmissionSpec) DeepCopyInto(out *ReleasePlanAdmissionSpec) *out = new(runtime.RawExtension) (*in).DeepCopyInto(*out) } - if in.PipelineRef != nil { - in, out := &in.PipelineRef, &out.PipelineRef - *out = new(utils.PipelineRef) + if in.Pipeline != nil { + in, out := &in.Pipeline, &out.Pipeline + *out = new(utils.Pipeline) (*in).DeepCopyInto(*out) } } diff --git a/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml b/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml index e989d143..761d3568 100644 --- a/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml +++ b/config/crd/bases/appstudio.redhat.com_releaseplanadmissions.yaml @@ -66,30 +66,42 @@ spec: from pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string - pipelineRef: - description: PipelineRef is a reference to the Pipeline to be executed - by the managed Release PipelineRun + pipeline: + description: Pipeline contains all the information about the managed + Pipeline properties: - params: - description: Params is a slice of parameters for a given resolver - items: - description: Param defines the parameters for a given resolver - in PipelineRef - properties: - name: - description: Name is the name of the parameter - type: string - value: - description: Value is the value of the parameter - type: string - required: - - name - - value - type: object - type: array - resolver: - description: Resolver is the name of a Tekton resolver to be used - (e.g. git) + pipelineRef: + description: PipelineRef is the reference to the Pipeline + properties: + params: + description: Params is a slice of parameters for a given resolver + items: + description: Param defines the parameters for a given resolver + in PipelineRef + properties: + name: + description: Name is the name of the parameter + type: string + value: + description: Value is the value of the parameter + type: string + required: + - name + - value + type: object + type: array + resolver: + description: Resolver is the name of a Tekton resolver to + be used (e.g. git) + type: string + required: + - params + - resolver + type: object + serviceAccountName: + description: ServiceAccount is the ServiceAccount to use during + the execution of the Pipeline + pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string timeout: default: "0" @@ -97,22 +109,16 @@ spec: Pipelinerun timeout type: string required: - - params - - resolver + - pipelineRef type: object policy: description: Policy to validate before releasing an artifact pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ type: string - serviceAccount: - description: ServiceAccount is the name of the service account to - use in the managed Release PipelineRun to gain elevated privileges - pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ - type: string required: - applications - origin - - pipelineRef + - pipeline - policy type: object status: diff --git a/config/crd/bases/appstudio.redhat.com_releaseplans.yaml b/config/crd/bases/appstudio.redhat.com_releaseplans.yaml index 9b94667b..b307732b 100644 --- a/config/crd/bases/appstudio.redhat.com_releaseplans.yaml +++ b/config/crd/bases/appstudio.redhat.com_releaseplans.yaml @@ -79,11 +79,6 @@ spec: description: Resolver is the name of a Tekton resolver to be used (e.g. git) type: string - timeout: - default: "0" - description: Timeout is value to use to override the tekton default - Pipelinerun timeout - type: string required: - params - resolver diff --git a/controllers/release/adapter.go b/controllers/release/adapter.go index dd361919..ce74f873 100644 --- a/controllers/release/adapter.go +++ b/controllers/release/adapter.go @@ -342,10 +342,10 @@ func (a *adapter) createManagedPipelineRun(resources *loader.ProcessingResources WithOwner(a.release). WithReleaseAndApplicationMetadata(a.release, resources.Snapshot.Spec.Application). WithWorkspace(os.Getenv("DEFAULT_RELEASE_WORKSPACE_NAME"), os.Getenv("DEFAULT_RELEASE_PVC")). - WithServiceAccount(resources.ReleasePlanAdmission.Spec.ServiceAccount). - WithTimeout(resources.ReleasePlanAdmission.Spec.PipelineRef.Timeout). - WithPipelineRef(resources.ReleasePlanAdmission.Spec.PipelineRef.ToTektonPipelineRef()). - WithTaskGitPipelineParameters(resources.ReleasePlanAdmission.Spec.PipelineRef). + WithServiceAccount(resources.ReleasePlanAdmission.Spec.Pipeline.ServiceAccount). + WithTimeout(resources.ReleasePlanAdmission.Spec.Pipeline.Timeout). + WithPipelineRef(resources.ReleasePlanAdmission.Spec.Pipeline.PipelineRef.ToTektonPipelineRef()). + WithTaskGitPipelineParameters(&resources.ReleasePlanAdmission.Spec.Pipeline.PipelineRef). WithEnterpriseContractConfigMap(resources.EnterpriseContractConfigMap). WithEnterpriseContractPolicy(resources.EnterpriseContractPolicy). AsPipelineRun() @@ -621,7 +621,7 @@ func (a *adapter) validatePipelineRef() *controller.ValidationResult { return &controller.ValidationResult{Err: err} } - if !a.releaseServiceConfig.Spec.Debug && releasePlanAdmission.Spec.PipelineRef.IsClusterScoped() { + if !a.releaseServiceConfig.Spec.Debug && releasePlanAdmission.Spec.Pipeline.PipelineRef.IsClusterScoped() { a.release.MarkValidationFailed("tried using debug only options while debug mode is disabled in the ReleaseServiceConfig") return &controller.ValidationResult{Valid: false} } diff --git a/controllers/release/adapter_test.go b/controllers/release/adapter_test.go index 0e093a0e..54bf7494 100644 --- a/controllers/release/adapter_test.go +++ b/controllers/release/adapter_test.go @@ -319,12 +319,14 @@ var _ = Describe("Release adapter", Ordered, func() { Spec: v1alpha1.ReleasePlanAdmissionSpec{ Applications: []string{"app"}, Origin: "default", - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "quay.io/some/bundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + {Name: "bundle", Value: "quay.io/some/bundle"}, + {Name: "name", Value: "release-pipeline"}, + {Name: "kind", Value: "pipeline"}, + }, }, }, Policy: enterpriseContractPolicy.Name, @@ -879,7 +881,7 @@ var _ = Describe("Release adapter", Ordered, func() { pipelineUrl = resolverParams[i].Value.StringVal } } - Expect(pipelineUrl).To(Equal(releasePlanAdmission.Spec.PipelineRef.Params[0].Value)) + Expect(pipelineUrl).To(Equal(releasePlanAdmission.Spec.Pipeline.PipelineRef.Params[0].Value)) }) It("contains a parameter with the taskGitUrl", func() { @@ -907,7 +909,7 @@ var _ = Describe("Release adapter", Ordered, func() { }) It("contains the proper timeout value", func() { - timeout := releasePlanAdmission.Spec.PipelineRef.Timeout + timeout := releasePlanAdmission.Spec.Pipeline.Timeout Expect(pipelineRun.Spec.Timeouts.Pipeline.Duration.String()).To(Equal(string(timeout))) }) @@ -1548,12 +1550,14 @@ var _ = Describe("Release adapter", Ordered, func() { Applications: []string{application.Name}, Origin: "default", Environment: environment.Name, - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "cluster", - Params: []tektonutils.Param{ - {Name: "name", Value: "release-pipeline"}, - {Name: "namespace", Value: "default"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "cluster", + Params: []tektonutils.Param{ + {Name: "name", Value: "release-pipeline"}, + {Name: "namespace", Value: "default"}, + {Name: "kind", Value: "pipeline"}, + }, }, }, Policy: enterpriseContractPolicy.Name, @@ -1712,12 +1716,14 @@ var _ = Describe("Release adapter", Ordered, func() { Applications: []string{application.Name}, Origin: "default", Environment: environment.Name, - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "git", - Params: []tektonutils.Param{ - {Name: "url", Value: "my-url"}, - {Name: "revision", Value: "my-revision"}, - {Name: "pathInRepo", Value: "my-path"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "git", + Params: []tektonutils.Param{ + {Name: "url", Value: "my-url"}, + {Name: "revision", Value: "my-revision"}, + {Name: "pathInRepo", Value: "my-path"}, + }, }, Timeout: "2h0m0s", }, diff --git a/controllers/releaseplan/adapter_test.go b/controllers/releaseplan/adapter_test.go index 468de816..1d1abfb8 100644 --- a/controllers/releaseplan/adapter_test.go +++ b/controllers/releaseplan/adapter_test.go @@ -211,15 +211,17 @@ var _ = Describe("ReleasePlan adapter", Ordered, func() { Spec: v1alpha1.ReleasePlanAdmissionSpec{ Applications: []string{application.Name}, Origin: "default", - Policy: "policy", - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "quay.io/some/bundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + {Name: "bundle", Value: "quay.io/some/bundle"}, + {Name: "name", Value: "release-pipeline"}, + {Name: "kind", Value: "pipeline"}, + }, }, }, + Policy: "policy", }, } Expect(k8sClient.Create(ctx, releasePlanAdmission)).To(Succeed()) diff --git a/controllers/releaseplanadmission/adapter_test.go b/controllers/releaseplanadmission/adapter_test.go index ff1406f7..94696c0e 100644 --- a/controllers/releaseplanadmission/adapter_test.go +++ b/controllers/releaseplanadmission/adapter_test.go @@ -210,15 +210,17 @@ var _ = Describe("ReleasePlanAdmission adapter", Ordered, func() { Spec: v1alpha1.ReleasePlanAdmissionSpec{ Applications: []string{"application"}, Origin: "default", - Policy: "policy", - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "quay.io/some/bundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + {Name: "bundle", Value: "quay.io/some/bundle"}, + {Name: "name", Value: "release-pipeline"}, + {Name: "kind", Value: "pipeline"}, + }, }, }, + Policy: "policy", }, } Expect(k8sClient.Create(ctx, releasePlanAdmission)).To(Succeed()) diff --git a/controllers/utils/predicates/predicates_test.go b/controllers/utils/predicates/predicates_test.go index 48872250..2eeb3e35 100644 --- a/controllers/utils/predicates/predicates_test.go +++ b/controllers/utils/predicates/predicates_test.go @@ -128,15 +128,17 @@ var _ = Describe("Predicates", Ordered, func() { applicationName, }, Origin: namespace2, - Policy: "policy", - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "quay.io/some/bundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + {Name: "bundle", Value: "quay.io/some/bundle"}, + {Name: "name", Value: "release-pipeline"}, + {Name: "kind", Value: "pipeline"}, + }, }, }, + Policy: "policy", }, } releasePlanAdmissionDiffApps = &v1alpha1.ReleasePlanAdmission{ @@ -152,15 +154,17 @@ var _ = Describe("Predicates", Ordered, func() { "diff", }, Origin: namespace2, - Policy: "policy", - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "quay.io/some/bundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + {Name: "bundle", Value: "quay.io/some/bundle"}, + {Name: "name", Value: "release-pipeline"}, + {Name: "kind", Value: "pipeline"}, + }, }, }, + Policy: "policy", }, } releasePlanAdmissionDiffOrigin = &v1alpha1.ReleasePlanAdmission{ @@ -176,15 +180,17 @@ var _ = Describe("Predicates", Ordered, func() { applicationName, }, Origin: "diff", - Policy: "policy", - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "quay.io/some/bundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + {Name: "bundle", Value: "quay.io/some/bundle"}, + {Name: "name", Value: "release-pipeline"}, + {Name: "kind", Value: "pipeline"}, + }, }, }, + Policy: "policy", }, } releasePlanAdmissionDiffStatus = &v1alpha1.ReleasePlanAdmission{ @@ -200,15 +206,17 @@ var _ = Describe("Predicates", Ordered, func() { applicationName, }, Origin: namespace2, - Policy: "policy", - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "quay.io/some/bundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + {Name: "bundle", Value: "quay.io/some/bundle"}, + {Name: "name", Value: "release-pipeline"}, + {Name: "kind", Value: "pipeline"}, + }, }, }, + Policy: "policy", }, } releasePlanAdmissionDiffStatus.MarkMatched(&v1alpha1.ReleasePlan{}) diff --git a/go.mod b/go.mod index 8afe9365..9d2bf07f 100644 --- a/go.mod +++ b/go.mod @@ -58,7 +58,7 @@ require ( github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.3.0 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-multierror v1.1.1 github.com/imdario/mergo v0.3.13 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect diff --git a/loader/loader_test.go b/loader/loader_test.go index 489833dd..62c62751 100644 --- a/loader/loader_test.go +++ b/loader/loader_test.go @@ -502,12 +502,14 @@ var _ = Describe("Release Adapter", Ordered, func() { Applications: []string{application.Name}, Environment: environment.Name, Origin: "default", - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "testbundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + {Name: "bundle", Value: "testbundle"}, + {Name: "name", Value: "release-pipeline"}, + {Name: "kind", Value: "pipeline"}, + }, }, }, Policy: enterpriseContractPolicy.Name, diff --git a/tekton/pipeline_run_test.go b/tekton/pipeline_run_test.go index 0f2c193c..e942c8b1 100644 --- a/tekton/pipeline_run_test.go +++ b/tekton/pipeline_run_test.go @@ -117,16 +117,18 @@ var _ = Describe("PipelineRun", func() { releasePlanAdmission = &v1alpha1.ReleasePlanAdmission{ Spec: v1alpha1.ReleasePlanAdmissionSpec{ Applications: []string{"application"}, - PipelineRef: &tektonutils.PipelineRef{ - Resolver: "bundles", - Params: []tektonutils.Param{ - {Name: "bundle", Value: "testbundle"}, - {Name: "name", Value: "release-pipeline"}, - {Name: "kind", Value: "pipeline"}, + Pipeline: &tektonutils.Pipeline{ + PipelineRef: tektonutils.PipelineRef{ + Resolver: "bundles", + Params: []tektonutils.Param{ + {Name: "bundle", Value: "testbundle"}, + {Name: "name", Value: "release-pipeline"}, + {Name: "kind", Value: "pipeline"}, + }, }, + ServiceAccount: serviceAccountName, }, - Policy: "testpolicy", - ServiceAccount: serviceAccountName, + Policy: "testpolicy", }, } @@ -195,14 +197,14 @@ var _ = Describe("PipelineRun", func() { }) It("can add the PipelineRef to a PipelineRun object ", func() { - releasePipelineRun.WithPipelineRef(releasePlanAdmission.Spec.PipelineRef.ToTektonPipelineRef()) + releasePipelineRun.WithPipelineRef(releasePlanAdmission.Spec.Pipeline.PipelineRef.ToTektonPipelineRef()) Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef).NotTo(Equal(tektonv1.ResolverRef{})) Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Resolver).To(Equal(tektonv1.ResolverName("bundles"))) Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params).To(HaveLen(3)) Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[0].Name).To(Equal("bundle")) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[0].Value.StringVal).To(Equal(releasePlanAdmission.Spec.PipelineRef.Params[0].Value)) + Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[0].Value.StringVal).To(Equal(releasePlanAdmission.Spec.Pipeline.PipelineRef.Params[0].Value)) Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[1].Name).To(Equal("name")) - Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[1].Value.StringVal).To(Equal(releasePlanAdmission.Spec.PipelineRef.Params[1].Value)) + Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[1].Value.StringVal).To(Equal(releasePlanAdmission.Spec.Pipeline.PipelineRef.Params[1].Value)) Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[2].Name).To(Equal("kind")) Expect(releasePipelineRun.Spec.PipelineRef.ResolverRef.Params[2].Value.StringVal).To(Equal("pipeline")) }) diff --git a/tekton/utils/pipeline_ref.go b/tekton/utils/pipeline.go similarity index 69% rename from tekton/utils/pipeline_ref.go rename to tekton/utils/pipeline.go index 027dab88..192a2176 100644 --- a/tekton/utils/pipeline_ref.go +++ b/tekton/utils/pipeline.go @@ -18,6 +18,15 @@ package utils import tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" +// Param defines the parameters for a given resolver in PipelineRef +type Param struct { + // Name is the name of the parameter + Name string `json:"name"` + + // Value is the value of the parameter + Value string `json:"value"` +} + // PipelineRef represents a reference to a Pipeline using a resolver. // +kubebuilder:object:generate=true type PipelineRef struct { @@ -26,6 +35,18 @@ type PipelineRef struct { // Params is a slice of parameters for a given resolver Params []Param `json:"params"` +} + +// Pipeline contains a reference to a Pipeline and the name of the service account to use while executing it. +// +kubebuilder:object:generate=true +type Pipeline struct { + // PipelineRef is the reference to the Pipeline + PipelineRef PipelineRef `json:"pipelineRef"` + + // ServiceAccount is the ServiceAccount to use during the execution of the Pipeline + // +kubebuilder:validation:Pattern=^[a-z0-9]([-a-z0-9]*[a-z0-9])?$ + // +optional + ServiceAccount string `json:"serviceAccountName,omitempty"` // Timeout is value to use to override the tekton default Pipelinerun timeout // +kubebuilder:default="0" @@ -33,17 +54,16 @@ type PipelineRef struct { Timeout string `json:"timeout,omitempty"` } -// Param defines the parameters for a given resolver in PipelineRef -type Param struct { - // Name is the name of the parameter - Name string `json:"name"` - - // Value is the value of the parameter - Value string `json:"value"` +// ParameterizedPipeline is an extension of the Pipeline struct, adding an array of parameters that will be passed to +// the Pipeline. +// +kubebuilder:object:generate=true +type ParameterizedPipeline struct { + Pipeline + Params []Param `json:"params,omitempty"` } // ToTektonPipelineRef converts a PipelineRef object to Tekton's own PipelineRef type and returns it. -func (pr PipelineRef) ToTektonPipelineRef() *tektonv1.PipelineRef { +func (pr *PipelineRef) ToTektonPipelineRef() *tektonv1.PipelineRef { params := tektonv1.Params{} for _, p := range pr.Params { @@ -67,6 +87,6 @@ func (pr PipelineRef) ToTektonPipelineRef() *tektonv1.PipelineRef { } // IsClusterScoped returns whether the PipelineRef uses a cluster resolver or not. -func (pr PipelineRef) IsClusterScoped() bool { +func (pr *PipelineRef) IsClusterScoped() bool { return pr.Resolver == "cluster" } diff --git a/tekton/utils/pipeline_run_builder.go b/tekton/utils/pipeline_run_builder.go new file mode 100644 index 00000000..7c0988d3 --- /dev/null +++ b/tekton/utils/pipeline_run_builder.go @@ -0,0 +1,236 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import ( + "encoding/json" + "fmt" + "github.com/hashicorp/go-multierror" + libhandler "github.com/operator-framework/operator-lib/handler" + tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "reflect" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + "unicode" +) + +type PipelineRunBuilder struct { + err *multierror.Error + pipelineRun *tektonv1.PipelineRun +} + +// NewPipelineRunBuilder initializes a new PipelineRunBuilder with the given name prefix and namespace. +// It sets the name of the PipelineRun to be generated with the provided prefix and sets its namespace. +func NewPipelineRunBuilder(namePrefix, namespace string) *PipelineRunBuilder { + return &PipelineRunBuilder{ + pipelineRun: &tektonv1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + GenerateName: namePrefix + "-", + Namespace: namespace, + }, + Spec: tektonv1.PipelineRunSpec{}, + }, + } +} + +// Build returns the constructed PipelineRun and any accumulated error. +func (b *PipelineRunBuilder) Build() (*tektonv1.PipelineRun, error) { + return b.pipelineRun, b.err.ErrorOrNil() +} + +// WithAnnotations appends or updates annotations to the PipelineRun's metadata. +// If the PipelineRun does not have existing annotations, it initializes them before adding. +func (b *PipelineRunBuilder) WithAnnotations(annotations map[string]string) *PipelineRunBuilder { + if b.pipelineRun.ObjectMeta.Annotations == nil { + b.pipelineRun.ObjectMeta.Annotations = make(map[string]string) + } + + for key, value := range annotations { + b.pipelineRun.ObjectMeta.Annotations[key] = value + } + + return b +} + +// WithFinalizer adds the given finalizer to the PipelineRun's metadata. +func (b *PipelineRunBuilder) WithFinalizer(finalizer string) *PipelineRunBuilder { + controllerutil.AddFinalizer(b.pipelineRun, finalizer) + + return b +} + +// WithLabels appends or updates labels to the PipelineRun's metadata. +// If the PipelineRun does not have existing labels, it initializes them before adding. +func (b *PipelineRunBuilder) WithLabels(labels map[string]string) *PipelineRunBuilder { + if b.pipelineRun.ObjectMeta.Labels == nil { + b.pipelineRun.ObjectMeta.Labels = make(map[string]string) + } + + for key, value := range labels { + b.pipelineRun.ObjectMeta.Labels[key] = value + } + + return b +} + +// WithObjectReferences constructs tektonv1.Param entries for each of the provided client.Objects. +// Each param name is derived from the object's Kind (with the first letter made lowercase) and +// the value is a combination of the object's Namespace and Name. +func (b *PipelineRunBuilder) WithObjectReferences(objects ...client.Object) *PipelineRunBuilder { + for _, obj := range objects { + name := []rune(obj.GetObjectKind().GroupVersionKind().Kind) + name[0] = unicode.ToLower(name[0]) + + b.WithParams(tektonv1.Param{ + Name: string(name), + Value: tektonv1.ParamValue{ + Type: tektonv1.ParamTypeString, + StringVal: obj.GetNamespace() + "/" + obj.GetName(), + }, + }) + } + + return b +} + +// WithObjectSpecsAsJson constructs tektonv1.Param entries for the Spec field of each of the provided client.Objects. +// Each param name is derived from the object's Kind (with the first letter made lowercase). +// The value for each param is the JSON representation of the object's Spec. +// If an error occurs during extraction or serialization, it's accumulated in the builder's err field using multierror. +func (b *PipelineRunBuilder) WithObjectSpecsAsJson(objects ...client.Object) *PipelineRunBuilder { + for _, obj := range objects { + name := []rune(obj.GetObjectKind().GroupVersionKind().Kind) + name[0] = unicode.ToLower(name[0]) + + value := reflect.ValueOf(obj).Elem().FieldByName("Spec") + if !value.IsValid() { + b.err = multierror.Append(b.err, fmt.Errorf("failed to extract spec for object: %s", string(name))) + continue + } + + jsonData, err := json.Marshal(value.Interface()) + if err != nil { + b.err = multierror.Append(b.err, fmt.Errorf("failed to serialize spec of object %s to JSON: %v", string(name), err)) + continue + } + + b.WithParams(tektonv1.Param{ + Name: string(name), + Value: tektonv1.ParamValue{ + Type: tektonv1.ParamTypeString, + StringVal: string(jsonData), + }, + }) + } + + return b +} + +// WithOwner sets the given client.Object as the owner of the PipelineRun. +// It also adds the ReleaseFinalizer to the PipelineRun. +func (b *PipelineRunBuilder) WithOwner(object client.Object) *PipelineRunBuilder { + if err := libhandler.SetOwnerAnnotations(object, b.pipelineRun); err != nil { + b.err = multierror.Append(b.err, fmt.Errorf("failed to set owner annotations: %v", err)) + return b + } + + return b +} + +// WithParams appends the provided params to the PipelineRun's spec. +func (b *PipelineRunBuilder) WithParams(params ...tektonv1.Param) *PipelineRunBuilder { + if b.pipelineRun.Spec.Params == nil { + b.pipelineRun.Spec.Params = make([]tektonv1.Param, 0) + } + + b.pipelineRun.Spec.Params = append(b.pipelineRun.Spec.Params, params...) + + return b +} + +// WithParamsFromConfigMap adds parameters to the PipelineRun based on the provided keys from a given ConfigMap. +// If a key is present in the ConfigMap, a new tektonv1.Param is constructed with the key as the name and the associated +// value from the ConfigMap. Keys not found in the ConfigMap are ignored. +func (b *PipelineRunBuilder) WithParamsFromConfigMap(configMap *corev1.ConfigMap, keys []string) *PipelineRunBuilder { + if configMap == nil { + return b + } + + var params []tektonv1.Param + for _, key := range keys { + if value, exists := configMap.Data[key]; exists { + params = append(params, tektonv1.Param{ + Name: key, + Value: tektonv1.ParamValue{ + Type: tektonv1.ParamTypeString, + StringVal: value, + }, + }) + } + } + + return b.WithParams(params...) +} + +// WithPipelineRef sets the PipelineRef for the PipelineRun's spec. +func (b *PipelineRunBuilder) WithPipelineRef(pipelineRef *tektonv1.PipelineRef) *PipelineRunBuilder { + b.pipelineRun.Spec.PipelineRef = pipelineRef + + return b +} + +// WithServiceAccount sets the ServiceAccountName for the PipelineRun's TaskRunTemplate. +func (b *PipelineRunBuilder) WithServiceAccount(serviceAccount string) *PipelineRunBuilder { + b.pipelineRun.Spec.TaskRunTemplate.ServiceAccountName = serviceAccount + + return b +} + +// WithWorkspaceFromVolumeTemplate creates and adds a workspace binding to the PipelineRun's spec using +// the provided workspace name and volume size. +func (b *PipelineRunBuilder) WithWorkspaceFromVolumeTemplate(name, size string) *PipelineRunBuilder { + if b.pipelineRun.Spec.Workspaces == nil { + b.pipelineRun.Spec.Workspaces = []tektonv1.WorkspaceBinding{} + } + + quantity, err := resource.ParseQuantity(size) + if err != nil { + b.err = multierror.Append(b.err, fmt.Errorf("invalid size format: %v", err)) + return b + } + + workspace := tektonv1.WorkspaceBinding{ + Name: name, + VolumeClaimTemplate: &corev1.PersistentVolumeClaim{ + Spec: corev1.PersistentVolumeClaimSpec{ + AccessModes: []corev1.PersistentVolumeAccessMode{corev1.ReadWriteOnce}, + Resources: corev1.ResourceRequirements{ + Requests: corev1.ResourceList{ + corev1.ResourceStorage: quantity, + }, + }, + }, + }, + } + + b.pipelineRun.Spec.Workspaces = append(b.pipelineRun.Spec.Workspaces, workspace) + + return b +} diff --git a/tekton/utils/pipeline_run_builder_test.go b/tekton/utils/pipeline_run_builder_test.go new file mode 100644 index 00000000..6fa71931 --- /dev/null +++ b/tekton/utils/pipeline_run_builder_test.go @@ -0,0 +1,371 @@ +/* +Copyright 2023. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package utils + +import ( + "fmt" + "github.com/hashicorp/go-multierror" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("PipelineRun builder", func() { + + When("NewPipelineRunBuilder method is called", func() { + var ( + namePrefix = "testPrefix" + namespace = "testNamespace" + builder *PipelineRunBuilder + ) + + BeforeEach(func() { + builder = NewPipelineRunBuilder(namePrefix, namespace) + }) + + It("should return a new PipelineRunBuilder instance", func() { + Expect(builder).To(Not(BeNil())) + }) + + It("should set the correct GenerateName in the returned PipelineRunBuilder instance", func() { + Expect(builder.pipelineRun.ObjectMeta.GenerateName).To(Equal(namePrefix + "-")) + }) + + It("should set the correct Namespace in the returned PipelineRunBuilder instance", func() { + Expect(builder.pipelineRun.ObjectMeta.Namespace).To(Equal(namespace)) + }) + + It("should initialize an empty PipelineRunSpec", func() { + Expect(builder.pipelineRun.Spec).To(Equal(tektonv1.PipelineRunSpec{})) + }) + }) + + When("Build method is called", func() { + It("should return the constructed PipelineRun if there are no errors", func() { + builder := NewPipelineRunBuilder("testPrefix", "testNamespace") + pr, err := builder.Build() + Expect(pr).To(Not(BeNil())) + Expect(err).To(BeNil()) + }) + + It("should return the accumulated errors", func() { + builder := &PipelineRunBuilder{ + err: multierror.Append(nil, fmt.Errorf("dummy error 1"), fmt.Errorf("dummy error 2")), + } + _, err := builder.Build() + Expect(err).To(Not(BeNil())) + Expect(err.Error()).To(ContainSubstring("dummy error 1")) + Expect(err.Error()).To(ContainSubstring("dummy error 2")) + }) + }) + + When("WithAnnotations method is called", func() { + var ( + builder *PipelineRunBuilder + ) + + BeforeEach(func() { + builder = NewPipelineRunBuilder("testPrefix", "testNamespace") + }) + + It("should add annotations when none previously existed", func() { + builder.WithAnnotations(map[string]string{ + "annotation1": "value1", + "annotation2": "value2", + }) + Expect(builder.pipelineRun.ObjectMeta.Annotations).To(HaveKeyWithValue("annotation1", "value1")) + Expect(builder.pipelineRun.ObjectMeta.Annotations).To(HaveKeyWithValue("annotation2", "value2")) + }) + + It("should update existing annotations and add new ones", func() { + builder.pipelineRun.ObjectMeta.Annotations = map[string]string{ + "annotation1": "oldValue1", + "annotation3": "value3", + } + builder.WithAnnotations(map[string]string{ + "annotation1": "newValue1", + "annotation2": "value2", + }) + Expect(builder.pipelineRun.ObjectMeta.Annotations).To(HaveKeyWithValue("annotation1", "newValue1")) + Expect(builder.pipelineRun.ObjectMeta.Annotations).To(HaveKeyWithValue("annotation2", "value2")) + Expect(builder.pipelineRun.ObjectMeta.Annotations).To(HaveKeyWithValue("annotation3", "value3")) + }) + }) + + When("WithFinalizer method is called", func() { + var ( + builder *PipelineRunBuilder + ) + + BeforeEach(func() { + builder = NewPipelineRunBuilder("testPrefix", "testNamespace") + }) + + It("should add a finalizer when none previously existed", func() { + builder.WithFinalizer("finalizer1") + Expect(builder.pipelineRun.ObjectMeta.Finalizers).To(ContainElement("finalizer1")) + }) + + It("should append a new finalizer to the existing finalizers", func() { + builder.pipelineRun.ObjectMeta.Finalizers = []string{"existingFinalizer"} + builder.WithFinalizer("finalizer2") + Expect(builder.pipelineRun.ObjectMeta.Finalizers).To(ContainElements("existingFinalizer", "finalizer2")) + }) + }) + + When("WithLabels method is called", func() { + var ( + builder *PipelineRunBuilder + ) + + BeforeEach(func() { + builder = NewPipelineRunBuilder("testPrefix", "testNamespace") + }) + + It("should add labels when none previously existed", func() { + builder.WithLabels(map[string]string{ + "label1": "value1", + "label2": "value2", + }) + Expect(builder.pipelineRun.ObjectMeta.Labels).To(HaveKeyWithValue("label1", "value1")) + Expect(builder.pipelineRun.ObjectMeta.Labels).To(HaveKeyWithValue("label2", "value2")) + }) + + It("should update existing labels and add new ones", func() { + builder.pipelineRun.ObjectMeta.Labels = map[string]string{ + "label1": "oldValue1", + "label3": "value3", + } + builder.WithLabels(map[string]string{ + "label1": "newValue1", + "label2": "value2", + }) + Expect(builder.pipelineRun.ObjectMeta.Labels).To(HaveKeyWithValue("label1", "newValue1")) + Expect(builder.pipelineRun.ObjectMeta.Labels).To(HaveKeyWithValue("label2", "value2")) + Expect(builder.pipelineRun.ObjectMeta.Labels).To(HaveKeyWithValue("label3", "value3")) + }) + }) + + When("WithObjectReferences method is called", func() { + It("should add parameters based on the provided client.Objects", func() { + builder := NewPipelineRunBuilder("testPrefix", "testNamespace") + configMap1 := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "configName1", + Namespace: "configNamespace1", + }, + } + configMap1.Kind = "ConfigMap" + configMap2 := &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "configName2", + Namespace: "configNamespace2", + }, + } + configMap2.Kind = "ConfigMap" + + builder.WithObjectReferences(configMap1, configMap2) + + Expect(builder.pipelineRun.Spec.Params).To(ContainElement(tektonv1.Param{ + Name: "configMap", + Value: tektonv1.ParamValue{Type: tektonv1.ParamTypeString, StringVal: "configNamespace1/configName1"}, + })) + Expect(builder.pipelineRun.Spec.Params).To(ContainElement(tektonv1.Param{ + Name: "configMap", + Value: tektonv1.ParamValue{Type: tektonv1.ParamTypeString, StringVal: "configNamespace2/configName2"}, + })) + }) + }) + + When("WithObjectSpecsAsJson method is called", func() { + It("should add parameters with JSON representation of the object's Spec", func() { + builder := NewPipelineRunBuilder("testPrefix", "testNamespace") + pod1 := &corev1.Pod{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "container1", + Image: "image1", + }, + }, + }, + } + pod1.Kind = "Pod" + pod2 := &corev1.Pod{ + Spec: corev1.PodSpec{ + Containers: []corev1.Container{ + { + Name: "container2", + Image: "image2", + }, + }, + }, + } + pod2.Kind = "Pod" + + builder.WithObjectSpecsAsJson(pod1, pod2) + + Expect(builder.pipelineRun.Spec.Params).To(ContainElement(tektonv1.Param{ + Name: "pod", + Value: tektonv1.ParamValue{ + Type: tektonv1.ParamTypeString, + StringVal: `{"containers":[{"name":"container1","image":"image1","resources":{}}]}`, + }, + })) + Expect(builder.pipelineRun.Spec.Params).To(ContainElement(tektonv1.Param{ + Name: "pod", + Value: tektonv1.ParamValue{ + Type: tektonv1.ParamTypeString, + StringVal: `{"containers":[{"name":"container2","image":"image2","resources":{}}]}`, + }, + })) + }) + }) + + When("WithParams method is called", func() { + It("should append the provided parameters to the PipelineRun's spec", func() { + builder := NewPipelineRunBuilder("testPrefix", "testNamespace") + + param1 := tektonv1.Param{ + Name: "param1", + Value: tektonv1.ParamValue{Type: tektonv1.ParamTypeString, StringVal: "value1"}, + } + param2 := tektonv1.Param{ + Name: "param2", + Value: tektonv1.ParamValue{Type: tektonv1.ParamTypeString, StringVal: "value2"}, + } + + builder.WithParams(param1, param2) + + Expect(builder.pipelineRun.Spec.Params).To(ContainElements(param1, param2)) + }) + }) + + When("WithOwner method is called", func() { + var ( + builder *PipelineRunBuilder + configMap *corev1.ConfigMap + ) + + BeforeEach(func() { + builder = NewPipelineRunBuilder("testPrefix", "testNamespace") + configMap = &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: "configName", + Namespace: "configNamespace", + }, + } + configMap.Kind = "Config" + }) + + It("should handle owner without errors", func() { + builder.WithOwner(configMap) + _, err := builder.Build() + Expect(err).ToNot(HaveOccurred()) + }) + + It("should have added owner annotations to the PipelineRun", func() { + builder.WithOwner(configMap) + Expect(builder.pipelineRun.Annotations).ToNot(BeEmpty()) + }) + }) + + When("WithParamsFromConfigMap method is called", func() { + It("should add parameters corresponding to the provided keys", func() { + builder := NewPipelineRunBuilder("testPrefix", "testNamespace") + configMap := &corev1.ConfigMap{ + Data: map[string]string{ + "key1": "value1", + "key2": "value2", + }, + } + + builder.WithParamsFromConfigMap(configMap, []string{"key1", "key2", "key3"}) // "key3" doesn't exist in the ConfigMap. + + paramKey1 := tektonv1.Param{ + Name: "key1", + Value: tektonv1.ParamValue{Type: tektonv1.ParamTypeString, StringVal: "value1"}, + } + paramKey2 := tektonv1.Param{ + Name: "key2", + Value: tektonv1.ParamValue{Type: tektonv1.ParamTypeString, StringVal: "value2"}, + } + + Expect(builder.pipelineRun.Spec.Params).To(ContainElement(paramKey1)) + Expect(builder.pipelineRun.Spec.Params).To(ContainElement(paramKey2)) + + // Check that "key3" is not added as a Param since it doesn't exist in the ConfigMap. + for _, param := range builder.pipelineRun.Spec.Params { + Expect(param.Name).ToNot(Equal("key3")) + } + }) + }) + + When("WithPipelineRef method is called", func() { + It("should set the PipelineRef for the PipelineRun's spec", func() { + builder := NewPipelineRunBuilder("testPrefix", "testNamespace") + pipelineRef := &tektonv1.PipelineRef{ + Name: "samplePipeline", + APIVersion: "tekton.dev/v1", + } + + builder.WithPipelineRef(pipelineRef) + Expect(builder.pipelineRun.Spec.PipelineRef).To(Equal(pipelineRef)) + }) + }) + + When("WithServiceAccount method is called", func() { + It("should set the ServiceAccountName for the PipelineRun's TaskRunTemplate", func() { + builder := NewPipelineRunBuilder("testPrefix", "testNamespace") + serviceAccount := "sampleServiceAccount" + builder.WithServiceAccount(serviceAccount) + Expect(builder.pipelineRun.Spec.TaskRunTemplate.ServiceAccountName).To(Equal(serviceAccount)) + }) + }) + + When("WithWorkspaceFromVolumeTemplate method is called", func() { + var ( + builder *PipelineRunBuilder + name string + ) + + BeforeEach(func() { + builder = NewPipelineRunBuilder("testPrefix", "testNamespace") + name = "sampleWorkspace" + }) + + It("should add a new workspace binding to the PipelineRun's spec with the correct name and size", func() { + size := "5Gi" + builder.WithWorkspaceFromVolumeTemplate(name, size) + Expect(len(builder.pipelineRun.Spec.Workspaces)).To(Equal(1)) + + workspaceBinding := builder.pipelineRun.Spec.Workspaces[0] + Expect(workspaceBinding.Name).To(Equal(name)) + workspaceQuantity := workspaceBinding.VolumeClaimTemplate.Spec.Resources.Requests[corev1.ResourceStorage] + Expect(workspaceQuantity.String()).To(Equal(size)) + }) + + It("should fail if the size is not in the right format", func() { + builder.WithWorkspaceFromVolumeTemplate(name, "invalid") + _, err := builder.Build() + Expect(err).To(HaveOccurred()) + Expect(err.Error()).To(ContainSubstring("invalid size format")) + }) + }) +}) diff --git a/tekton/utils/pipeline_ref_test.go b/tekton/utils/pipeline_test.go similarity index 98% rename from tekton/utils/pipeline_ref_test.go rename to tekton/utils/pipeline_test.go index 0a2fb1d6..89fd5693 100644 --- a/tekton/utils/pipeline_ref_test.go +++ b/tekton/utils/pipeline_test.go @@ -21,7 +21,7 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("Release type", func() { +var _ = Describe("Pipeline", func() { var ( clusterRef PipelineRef gitRef PipelineRef diff --git a/tekton/utils/suite_test.go b/tekton/utils/suite_test.go index 6fc178a8..5487f546 100644 --- a/tekton/utils/suite_test.go +++ b/tekton/utils/suite_test.go @@ -1,5 +1,5 @@ /* -Copyright 2022. +Copyright 2023 Red Hat Inc. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -21,15 +21,14 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/log/zap" logf "sigs.k8s.io/controller-runtime/pkg/log" - "sigs.k8s.io/controller-runtime/pkg/log/zap" //+kubebuilder:scaffold:imports ) func Test(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "Tekton Utils Suite") } diff --git a/tekton/utils/zz_generated.deepcopy.go b/tekton/utils/zz_generated.deepcopy.go index 73d4b6e4..aa28c8c0 100644 --- a/tekton/utils/zz_generated.deepcopy.go +++ b/tekton/utils/zz_generated.deepcopy.go @@ -23,6 +23,43 @@ package utils import () +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ParameterizedPipeline) DeepCopyInto(out *ParameterizedPipeline) { + *out = *in + in.Pipeline.DeepCopyInto(&out.Pipeline) + if in.Params != nil { + in, out := &in.Params, &out.Params + *out = make([]Param, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ParameterizedPipeline. +func (in *ParameterizedPipeline) DeepCopy() *ParameterizedPipeline { + if in == nil { + return nil + } + out := new(ParameterizedPipeline) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Pipeline) DeepCopyInto(out *Pipeline) { + *out = *in + in.PipelineRef.DeepCopyInto(&out.PipelineRef) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Pipeline. +func (in *Pipeline) DeepCopy() *Pipeline { + if in == nil { + return nil + } + out := new(Pipeline) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PipelineRef) DeepCopyInto(out *PipelineRef) { *out = *in