diff --git a/Makefile b/Makefile index f87c79e71b..486273b407 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ TEST_NAMESPACE ?= default TEKTON_VERSION ?= v0.44.0 # E2E test flags -TEST_E2E_FLAGS ?= -p --randomize-all -timeout=1h -trace -v +TEST_E2E_FLAGS ?= -r -p --randomize-all -timeout=1h -trace -v # E2E test service account name to be used for the build runs, can be set to generated to use the generated service account feature TEST_E2E_SERVICEACCOUNT_NAME ?= pipeline @@ -222,7 +222,7 @@ test-e2e-plain: ginkgo TEST_E2E_SERVICEACCOUNT_NAME=${TEST_E2E_SERVICEACCOUNT_NAME} \ TEST_E2E_TIMEOUT_MULTIPLIER=${TEST_E2E_TIMEOUT_MULTIPLIER} \ TEST_E2E_VERIFY_TEKTONOBJECTS=${TEST_E2E_VERIFY_TEKTONOBJECTS} \ - $(GINKGO) ${TEST_E2E_FLAGS} test/e2e + $(GINKGO) ${TEST_E2E_FLAGS} test/e2e/ .PHONY: test-e2e-kind-with-prereq-install test-e2e-kind-with-prereq-install: ginkgo install-controller-kind install-strategies test-e2e-plain @@ -270,7 +270,7 @@ install-controller-kind: install-apis .PHONY: install-strategies install-strategies: install-apis - kubectl apply -R -f samples/buildstrategy/ + kubectl apply -R -f samples/v1beta1/buildstrategy/ .PHONY: local local: install-strategies diff --git a/go.mod b/go.mod index 1f26e242e0..56e844845a 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( k8s.io/client-go v0.26.9 k8s.io/code-generator v0.26.9 k8s.io/kubectl v0.26.9 - k8s.io/utils v0.0.0-20230209194617-a36077c30491 + k8s.io/utils v0.0.0-20230726121419-3b25d923346b knative.dev/pkg v0.0.0-20230221145627-8efb3485adcf sigs.k8s.io/controller-runtime v0.14.6 sigs.k8s.io/yaml v1.3.0 diff --git a/go.sum b/go.sum index ffe23f26cb..66a5197ec1 100644 --- a/go.sum +++ b/go.sum @@ -817,8 +817,8 @@ k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a h1:gmovKNur38vgoWfGtP5QOG k8s.io/kube-openapi v0.0.0-20230308215209-15aac26d736a/go.mod h1:y5VtZWM9sHHc2ZodIH/6SHzXj+TPU5USoA8lcIeKEKY= k8s.io/kubectl v0.26.9 h1:0Z8wEFQoXqWbWfT7G9si5EKVjYf5KG4hocSB7B8Jkbc= k8s.io/kubectl v0.26.9/go.mod h1:Rl9W561iyUZtzwgstHcKChzUo2xMaGqb7Za6jUDMKP4= -k8s.io/utils v0.0.0-20230209194617-a36077c30491 h1:r0BAOLElQnnFhE/ApUsg3iHdVYYPBjNSSOMowRZxxsY= -k8s.io/utils v0.0.0-20230209194617-a36077c30491/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI= +k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= knative.dev/pkg v0.0.0-20230221145627-8efb3485adcf h1:TwvZFDpkyqpK2OCAwvNGV2Zjk14FzIh8X8Ci/du3jYI= knative.dev/pkg v0.0.0-20230221145627-8efb3485adcf/go.mod h1:VO/fcEsq43seuONRQxZyftWHjpMabYzRHDtpSEQ/eoQ= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= diff --git a/pkg/apis/addtoscheme_build_v1beta1.go b/pkg/apis/addtoscheme_build_v1beta1.go new file mode 100644 index 0000000000..f19bbbe5d4 --- /dev/null +++ b/pkg/apis/addtoscheme_build_v1beta1.go @@ -0,0 +1,14 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package apis + +import ( + "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +func init() { + // Register the types with the Scheme so the components can map objects to GroupVersionKinds and back + AddToSchemes = append(AddToSchemes, v1beta1.SchemeBuilder.AddToScheme) +} diff --git a/pkg/apis/build/v1beta1/build_conversion.go b/pkg/apis/build/v1beta1/build_conversion.go index 7417e94060..94ce0e3c5f 100644 --- a/pkg/apis/build/v1beta1/build_conversion.go +++ b/pkg/apis/build/v1beta1/build_conversion.go @@ -14,7 +14,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" runtime "k8s.io/apimachinery/pkg/runtime" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" ) const ( @@ -48,6 +48,14 @@ func (src *Build) ConvertTo(ctx context.Context, obj *unstructured.Unstructured) alphaBuild.ObjectMeta.Annotations[v1alpha1.AnnotationBuildRunDeletion] = strconv.FormatBool(*src.Spec.Retention.AtBuildDeletion) } + // convert OCIArtifact to Bundle + if src.Spec.Source.OCIArtifact != nil { + alphaBuild.Spec.Source.BundleContainer = &v1alpha1.BundleContainer{ + Image: src.Spec.Source.OCIArtifact.Image, + Prune: (*v1alpha1.PruneOption)(src.Spec.Source.OCIArtifact.Prune), + } + } + mapito, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&alphaBuild) if err != nil { ctxlog.Error(ctx, err, "failed structuring the newObject") @@ -82,7 +90,7 @@ func (src *Build) ConvertFrom(ctx context.Context, obj *unstructured.Unstructure if src.Spec.Retention == nil { src.Spec.Retention = &BuildRetention{} } - src.Spec.Retention.AtBuildDeletion = pointer.Bool(value == "true") + src.Spec.Retention.AtBuildDeletion = ptr.To[bool](value == "true") delete(src.ObjectMeta.Annotations, v1alpha1.AnnotationBuildRunDeletion) } @@ -154,6 +162,17 @@ func (dest *BuildSpec) ConvertFrom(orig *v1alpha1.BuildSpec) error { dest.ParamValues = append(dest.ParamValues, dockerfileParam) } + // handle spec.Builder migration + if orig.Builder != nil { + builderParam := ParamValue{ + Name: "builder-image", + SingleValue: &SingleValue{ + Value: &orig.Builder.Image, + }, + } + dest.ParamValues = append(dest.ParamValues, builderParam) + } + // Handle BuildSpec Output dest.Output.Image = orig.Output.Image dest.Output.Insecure = orig.Output.Insecure @@ -282,11 +301,15 @@ func (p ParamValue) convertToAlpha(dest *v1alpha1.ParamValue) { } if p.ConfigMapValue != nil { - dest.ConfigMapValue = &v1alpha1.ObjectKeyRef{} - dest.ConfigMapValue = (*v1alpha1.ObjectKeyRef)(p.ConfigMapValue) + dest.SingleValue = &v1alpha1.SingleValue{ + ConfigMapValue: (*v1alpha1.ObjectKeyRef)(p.ConfigMapValue), + } } + if p.SecretValue != nil { - dest.SecretValue = (*v1alpha1.ObjectKeyRef)(p.SecretValue) + dest.SingleValue = &v1alpha1.SingleValue{ + SecretValue: (*v1alpha1.ObjectKeyRef)(p.SecretValue), + } } dest.Name = p.Name @@ -323,9 +346,11 @@ func convertBetaParamValue(orig v1alpha1.ParamValue) ParamValue { } if orig.ConfigMapValue != nil { + p.SingleValue = &SingleValue{} p.ConfigMapValue = (*ObjectKeyRef)(orig.ConfigMapValue) } if orig.SecretValue != nil { + p.SingleValue = &SingleValue{} p.SecretValue = (*ObjectKeyRef)(orig.SecretValue) } diff --git a/pkg/apis/build/v1beta1/buildrun_conversion.go b/pkg/apis/build/v1beta1/buildrun_conversion.go index cb7d64811b..637f835001 100644 --- a/pkg/apis/build/v1beta1/buildrun_conversion.go +++ b/pkg/apis/build/v1beta1/buildrun_conversion.go @@ -13,6 +13,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/utils/ptr" ) // ensure v1beta1 implements the Conversion interface @@ -42,8 +43,16 @@ func (src *BuildRun) ConvertTo(ctx context.Context, obj *unstructured.Unstructur } // BuildRunSpec ServiceAccount - alphaBuildRun.Spec.ServiceAccount = &v1alpha1.ServiceAccount{ - Name: src.Spec.ServiceAccount, + // With the deprecation of serviceAccount.Generate, serviceAccount is set to ".generate" to have the SA created on fly. + if src.Spec.ServiceAccount != nil && *src.Spec.ServiceAccount == ".generate" { + alphaBuildRun.Spec.ServiceAccount = &v1alpha1.ServiceAccount{ + Name: &src.ObjectMeta.Name, + Generate: ptr.To[bool](true), + } + } else { + alphaBuildRun.Spec.ServiceAccount = &v1alpha1.ServiceAccount{ + Name: src.Spec.ServiceAccount, + } } // BuildRunSpec Timeout @@ -142,6 +151,14 @@ func (src *BuildRun) ConvertFrom(ctx context.Context, obj *unstructured.Unstruct conditions = append(conditions, ct) } + if alphaBuildRun.Status.FailureDetails != nil { + src.Status.FailureDetails = &FailureDetails{ + Reason: alphaBuildRun.Status.FailureDetails.Reason, + Message: alphaBuildRun.Status.FailureDetails.Message, + Location: (*Location)(alphaBuildRun.Status.FailureDetails.Location), + } + } + src.Status = BuildRunStatus{ Sources: sources, Output: (*Output)(alphaBuildRun.Status.Output), diff --git a/pkg/apis/build/v1beta1/buildstrategy_conversion.go b/pkg/apis/build/v1beta1/buildstrategy_conversion.go index ae803999f8..6ec1101f9b 100644 --- a/pkg/apis/build/v1beta1/buildstrategy_conversion.go +++ b/pkg/apis/build/v1beta1/buildstrategy_conversion.go @@ -14,7 +14,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" runtime "k8s.io/apimachinery/pkg/runtime" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" ) // ensure v1beta1 implements the Conversion interface @@ -213,7 +213,7 @@ func (src *BuildStrategySpec) ConvertFrom(bs v1alpha1.BuildStrategySpec) { Name: "dockerfile", Description: "The Dockerfile to be built.", Type: ParameterTypeString, - Default: pointer.String("Dockerfile"), + Default: ptr.To[string]("Dockerfile"), }) } diff --git a/pkg/config/config.go b/pkg/config/config.go index fde2657eaf..830532e2c3 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -14,7 +14,7 @@ import ( "github.com/prometheus/client_golang/prometheus" pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" corev1 "k8s.io/api/core/v1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" ) const ( @@ -85,8 +85,8 @@ var ( metricBuildRunEstablishDurationBuckets = []float64{0, 1, 2, 3, 5, 7, 10, 15, 20, 30} metricBuildRunRampUpDurationBuckets = prometheus.LinearBuckets(0, 1, 10) - root = pointer.Int64(0) - nonRoot = pointer.Int64(1000) + root = ptr.To[int64](0) + nonRoot = ptr.To[int64](1000) ) // Config hosts different parameters that @@ -162,7 +162,7 @@ func NewDefaultConfig() *Config { }, }, SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: pointer.Bool(false), + AllowPrivilegeEscalation: ptr.To[bool](false), Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{ "ALL", @@ -186,7 +186,7 @@ func NewDefaultConfig() *Config { }, }, SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: pointer.Bool(false), + AllowPrivilegeEscalation: ptr.To[bool](false), Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{ "ALL", @@ -214,7 +214,7 @@ func NewDefaultConfig() *Config { // in all possible scenarios, we run this step as root with DAC_OVERRIDE // capability. SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: pointer.Bool(false), + AllowPrivilegeEscalation: ptr.To[bool](false), RunAsUser: root, RunAsGroup: root, Capabilities: &corev1.Capabilities{ @@ -244,7 +244,7 @@ func NewDefaultConfig() *Config { }, }, SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: pointer.Bool(false), + AllowPrivilegeEscalation: ptr.To[bool](false), Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{ "ALL", diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 9520c87c3b..c5b3c50f65 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -13,7 +13,7 @@ import ( pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" . "github.com/shipwright-io/build/pkg/config" ) @@ -126,7 +126,7 @@ var _ = Describe("Config", func() { } configWithEnvVariableOverrides(overrides, func(config *Config) { - nonRoot := pointer.Int64(1000) + nonRoot := ptr.To[int64](1000) Expect(config.GitContainerTemplate).To(Equal(pipeline.Step{ Image: "myregistry/custom/git-image", Command: []string{ @@ -134,7 +134,7 @@ var _ = Describe("Config", func() { }, Env: []corev1.EnvVar{{Name: "HOME", Value: "/shared-home"}}, SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: pointer.Bool(false), + AllowPrivilegeEscalation: ptr.To[bool](false), Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{ "ALL", @@ -228,14 +228,14 @@ var _ = Describe("Config", func() { } configWithEnvVariableOverrides(overrides, func(config *Config) { - nonRoot := pointer.Int64(1000) + nonRoot := ptr.To[int64](1000) Expect(config.WaiterContainerTemplate).To(Equal(pipeline.Step{ Image: "myregistry/custom/image", Command: []string{"/ko-app/waiter"}, Args: []string{"start"}, Env: []corev1.EnvVar{{Name: "HOME", Value: "/shared-home"}}, SecurityContext: &corev1.SecurityContext{ - AllowPrivilegeEscalation: pointer.Bool(false), + AllowPrivilegeEscalation: ptr.To[bool](false), Capabilities: &corev1.Capabilities{ Drop: []corev1.Capability{ "ALL", diff --git a/pkg/image/delete_test.go b/pkg/image/delete_test.go index 0ecb592fc7..74193d1923 100644 --- a/pkg/image/delete_test.go +++ b/pkg/image/delete_test.go @@ -17,7 +17,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/random" "github.com/google/go-containerregistry/pkg/v1/remote" "github.com/shipwright-io/build/pkg/image" - "github.com/shipwright-io/build/test/utils" + utils "github.com/shipwright-io/build/test/utils/v1alpha1" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" diff --git a/pkg/reconciler/build/build.go b/pkg/reconciler/build/build.go index ba9b2a9d2c..c203e556e6 100644 --- a/pkg/reconciler/build/build.go +++ b/pkg/reconciler/build/build.go @@ -10,7 +10,7 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -113,7 +113,7 @@ func (r *ReconcileBuild) Reconcile(ctx context.Context, request reconcile.Reques } b.Status.Registered = build.ConditionStatusPtr(corev1.ConditionTrue) - b.Status.Message = pointer.String(build.AllValidationsSucceeded) + b.Status.Message = ptr.To[string](build.AllValidationsSucceeded) if err := r.client.Status().Update(ctx, b); err != nil { return reconcile.Result{}, err } diff --git a/pkg/reconciler/build/build_test.go b/pkg/reconciler/build/build_test.go index f22136fcfe..3de36f0ec5 100644 --- a/pkg/reconciler/build/build_test.go +++ b/pkg/reconciler/build/build_test.go @@ -15,7 +15,7 @@ import ( "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" crc "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -24,7 +24,7 @@ import ( "github.com/shipwright-io/build/pkg/config" "github.com/shipwright-io/build/pkg/controller/fakes" buildController "github.com/shipwright-io/build/pkg/reconciler/build" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" ) var _ = Describe("Reconcile Build", func() { @@ -371,7 +371,7 @@ var _ = Describe("Reconcile Build", func() { Context("when source URL is specified", func() { // validate file protocol It("fails when source URL is invalid", func() { - buildSample.Spec.Source.URL = pointer.String("foobar") + buildSample.Spec.Source.URL = ptr.To[string]("foobar") buildSample.SetAnnotations(map[string]string{ build.AnnotationBuildVerifyRepository: "true", }) @@ -385,7 +385,7 @@ var _ = Describe("Reconcile Build", func() { // validate https protocol It("fails when public source URL is unreachable", func() { - buildSample.Spec.Source.URL = pointer.String("https://github.com/shipwright-io/sample-go-fake") + buildSample.Spec.Source.URL = ptr.To[string]("https://github.com/shipwright-io/sample-go-fake") buildSample.SetAnnotations(map[string]string{ build.AnnotationBuildVerifyRepository: "true", }) @@ -400,7 +400,7 @@ var _ = Describe("Reconcile Build", func() { // skip validation because of empty sourceURL annotation It("succeed when source URL is invalid because source annotation is empty", func() { - buildSample.Spec.Source.URL = pointer.String("foobar") + buildSample.Spec.Source.URL = ptr.To[string]("foobar") // Fake some client Get calls and ensure we populate all // different resources we could get during reconciliation @@ -451,7 +451,7 @@ var _ = Describe("Reconcile Build", func() { // skip validation because build references a sourceURL secret It("succeed when source URL is fake private URL because build reference a sourceURL secret", func() { buildSample := ctl.BuildWithClusterBuildStrategyAndSourceSecret(buildName, namespace, buildStrategyName) - buildSample.Spec.Source.URL = pointer.String("https://github.yourco.com/org/build-fake") + buildSample.Spec.Source.URL = ptr.To[string]("https://github.yourco.com/org/build-fake") buildSample.Spec.Source.Credentials.Name = registrySecret // Fake some client Get calls and ensure we populate all diff --git a/pkg/reconciler/buildrun/buildrun.go b/pkg/reconciler/buildrun/buildrun.go index 7c6840d526..82e730385b 100644 --- a/pkg/reconciler/buildrun/buildrun.go +++ b/pkg/reconciler/buildrun/buildrun.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/validation" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/reconcile" @@ -182,7 +182,7 @@ func (r *ReconcileBuildRun) Reconcile(ctx context.Context, request reconcile.Req // mark transient build as "registered" and validated build.Status.Registered = buildv1alpha1.ConditionStatusPtr(corev1.ConditionTrue) build.Status.Reason = buildv1alpha1.BuildReasonPtr(buildv1alpha1.SucceedStatus) - build.Status.Message = pointer.String(buildv1alpha1.AllValidationsSucceeded) + build.Status.Message = ptr.To[string](buildv1alpha1.AllValidationsSucceeded) } } @@ -220,7 +220,7 @@ func (r *ReconcileBuildRun) Reconcile(ctx context.Context, request reconcile.Req if build.GetAnnotations()[buildv1alpha1.AnnotationBuildRunDeletion] == "true" && !resources.IsOwnedByBuild(build, buildRun.OwnerReferences) { if err := r.setOwnerReferenceFunc(build, buildRun, r.scheme); err != nil { build.Status.Reason = buildv1alpha1.BuildReasonPtr(buildv1alpha1.SetOwnerReferenceFailed) - build.Status.Message = pointer.String(fmt.Sprintf("unexpected error when trying to set the ownerreference: %v", err)) + build.Status.Message = ptr.To[string](fmt.Sprintf("unexpected error when trying to set the ownerreference: %v", err)) if err := r.client.Status().Update(ctx, build); err != nil { return reconcile.Result{}, err } diff --git a/pkg/reconciler/buildrun/buildrun_test.go b/pkg/reconciler/buildrun/buildrun_test.go index d7817d942a..3eb3f499d6 100644 --- a/pkg/reconciler/buildrun/buildrun_test.go +++ b/pkg/reconciler/buildrun/buildrun_test.go @@ -21,7 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes/scheme" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" knativeapi "knative.dev/pkg/apis" knativev1 "knative.dev/pkg/apis/duck/v1" crc "sigs.k8s.io/controller-runtime/pkg/client" @@ -34,7 +34,7 @@ import ( "github.com/shipwright-io/build/pkg/controller/fakes" buildrunctl "github.com/shipwright-io/build/pkg/reconciler/buildrun" "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" ) var _ = Describe("Reconcile BuildRun", func() { @@ -1177,8 +1177,8 @@ var _ = Describe("Reconcile BuildRun", func() { // in the build clientUpdateCalls := ctl.StubBuildUpdateOwnerReferences("Build", buildName, - pointer.Bool(true), - pointer.Bool(true), + ptr.To[bool](true), + ptr.To[bool](true), ) client.UpdateCalls(clientUpdateCalls) @@ -1365,7 +1365,7 @@ var _ = Describe("Reconcile BuildRun", func() { Spec: build.BuildRunSpec{ ParamValues: []build.ParamValue{{ Name: "foo", - SingleValue: &build.SingleValue{Value: pointer.String("bar")}, + SingleValue: &build.SingleValue{Value: ptr.To[string]("bar")}, }}, BuildSpec: &build.BuildSpec{}, }, @@ -1421,8 +1421,8 @@ var _ = Describe("Reconcile BuildRun", func() { Spec: build.BuildRunSpec{ BuildSpec: &build.BuildSpec{ Source: build.Source{ - URL: pointer.String("https://github.com/shipwright-io/sample-go.git"), - ContextDir: pointer.String("source-build"), + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go.git"), + ContextDir: ptr.To[string]("source-build"), }, Strategy: build.Strategy{ Kind: &clusterBuildStrategy, @@ -1433,7 +1433,7 @@ var _ = Describe("Reconcile BuildRun", func() { }, }, ServiceAccount: &build.ServiceAccount{ - Generate: pointer.Bool(true), + Generate: ptr.To[bool](true), }, }, } diff --git a/pkg/reconciler/buildrun/resources/build_test.go b/pkg/reconciler/buildrun/resources/build_test.go index 25cf9ffb33..c559f1447f 100644 --- a/pkg/reconciler/buildrun/resources/build_test.go +++ b/pkg/reconciler/buildrun/resources/build_test.go @@ -20,7 +20,7 @@ import ( 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" + test "github.com/shipwright-io/build/test/v1alpha1_samples" ) var _ = Describe("Build Resource", func() { diff --git a/pkg/reconciler/buildrun/resources/conditions_test.go b/pkg/reconciler/buildrun/resources/conditions_test.go index 0560f6fc40..d9306fdd30 100644 --- a/pkg/reconciler/buildrun/resources/conditions_test.go +++ b/pkg/reconciler/buildrun/resources/conditions_test.go @@ -12,7 +12,7 @@ import ( 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" + test "github.com/shipwright-io/build/test/v1alpha1_samples" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" diff --git a/pkg/reconciler/buildrun/resources/credentials_test.go b/pkg/reconciler/buildrun/resources/credentials_test.go index 24c74e4552..361d96b4b2 100644 --- a/pkg/reconciler/buildrun/resources/credentials_test.go +++ b/pkg/reconciler/buildrun/resources/credentials_test.go @@ -11,13 +11,13 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" ) -var _ = Describe("Credentials", func() { +var _ = Describe("Credentials", func() { var ( build *buildv1alpha1.Build buildRun *buildv1alpha1.BuildRun @@ -33,12 +33,12 @@ var _ = Describe("Credentials", func() { } }) - Context("when secrets were not present in the service account", func() { + Context("when secrets were not present in the service account", func() { BeforeEach(func() { build = &buildv1alpha1.Build{ Spec: buildv1alpha1.BuildSpec{ Source: buildv1alpha1.Source{ - URL: pointer.String("a/b/c"), + URL: ptr.To[string]("a/b/c"), Credentials: &corev1.LocalObjectReference{ Name: "secret_a", }, @@ -89,12 +89,12 @@ var _ = Describe("Credentials", func() { }) }) - Context("when secrets were already in the service account", func() { + Context("when secrets were already in the service account", func() { BeforeEach(func() { build = &buildv1alpha1.Build{ Spec: buildv1alpha1.BuildSpec{ Source: buildv1alpha1.Source{ - URL: pointer.String("a/b/c"), + URL: ptr.To[string]("a/b/c"), }, Output: buildv1alpha1.Image{ Credentials: &corev1.LocalObjectReference{ @@ -126,12 +126,12 @@ var _ = Describe("Credentials", func() { }) }) - Context("when build does not reference any secret", func() { + Context("when build does not reference any secret", func() { BeforeEach(func() { build = &buildv1alpha1.Build{ Spec: buildv1alpha1.BuildSpec{ Source: buildv1alpha1.Source{ - URL: pointer.String("a/b/c"), + URL: ptr.To[string]("a/b/c"), Credentials: nil, }, }, diff --git a/pkg/reconciler/buildrun/resources/image_processing_test.go b/pkg/reconciler/buildrun/resources/image_processing_test.go index c67ecf772c..ebaaa0d741 100644 --- a/pkg/reconciler/buildrun/resources/image_processing_test.go +++ b/pkg/reconciler/buildrun/resources/image_processing_test.go @@ -13,7 +13,7 @@ import ( buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" "github.com/shipwright-io/build/pkg/config" "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" - "github.com/shipwright-io/build/test/utils" + utils "github.com/shipwright-io/build/test/utils/v1alpha1" pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" ) diff --git a/pkg/reconciler/buildrun/resources/params_test.go b/pkg/reconciler/buildrun/resources/params_test.go index ad61c6183a..5dd805a012 100644 --- a/pkg/reconciler/buildrun/resources/params_test.go +++ b/pkg/reconciler/buildrun/resources/params_test.go @@ -12,7 +12,7 @@ import ( "github.com/onsi/gomega/types" corev1 "k8s.io/api/core/v1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" pipeline "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" @@ -28,22 +28,22 @@ var _ = Describe("Params overrides", func() { Entry("override a single parameter", []buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, }, []buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("3"), + Value: ptr.To[string]("3"), }}, }, ContainElements([]buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("3"), + Value: ptr.To[string]("3"), }}, })), Entry("override two parameters", []buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, {Name: "b", SingleValue: &buildv1alpha1.SingleValue{ SecretValue: &buildv1alpha1.ObjectKeyRef{ @@ -53,7 +53,7 @@ var _ = Describe("Params overrides", func() { }}, }, []buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("3"), + Value: ptr.To[string]("3"), }}, {Name: "b", SingleValue: &buildv1alpha1.SingleValue{ ConfigMapValue: &buildv1alpha1.ObjectKeyRef{ @@ -63,7 +63,7 @@ var _ = Describe("Params overrides", func() { }}, }, ContainElements([]buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("3"), + Value: ptr.To[string]("3"), }}, {Name: "b", SingleValue: &buildv1alpha1.SingleValue{ ConfigMapValue: &buildv1alpha1.ObjectKeyRef{ @@ -76,43 +76,43 @@ var _ = Describe("Params overrides", func() { Entry("override multiple parameters", []buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, {Name: "b", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, {Name: "c", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, }, []buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("6"), + Value: ptr.To[string]("6"), }}, {Name: "c", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("6"), + Value: ptr.To[string]("6"), }}, }, ContainElements([]buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("6"), + Value: ptr.To[string]("6"), }}, {Name: "b", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, {Name: "c", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("6"), + Value: ptr.To[string]("6"), }}, })), Entry("dont override when second list is empty", []buildv1alpha1.ParamValue{ {Name: "t", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, {Name: "z", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, {Name: "g", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, }, []buildv1alpha1.ParamValue{ @@ -120,13 +120,13 @@ var _ = Describe("Params overrides", func() { }, ContainElements([]buildv1alpha1.ParamValue{ {Name: "t", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, {Name: "z", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, {Name: "g", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, })), @@ -135,56 +135,56 @@ var _ = Describe("Params overrides", func() { // no original values }, []buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("6"), + Value: ptr.To[string]("6"), }}, {Name: "c", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("6"), + Value: ptr.To[string]("6"), }}, }, ContainElements([]buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("6"), + Value: ptr.To[string]("6"), }}, {Name: "c", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("6"), + Value: ptr.To[string]("6"), }}, })), Entry("override multiple parameters if the match and add them if not present in first list", []buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("2"), + Value: ptr.To[string]("2"), }}, }, []buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("22"), + Value: ptr.To[string]("22"), }}, {Name: "b", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("20"), + Value: ptr.To[string]("20"), }}, {Name: "c", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("10"), + Value: ptr.To[string]("10"), }}, {Name: "d", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("8"), + Value: ptr.To[string]("8"), }}, {Name: "e", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("4"), + Value: ptr.To[string]("4"), }}, }, ContainElements([]buildv1alpha1.ParamValue{ {Name: "a", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("22"), + Value: ptr.To[string]("22"), }}, {Name: "b", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("20"), + Value: ptr.To[string]("20"), }}, {Name: "c", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("10"), + Value: ptr.To[string]("10"), }}, {Name: "d", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("8"), + Value: ptr.To[string]("8"), }}, {Name: "e", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("4"), + Value: ptr.To[string]("4"), }}, })), ) @@ -244,13 +244,13 @@ var _ = Describe("FindParamValueByName", func() { paramValues := []buildv1alpha1.ParamValue{{ Name: "some-parameter", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("some-value"), + Value: ptr.To[string]("some-value"), }, }, { Name: "another-parameter", Values: []buildv1alpha1.SingleValue{ { - Value: pointer.String("item"), + Value: ptr.To[string]("item"), }, { ConfigMapValue: &buildv1alpha1.ObjectKeyRef{ @@ -262,7 +262,7 @@ var _ = Describe("FindParamValueByName", func() { }, { Name: "last-parameter", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("last-value"), + Value: ptr.To[string]("last-value"), }, }} @@ -277,7 +277,7 @@ var _ = Describe("FindParamValueByName", func() { Name: "another-parameter", Values: []buildv1alpha1.SingleValue{ { - Value: pointer.String("item"), + Value: ptr.To[string]("item"), }, { ConfigMapValue: &buildv1alpha1.ObjectKeyRef{ @@ -383,7 +383,7 @@ var _ = Describe("HandleTaskRunParam", func() { err := HandleTaskRunParam(taskRun, parameterDefinition, buildv1alpha1.ParamValue{ Name: "string-parameter", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("My value"), + Value: ptr.To[string]("My value"), }, }) Expect(err).ToNot(HaveOccurred()) @@ -449,7 +449,7 @@ var _ = Describe("HandleTaskRunParam", func() { ConfigMapValue: &buildv1alpha1.ObjectKeyRef{ Name: "config-map-name", Key: "my-key", - Format: pointer.String("The value from the config map is '${CONFIGMAP_VALUE}'."), + Format: ptr.To[string]("The value from the config map is '${CONFIGMAP_VALUE}'."), }, }, }) @@ -536,7 +536,7 @@ var _ = Describe("HandleTaskRunParam", func() { SecretValue: &buildv1alpha1.ObjectKeyRef{ Name: "secret-name", Key: "secret-key", - Format: pointer.String("secret-value: ${SECRET_VALUE}"), + Format: ptr.To[string]("secret-value: ${SECRET_VALUE}"), }, }, }) @@ -586,13 +586,13 @@ var _ = Describe("HandleTaskRunParam", func() { Name: "array-parameter", Values: []buildv1alpha1.SingleValue{ { - Value: pointer.String("first entry"), + Value: ptr.To[string]("first entry"), }, { - Value: pointer.String(""), + Value: ptr.To[string](""), }, { - Value: pointer.String("third entry"), + Value: ptr.To[string]("third entry"), }, }, }) @@ -621,7 +621,7 @@ var _ = Describe("HandleTaskRunParam", func() { Name: "array-parameter", Values: []buildv1alpha1.SingleValue{ { - Value: pointer.String("first entry"), + Value: ptr.To[string]("first entry"), }, { SecretValue: &buildv1alpha1.ObjectKeyRef{ @@ -633,7 +633,7 @@ var _ = Describe("HandleTaskRunParam", func() { SecretValue: &buildv1alpha1.ObjectKeyRef{ Name: "secret-name", Key: "secret-key", - Format: pointer.String("The secret value is ${SECRET_VALUE}"), + Format: ptr.To[string]("The secret value is ${SECRET_VALUE}"), }, }, }, diff --git a/pkg/reconciler/buildrun/resources/results_test.go b/pkg/reconciler/buildrun/resources/results_test.go index daf63d1883..1bf4f45f10 100644 --- a/pkg/reconciler/buildrun/resources/results_test.go +++ b/pkg/reconciler/buildrun/resources/results_test.go @@ -12,11 +12,11 @@ import ( build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" pipelinev1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/reconcile" ) @@ -50,7 +50,7 @@ var _ = Describe("TaskRun results to BuildRun", func() { It("should surface the TaskRun results emitting from default(git) source step", func() { commitSha := "0e0583421a5e4bf562ffe33f3651e16ba0c78591" - br.Status.BuildSpec.Source.URL = pointer.String("https://github.com/shipwright-io/sample-go") + br.Status.BuildSpec.Source.URL = ptr.To[string]("https://github.com/shipwright-io/sample-go") tr.Status.TaskRunResults = append(tr.Status.TaskRunResults, pipelinev1beta1.TaskRunResult{ @@ -124,7 +124,7 @@ var _ = Describe("TaskRun results to BuildRun", func() { It("should surface the TaskRun results emitting from source and output step", func() { commitSha := "0e0583421a5e4bf562ffe33f3651e16ba0c78591" imageDigest := "sha256:fe1b73cd25ac3f11dec752755e2" - br.Status.BuildSpec.Source.URL = pointer.String("https://github.com/shipwright-io/sample-go") + br.Status.BuildSpec.Source.URL = ptr.To[string]("https://github.com/shipwright-io/sample-go") tr.Status.TaskRunResults = append(tr.Status.TaskRunResults, pipelinev1beta1.TaskRunResult{ diff --git a/pkg/reconciler/buildrun/resources/service_accounts.go b/pkg/reconciler/buildrun/resources/service_accounts.go index 38cd815f3d..4cf400cb0f 100644 --- a/pkg/reconciler/buildrun/resources/service_accounts.go +++ b/pkg/reconciler/buildrun/resources/service_accounts.go @@ -14,7 +14,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" ) @@ -65,7 +65,7 @@ func GenerateSA(ctx context.Context, client client.Client, build *buildv1alpha1. *metav1.NewControllerRef(buildRun, buildv1alpha1.SchemeGroupVersion.WithKind("BuildRun")), }, }, - AutomountServiceAccountToken: pointer.Bool(false), + AutomountServiceAccountToken: ptr.To[bool](false), } ctxlog.Debug(ctx, "automatic generation of service account", namespace, serviceAccount.Namespace, name, serviceAccount.Name) diff --git a/pkg/reconciler/buildrun/resources/service_accounts_test.go b/pkg/reconciler/buildrun/resources/service_accounts_test.go index 4cf4d0b91b..2e36bdfefb 100644 --- a/pkg/reconciler/buildrun/resources/service_accounts_test.go +++ b/pkg/reconciler/buildrun/resources/service_accounts_test.go @@ -13,7 +13,7 @@ import ( 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" + test "github.com/shipwright-io/build/test/v1alpha1_samples" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" diff --git a/pkg/reconciler/buildrun/resources/sources/git_test.go b/pkg/reconciler/buildrun/resources/sources/git_test.go index 19df2a68d1..3d5ef09dad 100644 --- a/pkg/reconciler/buildrun/resources/sources/git_test.go +++ b/pkg/reconciler/buildrun/resources/sources/git_test.go @@ -14,7 +14,7 @@ import ( tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" corev1 "k8s.io/api/core/v1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" ) var _ = Describe("Git", func() { @@ -31,7 +31,7 @@ var _ = Describe("Git", func() { JustBeforeEach(func() { sources.AppendGitStep(cfg, taskSpec, buildv1alpha1.Source{ - URL: pointer.String("https://github.com/shipwright-io/build"), + URL: ptr.To[string]("https://github.com/shipwright-io/build"), }, "default") }) @@ -75,7 +75,7 @@ var _ = Describe("Git", func() { JustBeforeEach(func() { sources.AppendGitStep(cfg, taskSpec, buildv1alpha1.Source{ - URL: pointer.String("git@github.com:shipwright-io/build.git"), + URL: ptr.To[string]("git@github.com:shipwright-io/build.git"), Credentials: &corev1.LocalObjectReference{ Name: "a.secret", }, diff --git a/pkg/reconciler/buildrun/resources/sources/utils.go b/pkg/reconciler/buildrun/resources/sources/utils.go index 72d837fe6f..1e8a346c0e 100644 --- a/pkg/reconciler/buildrun/resources/sources/utils.go +++ b/pkg/reconciler/buildrun/resources/sources/utils.go @@ -11,7 +11,7 @@ import ( tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" corev1 "k8s.io/api/core/v1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" ) const ( @@ -24,7 +24,7 @@ var ( dnsLabel1123Forbidden = regexp.MustCompile("[^a-zA-Z0-9-]+") // secrets are volumes and volumes are mounted as root, as we run as non-root, we must use 0444 to allow non-root to read it - secretMountMode = pointer.Int32(0444) + secretMountMode = ptr.To[int32](0444) ) // AppendSecretVolume checks if a volume for a secret already exists, if not it appends it to the TaskSpec diff --git a/pkg/reconciler/buildrun/resources/steps/security_context.go b/pkg/reconciler/buildrun/resources/steps/security_context.go index 4a866e16cf..8518d21b43 100644 --- a/pkg/reconciler/buildrun/resources/steps/security_context.go +++ b/pkg/reconciler/buildrun/resources/steps/security_context.go @@ -10,7 +10,7 @@ import ( buildapi "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" tektonapi "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" corev1 "k8s.io/api/core/v1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "k8s.io/utils/strings/slices" ) @@ -66,7 +66,7 @@ func UpdateSecurityContext(taskSpec *tektonapi.TaskSpec, taskRunAnnotations map[ Name: VolumeNameSecurityContext, VolumeSource: corev1.VolumeSource{ DownwardAPI: &corev1.DownwardAPIVolumeSource{ - DefaultMode: pointer.Int32(0444), + DefaultMode: ptr.To[int32](0444), Items: []corev1.DownwardAPIVolumeFile{{ Path: "group", diff --git a/pkg/reconciler/buildrun/resources/steps/security_context_test.go b/pkg/reconciler/buildrun/resources/steps/security_context_test.go index 64eda83c56..62b3c7300e 100644 --- a/pkg/reconciler/buildrun/resources/steps/security_context_test.go +++ b/pkg/reconciler/buildrun/resources/steps/security_context_test.go @@ -12,7 +12,7 @@ import ( buildapi "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" tektonapi "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" corev1 "k8s.io/api/core/v1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" @@ -30,15 +30,15 @@ var _ = Describe("UpdateSecurityContext", func() { Container: corev1.Container{ Name: "first-step", SecurityContext: &corev1.SecurityContext{ - RunAsUser: pointer.Int64(891), - RunAsGroup: pointer.Int64(1210), + RunAsUser: ptr.To[int64](891), + RunAsGroup: ptr.To[int64](1210), }, }, }, { Container: corev1.Container{ Name: "second-step", SecurityContext: &corev1.SecurityContext{ - RunAsUser: pointer.Int64(891), + RunAsUser: ptr.To[int64](891), }, }, }, { @@ -51,19 +51,19 @@ var _ = Describe("UpdateSecurityContext", func() { Steps: []tektonapi.Step{{ Name: "shp-source-default", SecurityContext: &corev1.SecurityContext{ - RunAsUser: pointer.Int64(1000), - RunAsGroup: pointer.Int64(1000), + RunAsUser: ptr.To[int64](1000), + RunAsGroup: ptr.To[int64](1000), }, }, { Name: "first-step", SecurityContext: &corev1.SecurityContext{ - RunAsUser: pointer.Int64(891), - RunAsGroup: pointer.Int64(1210), + RunAsUser: ptr.To[int64](891), + RunAsGroup: ptr.To[int64](1210), }, }, { Name: "second-step", SecurityContext: &corev1.SecurityContext{ - RunAsUser: pointer.Int64(891), + RunAsUser: ptr.To[int64](891), }, }, { Name: "third-step", @@ -83,11 +83,11 @@ var _ = Describe("UpdateSecurityContext", func() { }) It("does not change the step's securityContext", func() { - Expect(taskRunSpec.Steps[0].SecurityContext.RunAsUser).To(Equal(pointer.Int64(1000))) - Expect(taskRunSpec.Steps[0].SecurityContext.RunAsGroup).To(Equal(pointer.Int64(1000))) - Expect(taskRunSpec.Steps[1].SecurityContext.RunAsUser).To(Equal(pointer.Int64(891))) - Expect(taskRunSpec.Steps[1].SecurityContext.RunAsGroup).To(Equal(pointer.Int64(1210))) - Expect(taskRunSpec.Steps[2].SecurityContext.RunAsUser).To(Equal(pointer.Int64(891))) + Expect(taskRunSpec.Steps[0].SecurityContext.RunAsUser).To(Equal(ptr.To[int64](1000))) + Expect(taskRunSpec.Steps[0].SecurityContext.RunAsGroup).To(Equal(ptr.To[int64](1000))) + Expect(taskRunSpec.Steps[1].SecurityContext.RunAsUser).To(Equal(ptr.To[int64](891))) + Expect(taskRunSpec.Steps[1].SecurityContext.RunAsGroup).To(Equal(ptr.To[int64](1210))) + Expect(taskRunSpec.Steps[2].SecurityContext.RunAsUser).To(Equal(ptr.To[int64](891))) Expect(taskRunSpec.Steps[2].SecurityContext.RunAsGroup).To(BeNil()) Expect(taskRunSpec.Steps[3].SecurityContext).To(BeNil()) }) @@ -115,24 +115,24 @@ var _ = Describe("UpdateSecurityContext", func() { }) It("changes the securityContext of shipwright-managed steps", func() { - Expect(taskRunSpec.Steps[0].SecurityContext.RunAsUser).To(Equal(pointer.Int64(123))) - Expect(taskRunSpec.Steps[0].SecurityContext.RunAsGroup).To(Equal(pointer.Int64(456))) + Expect(taskRunSpec.Steps[0].SecurityContext.RunAsUser).To(Equal(ptr.To[int64](123))) + Expect(taskRunSpec.Steps[0].SecurityContext.RunAsGroup).To(Equal(ptr.To[int64](456))) }) It("does not change the securityContext of a strategy step that has runAsUser and runAsGroup set", func() { - Expect(taskRunSpec.Steps[1].SecurityContext.RunAsUser).To(Equal(pointer.Int64(891))) - Expect(taskRunSpec.Steps[1].SecurityContext.RunAsGroup).To(Equal(pointer.Int64(1210))) + Expect(taskRunSpec.Steps[1].SecurityContext.RunAsUser).To(Equal(ptr.To[int64](891))) + Expect(taskRunSpec.Steps[1].SecurityContext.RunAsGroup).To(Equal(ptr.To[int64](1210))) }) It("changes the securityContext of a strategy step that does not have both runAsUser and runAsGroup set", func() { - Expect(taskRunSpec.Steps[2].SecurityContext.RunAsUser).To(Equal(pointer.Int64(891))) - Expect(taskRunSpec.Steps[2].SecurityContext.RunAsGroup).To(Equal(pointer.Int64(456))) + Expect(taskRunSpec.Steps[2].SecurityContext.RunAsUser).To(Equal(ptr.To[int64](891))) + Expect(taskRunSpec.Steps[2].SecurityContext.RunAsGroup).To(Equal(ptr.To[int64](456))) }) It("introduces a securityContext for a strategy step that does not have one", func() { Expect(taskRunSpec.Steps[3].SecurityContext).ToNot(BeNil()) - Expect(taskRunSpec.Steps[3].SecurityContext.RunAsUser).To(Equal(pointer.Int64(123))) - Expect(taskRunSpec.Steps[3].SecurityContext.RunAsGroup).To(Equal(pointer.Int64(456))) + Expect(taskRunSpec.Steps[3].SecurityContext.RunAsUser).To(Equal(ptr.To[int64](123))) + Expect(taskRunSpec.Steps[3].SecurityContext.RunAsGroup).To(Equal(ptr.To[int64](456))) }) It("adds annotations", func() { @@ -147,7 +147,7 @@ var _ = Describe("UpdateSecurityContext", func() { Name: steps.VolumeNameSecurityContext, VolumeSource: corev1.VolumeSource{ DownwardAPI: &corev1.DownwardAPIVolumeSource{ - DefaultMode: pointer.Int32(0444), + DefaultMode: ptr.To[int32](0444), Items: []corev1.DownwardAPIVolumeFile{{ Path: "group", diff --git a/pkg/reconciler/buildrun/resources/strategies_test.go b/pkg/reconciler/buildrun/resources/strategies_test.go index e4dab4ef70..8e6a5f5f25 100644 --- a/pkg/reconciler/buildrun/resources/strategies_test.go +++ b/pkg/reconciler/buildrun/resources/strategies_test.go @@ -12,7 +12,7 @@ import ( 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" + test "github.com/shipwright-io/build/test/v1alpha1_samples" k8serrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" diff --git a/pkg/reconciler/buildrun/resources/taskrun_test.go b/pkg/reconciler/buildrun/resources/taskrun_test.go index edae526f45..0dabfe4380 100644 --- a/pkg/reconciler/buildrun/resources/taskrun_test.go +++ b/pkg/reconciler/buildrun/resources/taskrun_test.go @@ -22,8 +22,8 @@ import ( "github.com/shipwright-io/build/pkg/config" "github.com/shipwright-io/build/pkg/env" "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" - "github.com/shipwright-io/build/test" - "github.com/shipwright-io/build/test/utils" + utils "github.com/shipwright-io/build/test/utils/v1alpha1" + test "github.com/shipwright-io/build/test/v1alpha1_samples" ) var _ = Describe("GenerateTaskrun", func() { diff --git a/pkg/validate/buildname.go b/pkg/validate/buildname.go index 1eaa83c1f5..2bac3686a9 100644 --- a/pkg/validate/buildname.go +++ b/pkg/validate/buildname.go @@ -9,7 +9,7 @@ import ( "strings" "k8s.io/apimachinery/pkg/util/validation" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" ) @@ -29,7 +29,7 @@ func NewBuildName(build *build.Build) *BuildNameRef { func (b *BuildNameRef) ValidatePath(_ context.Context) error { if errs := validation.IsValidLabelValue(b.Build.Name); len(errs) > 0 { b.Build.Status.Reason = build.BuildReasonPtr(build.BuildNameInvalid) - b.Build.Status.Message = pointer.String(strings.Join(errs, ", ")) + b.Build.Status.Message = ptr.To[string](strings.Join(errs, ", ")) } return nil diff --git a/pkg/validate/envvars.go b/pkg/validate/envvars.go index 6d116b78ad..fb23a2d2e4 100644 --- a/pkg/validate/envvars.go +++ b/pkg/validate/envvars.go @@ -10,7 +10,7 @@ import ( corev1 "k8s.io/api/core/v1" kerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" ) @@ -47,13 +47,13 @@ func (e *Env) validate(envVar corev1.EnvVar) []error { if envVar.Name == "" { e.Build.Status.Reason = build.BuildReasonPtr(build.SpecEnvNameCanNotBeBlank) - e.Build.Status.Message = pointer.String("name for environment variable must not be blank") + e.Build.Status.Message = ptr.To[string]("name for environment variable must not be blank") allErrs = append(allErrs, fmt.Errorf("%s", *e.Build.Status.Message)) } if envVar.Value != "" && envVar.ValueFrom != nil { e.Build.Status.Reason = build.BuildReasonPtr(build.SpecEnvOnlyOneOfValueOrValueFromMustBeSpecified) - e.Build.Status.Message = pointer.String("only one of value or valueFrom must be specified") + e.Build.Status.Message = ptr.To[string]("only one of value or valueFrom must be specified") allErrs = append(allErrs, fmt.Errorf("%s", *e.Build.Status.Message)) } diff --git a/pkg/validate/envvars_test.go b/pkg/validate/envvars_test.go index 293de3e5ac..f548238ea4 100644 --- a/pkg/validate/envvars_test.go +++ b/pkg/validate/envvars_test.go @@ -11,7 +11,7 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" "github.com/shipwright-io/build/pkg/validate" @@ -34,7 +34,7 @@ var _ = Describe("Env", func() { err := validate.NewEnv(b).ValidatePath(context.TODO()) Expect(err).To(HaveOccurred()) Expect(b.Status.Reason).To(Equal(build.BuildReasonPtr(build.SpecEnvNameCanNotBeBlank))) - Expect(b.Status.Message).To(Equal(pointer.String("name for environment variable must not be blank"))) + Expect(b.Status.Message).To(Equal(ptr.To[string]("name for environment variable must not be blank"))) }) It("should fail in case of specifying both value and valueFrom", func() { @@ -57,7 +57,7 @@ var _ = Describe("Env", func() { err := validate.NewEnv(b).ValidatePath(context.TODO()) Expect(err).To(HaveOccurred()) Expect(b.Status.Reason).To(Equal(build.BuildReasonPtr(build.SpecEnvOnlyOneOfValueOrValueFromMustBeSpecified))) - Expect(b.Status.Message).To(Equal(pointer.String("only one of value or valueFrom must be specified"))) + Expect(b.Status.Message).To(Equal(ptr.To[string]("only one of value or valueFrom must be specified"))) }) It("should pass in case no env var are set", func() { diff --git a/pkg/validate/ownerreferences.go b/pkg/validate/ownerreferences.go index 2a39c8fe83..65f8cc405a 100644 --- a/pkg/validate/ownerreferences.go +++ b/pkg/validate/ownerreferences.go @@ -11,7 +11,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -44,7 +44,7 @@ func (o OwnerRef) ValidatePath(ctx context.Context) error { if index := o.validateBuildOwnerReference(buildRun.OwnerReferences); index == -1 { if err := controllerutil.SetControllerReference(o.Build, &buildRun, o.Scheme); err != nil { o.Build.Status.Reason = build.BuildReasonPtr(build.SetOwnerReferenceFailed) - o.Build.Status.Message = pointer.String(fmt.Sprintf("unexpected error when trying to set the ownerreference: %v", err)) + o.Build.Status.Message = ptr.To[string](fmt.Sprintf("unexpected error when trying to set the ownerreference: %v", err)) } if err = o.Client.Update(ctx, &buildRun); err != nil { return err diff --git a/pkg/validate/params_test.go b/pkg/validate/params_test.go index 66bc57c15c..dc5f8072da 100644 --- a/pkg/validate/params_test.go +++ b/pkg/validate/params_test.go @@ -7,8 +7,7 @@ package validate_test import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" "github.com/shipwright-io/build/pkg/validate" @@ -23,7 +22,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { { Name: "string-param-with-default", Type: buildv1alpha1.ParameterTypeString, - Default: pointer.String("default value"), + Default: ptr.To[string]("default value"), }, { Name: "array-param-no-defaults", @@ -41,7 +40,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { { Name: "string-param-no-default", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("a value"), + Value: ptr.To[string]("a value"), }, }, } @@ -92,7 +91,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { { Name: "string-param-with-default", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String(""), + Value: ptr.To[string](""), }, }, } @@ -143,7 +142,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { { Name: "string-param-no-default", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("a value"), + Value: ptr.To[string]("a value"), }, }, { @@ -156,7 +155,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { { Name: "shp-source-context", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("/my-source"), + Value: ptr.To[string]("/my-source"), }, }, } @@ -174,7 +173,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { { Name: "string-param-no-default", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("a value"), + Value: ptr.To[string]("a value"), }, }, { @@ -191,7 +190,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { { Name: "non-existing-parameter", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("my value"), + Value: ptr.To[string]("my value"), }, }, } @@ -211,7 +210,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { { Name: "string-param-no-default", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("a value"), + Value: ptr.To[string]("a value"), ConfigMapValue: &buildv1alpha1.ObjectKeyRef{ Name: "a-config-map", Key: "a-key", @@ -225,7 +224,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { Name: "array-param-no-defaults", Values: []buildv1alpha1.SingleValue{ { - Value: pointer.String("a good item"), + Value: ptr.To[string]("a good item"), }, { ConfigMapValue: &buildv1alpha1.ObjectKeyRef{ @@ -257,7 +256,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { Name: "string-param-no-default", Values: []buildv1alpha1.SingleValue{ { - Value: pointer.String("an item"), + Value: ptr.To[string]("an item"), }, { ConfigMapValue: &buildv1alpha1.ObjectKeyRef{ @@ -273,7 +272,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { { Name: "array-param-no-defaults", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String("a value"), + Value: ptr.To[string]("a value"), }, }, } @@ -293,7 +292,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { { Name: "string-param-no-default", SingleValue: &buildv1alpha1.SingleValue{ - Value: pointer.String(" some value"), + Value: ptr.To[string](" some value"), }, }, { @@ -311,7 +310,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { Name: "array-param-no-defaults", Values: []buildv1alpha1.SingleValue{ { - Value: pointer.String("a good item"), + Value: ptr.To[string]("a good item"), }, { // the bad item without any value @@ -353,7 +352,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { Name: "array-param-no-defaults", Values: []buildv1alpha1.SingleValue{ { - Value: pointer.String("an item"), + Value: ptr.To[string]("an item"), }, { ConfigMapValue: &buildv1alpha1.ObjectKeyRef{ @@ -391,7 +390,7 @@ var _ = Describe("ValidateBuildRunParameters", func() { Name: "array-param-no-defaults", Values: []buildv1alpha1.SingleValue{ { - Value: pointer.String("an item"), + Value: ptr.To[string]("an item"), }, { SecretValue: &buildv1alpha1.ObjectKeyRef{ diff --git a/pkg/validate/secrets.go b/pkg/validate/secrets.go index 5e3692e0c6..a124c3b0b6 100644 --- a/pkg/validate/secrets.go +++ b/pkg/validate/secrets.go @@ -13,7 +13,7 @@ import ( corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" @@ -43,7 +43,7 @@ func (s Credentials) ValidatePath(ctx context.Context) error { return err } else if apierrors.IsNotFound(err) { s.Build.Status.Reason = build.BuildReasonPtr(secretType) - s.Build.Status.Message = pointer.String(fmt.Sprintf("referenced secret %s not found", refSecret)) + s.Build.Status.Message = ptr.To[string](fmt.Sprintf("referenced secret %s not found", refSecret)) missingSecrets = append(missingSecrets, refSecret) } } @@ -53,7 +53,7 @@ func (s Credentials) ValidatePath(ctx context.Context) error { if len(missingSecrets) > 1 { s.Build.Status.Reason = build.BuildReasonPtr(build.MultipleSecretRefNotFound) - s.Build.Status.Message = pointer.String(fmt.Sprintf("missing secrets are %s", strings.Join(missingSecrets, ","))) + s.Build.Status.Message = ptr.To[string](fmt.Sprintf("missing secrets are %s", strings.Join(missingSecrets, ","))) } return nil } diff --git a/pkg/validate/sourceurl.go b/pkg/validate/sourceurl.go index c724d423b7..7d9c21caee 100644 --- a/pkg/validate/sourceurl.go +++ b/pkg/validate/sourceurl.go @@ -8,7 +8,7 @@ import ( "context" "fmt" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" @@ -56,5 +56,5 @@ func (s SourceURLRef) ValidatePath(ctx context.Context) error { // MarkBuildStatus updates a Build Status fields func (s SourceURLRef) MarkBuildStatus(b *build.Build, reason build.BuildReason, msg string) { b.Status.Reason = build.BuildReasonPtr(reason) - b.Status.Message = pointer.String(msg) + b.Status.Message = ptr.To[string](msg) } diff --git a/pkg/validate/strategies.go b/pkg/validate/strategies.go index 56a24d253a..4013c3127e 100644 --- a/pkg/validate/strategies.go +++ b/pkg/validate/strategies.go @@ -10,7 +10,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" @@ -75,7 +75,7 @@ func (s Strategy) validateBuildStrategy(ctx context.Context, strategyName string return false, err } else if apierrors.IsNotFound(err) { s.Build.Status.Reason = build.BuildReasonPtr(build.BuildStrategyNotFound) - s.Build.Status.Message = pointer.String(fmt.Sprintf("buildStrategy %s does not exist in namespace %s", s.Build.Spec.Strategy.Name, s.Build.Namespace)) + s.Build.Status.Message = ptr.To[string](fmt.Sprintf("buildStrategy %s does not exist in namespace %s", s.Build.Spec.Strategy.Name, s.Build.Namespace)) return false, nil } return true, nil @@ -86,7 +86,7 @@ func (s Strategy) validateClusterBuildStrategy(ctx context.Context, strategyName return false, err } else if apierrors.IsNotFound(err) { s.Build.Status.Reason = build.BuildReasonPtr(build.ClusterBuildStrategyNotFound) - s.Build.Status.Message = pointer.String(fmt.Sprintf("clusterBuildStrategy %s does not exist", s.Build.Spec.Strategy.Name)) + s.Build.Status.Message = ptr.To[string](fmt.Sprintf("clusterBuildStrategy %s does not exist", s.Build.Spec.Strategy.Name)) return false, nil } return true, nil @@ -97,7 +97,7 @@ func (s Strategy) validateBuildParams(parameterDefinitions []build.Parameter) { if !valid { s.Build.Status.Reason = build.BuildReasonPtr(reason) - s.Build.Status.Message = pointer.String(message) + s.Build.Status.Message = ptr.To[string](message) } } @@ -106,6 +106,6 @@ func (s Strategy) validateBuildVolumes(strategyVolumes []build.BuildStrategyVolu if !valid { s.Build.Status.Reason = build.BuildReasonPtr(reason) - s.Build.Status.Message = pointer.String(message) + s.Build.Status.Message = ptr.To[string](message) } } diff --git a/pkg/validate/trigger.go b/pkg/validate/trigger.go index 562aafea1f..bd3160f209 100644 --- a/pkg/validate/trigger.go +++ b/pkg/validate/trigger.go @@ -9,7 +9,7 @@ import ( build "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" kerrors "k8s.io/apimachinery/pkg/util/errors" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" ) // Trigger implements the interface BuildPath with the objective of applying validations against the @@ -24,7 +24,7 @@ func (t *Trigger) validate(triggerWhen []build.TriggerWhen) []error { for _, when := range triggerWhen { if when.Name == "" { t.build.Status.Reason = build.BuildReasonPtr(build.TriggerNameCanNotBeBlank) - t.build.Status.Message = pointer.String("name is not set on when trigger condition") + t.build.Status.Message = ptr.To[string]("name is not set on when trigger condition") allErrs = append(allErrs, fmt.Errorf("%s", *t.build.Status.Message)) } @@ -32,14 +32,14 @@ func (t *Trigger) validate(triggerWhen []build.TriggerWhen) []error { case build.GitHubWebHookTrigger: if when.GitHub == nil { t.build.Status.Reason = build.BuildReasonPtr(build.TriggerInvalidGitHubWebHook) - t.build.Status.Message = pointer.String(fmt.Sprintf( + t.build.Status.Message = ptr.To[string](fmt.Sprintf( "%q is missing required attribute `.github`", when.Name, )) allErrs = append(allErrs, fmt.Errorf("%s", *t.build.Status.Message)) } else { if len(when.GitHub.Events) == 0 { t.build.Status.Reason = build.BuildReasonPtr(build.TriggerInvalidGitHubWebHook) - t.build.Status.Message = pointer.String(fmt.Sprintf( + t.build.Status.Message = ptr.To[string](fmt.Sprintf( "%q is missing required attribute `.github.events`", when.Name, )) allErrs = append(allErrs, fmt.Errorf("%s", *t.build.Status.Message)) @@ -48,14 +48,14 @@ func (t *Trigger) validate(triggerWhen []build.TriggerWhen) []error { case build.ImageTrigger: if when.Image == nil { t.build.Status.Reason = build.BuildReasonPtr(build.TriggerInvalidImage) - t.build.Status.Message = pointer.String(fmt.Sprintf( + t.build.Status.Message = ptr.To[string](fmt.Sprintf( "%q is missing required attribute `.image`", when.Name, )) allErrs = append(allErrs, fmt.Errorf("%s", *t.build.Status.Message)) } else { if len(when.Image.Names) == 0 { t.build.Status.Reason = build.BuildReasonPtr(build.TriggerInvalidImage) - t.build.Status.Message = pointer.String(fmt.Sprintf( + t.build.Status.Message = ptr.To[string](fmt.Sprintf( "%q is missing required attribute `.image.names`", when.Name, )) allErrs = append(allErrs, fmt.Errorf("%s", *t.build.Status.Message)) @@ -64,21 +64,21 @@ func (t *Trigger) validate(triggerWhen []build.TriggerWhen) []error { case build.PipelineTrigger: if when.ObjectRef == nil { t.build.Status.Reason = build.BuildReasonPtr(build.TriggerInvalidPipeline) - t.build.Status.Message = pointer.String(fmt.Sprintf( + t.build.Status.Message = ptr.To[string](fmt.Sprintf( "%q is missing required attribute `.objectRef`", when.Name, )) allErrs = append(allErrs, fmt.Errorf("%s", *t.build.Status.Message)) } else { if len(when.ObjectRef.Status) == 0 { t.build.Status.Reason = build.BuildReasonPtr(build.TriggerInvalidPipeline) - t.build.Status.Message = pointer.String(fmt.Sprintf( + t.build.Status.Message = ptr.To[string](fmt.Sprintf( "%q is missing required attribute `.objectRef.status`", when.Name, )) allErrs = append(allErrs, fmt.Errorf("%s", *t.build.Status.Message)) } if when.ObjectRef.Name == "" && len(when.ObjectRef.Selector) == 0 { t.build.Status.Reason = build.BuildReasonPtr(build.TriggerInvalidPipeline) - t.build.Status.Message = pointer.String(fmt.Sprintf( + t.build.Status.Message = ptr.To[string](fmt.Sprintf( "%q is missing required attributes `.objectRef.name` or `.objectRef.selector`", when.Name, )) @@ -86,7 +86,7 @@ func (t *Trigger) validate(triggerWhen []build.TriggerWhen) []error { } if when.ObjectRef.Name != "" && len(when.ObjectRef.Selector) > 0 { t.build.Status.Reason = build.BuildReasonPtr(build.TriggerInvalidPipeline) - t.build.Status.Message = pointer.String(fmt.Sprintf( + t.build.Status.Message = ptr.To[string](fmt.Sprintf( "%q contains `.objectRef.name` and `.objectRef.selector`, must be only one", when.Name, )) @@ -95,7 +95,7 @@ func (t *Trigger) validate(triggerWhen []build.TriggerWhen) []error { } default: t.build.Status.Reason = build.BuildReasonPtr(build.TriggerInvalidType) - t.build.Status.Message = pointer.String( + t.build.Status.Message = ptr.To[string]( fmt.Sprintf("%q contains an invalid type %q", when.Name, when.Type)) allErrs = append(allErrs, fmt.Errorf("%s", *t.build.Status.Message)) } diff --git a/pkg/webhook/conversion/converter_test.go b/pkg/webhook/conversion/converter_test.go index f9d3780386..6ecdc7e40a 100644 --- a/pkg/webhook/conversion/converter_test.go +++ b/pkg/webhook/conversion/converter_test.go @@ -22,7 +22,7 @@ import ( "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/serializer/json" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" ) func getConversionReview(o string) (apiextensionsv1.ConversionReview, error) { @@ -497,7 +497,7 @@ request: }, }, Retention: &v1beta1.BuildRetention{ - AtBuildDeletion: pointer.Bool(true), + AtBuildDeletion: ptr.To[bool](true), }, Trigger: &v1beta1.Trigger{ When: []v1beta1.TriggerWhen{ @@ -1157,7 +1157,7 @@ request: Name: "dockerfile", Description: "The Dockerfile to be built.", Type: v1beta1.ParameterTypeString, - Default: pointer.String("Dockerfile"), + Default: ptr.To[string]("Dockerfile"), }, }, SecurityContext: &v1beta1.BuildStrategySecurityContext{ diff --git a/samples/v1alpha1/build/build_buildah_shipwright_managed_push_cr.yaml b/samples/v1alpha1/build/build_buildah_shipwright_managed_push_cr.yaml new file mode 100644 index 0000000000..820c5109cc --- /dev/null +++ b/samples/v1alpha1/build/build_buildah_shipwright_managed_push_cr.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildah-golang-build +spec: + source: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + strategy: + name: buildah-shipwright-managed-push + kind: ClusterBuildStrategy + dockerfile: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/build/build_buildah_strategy_managed_push_cr.yaml b/samples/v1alpha1/build/build_buildah_strategy_managed_push_cr.yaml new file mode 100644 index 0000000000..e641a2822a --- /dev/null +++ b/samples/v1alpha1/build/build_buildah_strategy_managed_push_cr.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildah-golang-build +spec: + source: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + strategy: + name: buildah-strategy-managed-push + kind: ClusterBuildStrategy + dockerfile: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/build/build_buildkit_cr.yaml b/samples/v1alpha1/build/build_buildkit_cr.yaml new file mode 100644 index 0000000000..32f03169f1 --- /dev/null +++ b/samples/v1alpha1/build/build_buildkit_cr.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildkit-build + annotations: + build.shipwright.io/build-run-deletion: "true" +spec: + source: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + paramValues: + - name: platforms + values: + - value: linux/amd64 + - value: linux/arm64 + strategy: + name: buildkit + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app + diff --git a/samples/v1alpha1/build/build_buildpacks-v3-heroku_cr.yaml b/samples/v1alpha1/build/build_buildpacks-v3-heroku_cr.yaml new file mode 100644 index 0000000000..c666eca31e --- /dev/null +++ b/samples/v1alpha1/build/build_buildpacks-v3-heroku_cr.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildpack-nodejs-build-heroku +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build-heroku + strategy: + name: buildpacks-v3-heroku + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/build/build_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1alpha1/build/build_buildpacks-v3-heroku_namespaced_cr.yaml new file mode 100644 index 0000000000..b6278d6597 --- /dev/null +++ b/samples/v1alpha1/build/build_buildpacks-v3-heroku_namespaced_cr.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildpack-nodejs-build-namespaced-heroku +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build-heroku + strategy: + name: buildpacks-v3-heroku + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/build/build_buildpacks-v3_cr.yaml b/samples/v1alpha1/build/build_buildpacks-v3_cr.yaml new file mode 100644 index 0000000000..fef649e1a4 --- /dev/null +++ b/samples/v1alpha1/build/build_buildpacks-v3_cr.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildpack-nodejs-build + annotations: + build.shipwright.io/build-run-deletion: "false" +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build + strategy: + name: buildpacks-v3 + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/build/build_buildpacks-v3_namespaced_cr.yaml b/samples/v1alpha1/build/build_buildpacks-v3_namespaced_cr.yaml new file mode 100644 index 0000000000..670efe1119 --- /dev/null +++ b/samples/v1alpha1/build/build_buildpacks-v3_namespaced_cr.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildpack-nodejs-build-namespaced +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build + strategy: + name: buildpacks-v3 + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/build/build_kaniko-trivy-bad_cr.yaml b/samples/v1alpha1/build/build_kaniko-trivy-bad_cr.yaml new file mode 100644 index 0000000000..8752a8cd6a --- /dev/null +++ b/samples/v1alpha1/build/build_kaniko-trivy-bad_cr.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: kaniko-trivy-bad-build + annotations: + build.shipwright.io/build-run-deletion: "true" +spec: + source: + url: https://github.com/shipwright-io/sample-scanning + strategy: + name: kaniko-trivy + kind: ClusterBuildStrategy + dockerfile: Dockerfile.bad + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/bad-trivy diff --git a/samples/v1alpha1/build/build_kaniko-trivy-good_cr.yaml b/samples/v1alpha1/build/build_kaniko-trivy-good_cr.yaml new file mode 100644 index 0000000000..6cc8e41be0 --- /dev/null +++ b/samples/v1alpha1/build/build_kaniko-trivy-good_cr.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: kaniko-trivy-good-build + annotations: + build.shipwright.io/build-run-deletion: "true" +spec: + source: + url: https://github.com/shipwright-io/sample-scanning + strategy: + name: kaniko-trivy + kind: ClusterBuildStrategy + dockerfile: Dockerfile.good + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/good-trivy diff --git a/samples/v1alpha1/build/build_kaniko_cr.yaml b/samples/v1alpha1/build/build_kaniko_cr.yaml new file mode 100644 index 0000000000..014940884d --- /dev/null +++ b/samples/v1alpha1/build/build_kaniko_cr.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: kaniko-golang-build + annotations: + build.shipwright.io/build-run-deletion: "true" +spec: + source: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + strategy: + name: kaniko + kind: ClusterBuildStrategy + dockerfile: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/build/build_ko_cr.yaml b/samples/v1alpha1/build/build_ko_cr.yaml new file mode 100644 index 0000000000..93af59096d --- /dev/null +++ b/samples/v1alpha1/build/build_ko_cr.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: ko-build + annotations: + build.shipwright.io/build-run-deletion: "false" +spec: + paramValues: + - name: go-flags + value: "-v -mod=vendor -ldflags=-w" + - name: go-version + value: "1.20" + - name: package-directory + value: ./cmd/shipwright-build-controller + source: + url: https://github.com/shipwright-io/build + strategy: + name: ko + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/shipwright-build diff --git a/samples/v1alpha1/build/build_source-to-image_cr.yaml b/samples/v1alpha1/build/build_source-to-image_cr.yaml new file mode 100644 index 0000000000..c9a64b58bf --- /dev/null +++ b/samples/v1alpha1/build/build_source-to-image_cr.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: s2i-nodejs-build +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build/ + strategy: + name: source-to-image + kind: ClusterBuildStrategy + builder: + image: docker.io/centos/nodejs-10-centos7 + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/nodejs-ex diff --git a/samples/v1alpha1/buildrun/buildrun_buildah_cr.yaml b/samples/v1alpha1/buildrun/buildrun_buildah_cr.yaml new file mode 100644 index 0000000000..c34fccc47a --- /dev/null +++ b/samples/v1alpha1/buildrun/buildrun_buildah_cr.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildah-golang-buildrun +spec: + buildRef: + name: buildah-golang-build diff --git a/samples/v1alpha1/buildrun/buildrun_buildkit_cr.yaml b/samples/v1alpha1/buildrun/buildrun_buildkit_cr.yaml new file mode 100644 index 0000000000..2ba036e0b6 --- /dev/null +++ b/samples/v1alpha1/buildrun/buildrun_buildkit_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildkit-buildrun +spec: + buildRef: + name: buildkit-build + serviceAccount: + generate: true diff --git a/test/data/buildrun_buildpacks-v3_nodejs_runtime-image_cr.yaml b/samples/v1alpha1/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml similarity index 100% rename from test/data/buildrun_buildpacks-v3_nodejs_runtime-image_cr.yaml rename to samples/v1alpha1/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml diff --git a/samples/v1alpha1/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1alpha1/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml new file mode 100644 index 0000000000..dac3232d9f --- /dev/null +++ b/samples/v1alpha1/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-buildrun-namespaced-heroku +spec: + buildRef: + name: buildpack-nodejs-build-namespaced-heroku + serviceAccount: + generate: true diff --git a/samples/v1alpha1/buildrun/buildrun_buildpacks-v3_cr.yaml b/samples/v1alpha1/buildrun/buildrun_buildpacks-v3_cr.yaml new file mode 100644 index 0000000000..39b6439a17 --- /dev/null +++ b/samples/v1alpha1/buildrun/buildrun_buildpacks-v3_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-buildrun +spec: + buildRef: + name: buildpack-nodejs-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml b/samples/v1alpha1/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml new file mode 100644 index 0000000000..a2f48ee823 --- /dev/null +++ b/samples/v1alpha1/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-buildrun-namespaced +spec: + buildRef: + name: buildpack-nodejs-build-namespaced + serviceAccount: + generate: true diff --git a/samples/v1alpha1/buildrun/buildrun_kaniko-trivy-bad_cr.yaml b/samples/v1alpha1/buildrun/buildrun_kaniko-trivy-bad_cr.yaml new file mode 100644 index 0000000000..7e55cb8601 --- /dev/null +++ b/samples/v1alpha1/buildrun/buildrun_kaniko-trivy-bad_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: kaniko-trivy-bad-buildrun +spec: + buildRef: + name: kaniko-trivy-bad-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/buildrun/buildrun_kaniko-trivy-good_cr.yaml b/samples/v1alpha1/buildrun/buildrun_kaniko-trivy-good_cr.yaml new file mode 100644 index 0000000000..4d657f3c6b --- /dev/null +++ b/samples/v1alpha1/buildrun/buildrun_kaniko-trivy-good_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: kaniko-trivy-good-buildrun +spec: + buildRef: + name: kaniko-trivy-good-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/buildrun/buildrun_kaniko_cr.yaml b/samples/v1alpha1/buildrun/buildrun_kaniko_cr.yaml new file mode 100644 index 0000000000..227c3d0a0c --- /dev/null +++ b/samples/v1alpha1/buildrun/buildrun_kaniko_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: kaniko-golang-buildrun +spec: + buildRef: + name: kaniko-golang-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/buildrun/buildrun_ko_cr.yaml b/samples/v1alpha1/buildrun/buildrun_ko_cr.yaml new file mode 100644 index 0000000000..a7857afd33 --- /dev/null +++ b/samples/v1alpha1/buildrun/buildrun_ko_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: ko-buildrun +spec: + buildRef: + name: ko-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/buildrun/buildrun_source-to-image_cr.yaml b/samples/v1alpha1/buildrun/buildrun_source-to-image_cr.yaml new file mode 100644 index 0000000000..196cf0a5f2 --- /dev/null +++ b/samples/v1alpha1/buildrun/buildrun_source-to-image_cr.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: s2i-nodejs-buildrun +spec: + buildRef: + name: s2i-nodejs-build diff --git a/samples/v1alpha1/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml b/samples/v1alpha1/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml new file mode 100644 index 0000000000..c95c2f6da2 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml @@ -0,0 +1,204 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildah-shipwright-managed-push +spec: + buildSteps: + - name: build + image: quay.io/containers/buildah:v1.32.0 + workingDir: $(params.shp-source-root) + securityContext: + privileged: true + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Parse parameters + context= + dockerfile= + image= + target= + buildArgs=() + inBuildArgs=false + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + while [[ $# -gt 0 ]]; do + arg="$1" + shift + + if [ "${arg}" == "--context" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + context="$1" + shift + elif [ "${arg}" == "--dockerfile" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + dockerfile="$1" + shift + elif [ "${arg}" == "--image" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--target" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + target="$1" + shift + elif [ "${arg}" == "--build-args" ]; then + inBuildArgs=true + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inBuildArgs=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inBuildArgs}" == "true" ]; then + buildArgs+=("--build-arg" "${arg}") + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + + # Verify the existence of the context directory + if [ ! -d "${context}" ]; then + echo -e "The context directory '${context}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${context}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + cd "${context}" + + # Verify the existence of the Dockerfile + if [ ! -f "${dockerfile}" ]; then + echo -e "The Dockerfile '${dockerfile}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${dockerfile}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + + EOF + fi + + # Building the image + echo "[INFO] Building image ${image}" + buildah --storage-driver=$(params.storage-driver) \ + bud "${buildArgs[@]}" \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" \ + --file="${dockerfile}" \ + . + + # Write the image + echo "[INFO] Writing image ${image}" + buildah --storage-driver=$(params.storage-driver) push \ + "${image}" \ + "oci:${target}" + # That's the separator between the shell script and its args + - -- + - --context + - $(params.shp-source-context) + - --dockerfile + - $(build.dockerfile) + - --image + - $(params.shp-output-image) + - --build-args + - $(params.build-args[*]) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + - --target + - $(params.shp-output-directory) + resources: + limits: + cpu: "1" + memory: 2Gi + requests: + cpu: 250m + memory: 65Mi + parameters: + - name: build-args + description: "The values for the args in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + - name: storage-driver + description: "The storage driver to use, such as 'overlay' or 'vfs'." + type: string + default: "vfs" + # For details see the "--storage-driver" section of https://github.com/containers/buildah/blob/main/docs/buildah.1.md#options + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml b/samples/v1alpha1/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml new file mode 100644 index 0000000000..03075863cf --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml @@ -0,0 +1,204 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildah-strategy-managed-push +spec: + buildSteps: + - name: build-and-push + image: quay.io/containers/buildah:v1.32.0 + workingDir: $(params.shp-source-root) + securityContext: + capabilities: + add: + - "SETFCAP" + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Parse parameters + context= + dockerfile= + image= + buildArgs=() + inBuildArgs=false + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + tlsVerify=true + while [[ $# -gt 0 ]]; do + arg="$1" + shift + + if [ "${arg}" == "--context" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + context="$1" + shift + elif [ "${arg}" == "--dockerfile" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + dockerfile="$1" + shift + elif [ "${arg}" == "--image" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--build-args" ]; then + inBuildArgs=true + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inBuildArgs=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inBuildArgs}" == "true" ]; then + buildArgs+=("--build-arg" "${arg}") + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + + # This assumes that the image is passed before the insecure registries which is fair in this context + if [[ ${image} == ${arg}/* ]]; then + tlsVerify=false + fi + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + + # Verify the existence of the context directory + if [ ! -d "${context}" ]; then + echo -e "The context directory '${context}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${context}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + cd "${context}" + + # Verify the existence of the Dockerfile + if [ ! -f "${dockerfile}" ]; then + echo -e "The Dockerfile '${dockerfile}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${dockerfile}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + + EOF + fi + + # Building the image + echo "[INFO] Building image ${image}" + buildah --storage-driver=$(params.storage-driver) \ + bud "${buildArgs[@]}" \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" \ + --file="${dockerfile}" \ + . + + # Push the image + echo "[INFO] Pushing image ${image}" + buildah --storage-driver=$(params.storage-driver) push \ + --digestfile='$(results.shp-image-digest.path)' \ + --tls-verify="${tlsVerify}" \ + "${image}" \ + "docker://${image}" + # That's the separator between the shell script and its args + - -- + - --context + - $(params.shp-source-context) + - --dockerfile + - $(build.dockerfile) + - --image + - $(params.shp-output-image) + - --build-args + - $(params.build-args[*]) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + resources: + limits: + cpu: "1" + memory: 2Gi + requests: + cpu: 250m + memory: 65Mi + parameters: + - name: build-args + description: "The values for the args in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + - name: storage-driver + description: "The storage driver to use, such as 'overlay' or 'vfs'" + type: string + default: "vfs" + # For details see the "--storage-driver" section of https://github.com/containers/buildah/blob/main/docs/buildah.1.md#options + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml b/samples/v1alpha1/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml new file mode 100644 index 0000000000..ff329d5483 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml @@ -0,0 +1,170 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildkit + annotations: + # See https://github.com/moby/buildkit/blob/master/docs/rootless.md#about---oci-worker-no-process-sandbox for more information + container.apparmor.security.beta.kubernetes.io/step-build-and-push: unconfined + # The usage of seccomp annotation will be deprecate in k8s v1.22.0, see + # https://kubernetes.io/docs/tutorials/clusters/seccomp/#create-a-pod-with-a-seccomp-profile-for-syscall-auditing for more information + container.seccomp.security.alpha.kubernetes.io/step-build-and-push: unconfined +spec: + parameters: + - name: build-args + description: "The values for the ARGs in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: cache + description: "Configure BuildKit's cache usage. Allowed values are 'disabled' and 'registry'. The default is 'registry'." + type: string + default: registry + - name: platforms + description: "Build the image for different platforms. By default, the image is built for the platform used by the FROM image. If that is present for multiple platforms, then it is built for the environment's platform." + type: array + defaults: [] + - name: secrets + description: "The secrets to pass to the build. Values must be in the format ID=FILE_CONTENT." + type: array + defaults: [] + buildSteps: + - name: build-and-push + image: moby/buildkit:nightly-rootless + imagePullPolicy: Always + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - SETGID + - SETUID + workingDir: $(params.shp-source-root) + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + # See https://github.com/moby/buildkit/blob/master/docs/rootless.md#about---oci-worker-no-process-sandbox for more information + - name: BUILDKITD_FLAGS + value: --oci-worker-no-process-sandbox + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_DOCKERFILE + value: $(params.DOCKERFILE) + - name: PARAM_OUTPUT_DIRECTORY + value: $(params.shp-output-directory) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + - name: PARAM_OUTPUT_INSECURE + value: $(params.shp-output-insecure) + - name: PARAM_CACHE + value: $(params.cache) + command: + - /bin/ash + args: + - -c + - | + set -euo pipefail + + # Verify the existence of the context directory + if [ ! -d "${PARAM_SOURCE_CONTEXT}" ]; then + echo -e "The context directory '${PARAM_SOURCE_CONTEXT}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${PARAM_SOURCE_CONTEXT}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + # Prepare the file arguments + DOCKERFILE_PATH="${PARAM_SOURCE_CONTEXT}/${PARAM_DOCKERFILE}" + DOCKERFILE_DIR="$(dirname "${DOCKERFILE_PATH}")" + DOCKERFILE_NAME="$(basename "${DOCKERFILE_PATH}")" + + # Verify the existence of the Dockerfile + if [ ! -f "${DOCKERFILE_PATH}" ]; then + echo -e "The Dockerfile '${DOCKERFILE_PATH}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${DOCKERFILE_PATH}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + # We only have ash here and therefore no bash arrays to help add dynamic arguments (the build-args) to the build command. + + echo "#!/bin/ash" > /tmp/run.sh + echo "set -euo pipefail" >> /tmp/run.sh + echo "buildctl-daemonless.sh \\" >> /tmp/run.sh + echo "build \\" >> /tmp/run.sh + echo "--frontend=dockerfile.v0 \\" >> /tmp/run.sh + echo "--opt=filename=\"${DOCKERFILE_NAME}\" \\" >> /tmp/run.sh + echo "--local=context=\"${PARAM_SOURCE_CONTEXT}\" \\" >> /tmp/run.sh + echo "--local=dockerfile=\"${DOCKERFILE_DIR}\" \\" >> /tmp/run.sh + echo "--output=type=oci,tar=false,dest=\"${PARAM_OUTPUT_DIRECTORY}\" \\" >> /tmp/run.sh + if [ "${PARAM_CACHE}" == "registry" ]; then + echo "--export-cache=type=inline \\" >> /tmp/run.sh + echo "--import-cache=type=registry,ref=\"${PARAM_OUTPUT_IMAGE}\",registry.insecure=\"${PARAM_OUTPUT_INSECURE}\" \\" >> /tmp/run.sh + elif [ "${PARAM_CACHE}" == "disabled" ]; then + echo "--no-cache \\" >> /tmp/run.sh + else + echo -e "An invalid value for the parameter 'cache' has been provided: '${PARAM_CACHE}'. Allowed values are 'disabled' and 'registry'." + echo -n "InvalidParameterValue" > '$(results.shp-error-reason.path)' + echo -n "An invalid value for the parameter 'cache' has been provided: '${PARAM_CACHE}'. Allowed values are 'disabled' and 'registry'." > '$(results.shp-error-message.path)' + exit 1 + fi + + stage="" + platforms="" + for a in "$@" + do + if [ "${a}" == "--build-args" ]; then + stage=build-args + elif [ "${a}" == "--platforms" ]; then + stage=platforms + elif [ "${a}" == "--secrets" ]; then + stage=secrets + elif [ "${stage}" == "build-args" ]; then + echo "--opt=\"build-arg:${a}\" \\" >> /tmp/run.sh + elif [ "${stage}" == "platforms" ]; then + if [ "${platforms}" == "" ]; then + platforms="${a}" + else + platforms="${platforms},${a}" + fi + elif [ "${stage}" == "secrets" ]; then + # Split ID=FILE_CONTENT into variables id and data + + # using head because the data could be multiline + id="$(echo "${a}" | head -1 | sed 's/=.*//')" + + # This is hacky, we remove the suffix ${id}= from all lines of the data. + # If the data would be multiple lines and a line would start with ${id}= + # then we would remove it. We could force users to give us the secret + # base64 encoded. But ultimately, the best solution might be if the user + # mounts the secret and just gives us the path here. + data="$(echo "${a}" | sed "s/^${id}=//")" + + # Write the secret data into a temporary file, once we have volume support + # in the build strategy, we should use a memory based emptyDir for this. + echo -n "${data}" > "/tmp/secret_${id}" + + # Add the secret argument + echo "--secret id=${id},src="/tmp/secret_${id}" \\" >> /tmp/run.sh + fi + done + + if [ "${platforms}" != "" ]; then + echo "--opt=\"platform=${platforms}\" \\" >> /tmp/run.sh + fi + + echo "--progress=plain" >> /tmp/run.sh + + chmod +x /tmp/run.sh + /tmp/run.sh + # That's the separator between the shell script and its args + - -- + - --build-args + - $(params.build-args[*]) + - --platforms + - $(params.platforms[*]) + - --secrets + - $(params.secrets[*]) + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml b/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml new file mode 100644 index 0000000000..61eca36ee8 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildpacks-v3-heroku +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: heroku/builder:22 + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml new file mode 100644 index 0000000000..aa01340555 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: buildpacks-v3-heroku +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: heroku/builder:22 + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml b/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml new file mode 100644 index 0000000000..f4c11a65f1 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildpacks-v3 +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: docker.io/paketobuildpacks/builder-jammy-full:latest + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1001 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml b/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml new file mode 100644 index 0000000000..32dcadc67c --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: buildpacks-v3 +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: docker.io/paketobuildpacks/builder-jammy-full:latest + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1001 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml new file mode 100644 index 0000000000..c95c2f6da2 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml @@ -0,0 +1,204 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildah-shipwright-managed-push +spec: + buildSteps: + - name: build + image: quay.io/containers/buildah:v1.32.0 + workingDir: $(params.shp-source-root) + securityContext: + privileged: true + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Parse parameters + context= + dockerfile= + image= + target= + buildArgs=() + inBuildArgs=false + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + while [[ $# -gt 0 ]]; do + arg="$1" + shift + + if [ "${arg}" == "--context" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + context="$1" + shift + elif [ "${arg}" == "--dockerfile" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + dockerfile="$1" + shift + elif [ "${arg}" == "--image" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--target" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + target="$1" + shift + elif [ "${arg}" == "--build-args" ]; then + inBuildArgs=true + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inBuildArgs=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inBuildArgs}" == "true" ]; then + buildArgs+=("--build-arg" "${arg}") + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + + # Verify the existence of the context directory + if [ ! -d "${context}" ]; then + echo -e "The context directory '${context}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${context}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + cd "${context}" + + # Verify the existence of the Dockerfile + if [ ! -f "${dockerfile}" ]; then + echo -e "The Dockerfile '${dockerfile}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${dockerfile}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + + EOF + fi + + # Building the image + echo "[INFO] Building image ${image}" + buildah --storage-driver=$(params.storage-driver) \ + bud "${buildArgs[@]}" \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" \ + --file="${dockerfile}" \ + . + + # Write the image + echo "[INFO] Writing image ${image}" + buildah --storage-driver=$(params.storage-driver) push \ + "${image}" \ + "oci:${target}" + # That's the separator between the shell script and its args + - -- + - --context + - $(params.shp-source-context) + - --dockerfile + - $(build.dockerfile) + - --image + - $(params.shp-output-image) + - --build-args + - $(params.build-args[*]) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + - --target + - $(params.shp-output-directory) + resources: + limits: + cpu: "1" + memory: 2Gi + requests: + cpu: 250m + memory: 65Mi + parameters: + - name: build-args + description: "The values for the args in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + - name: storage-driver + description: "The storage driver to use, such as 'overlay' or 'vfs'." + type: string + default: "vfs" + # For details see the "--storage-driver" section of https://github.com/containers/buildah/blob/main/docs/buildah.1.md#options + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml new file mode 100644 index 0000000000..03075863cf --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml @@ -0,0 +1,204 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildah-strategy-managed-push +spec: + buildSteps: + - name: build-and-push + image: quay.io/containers/buildah:v1.32.0 + workingDir: $(params.shp-source-root) + securityContext: + capabilities: + add: + - "SETFCAP" + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Parse parameters + context= + dockerfile= + image= + buildArgs=() + inBuildArgs=false + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + tlsVerify=true + while [[ $# -gt 0 ]]; do + arg="$1" + shift + + if [ "${arg}" == "--context" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + context="$1" + shift + elif [ "${arg}" == "--dockerfile" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + dockerfile="$1" + shift + elif [ "${arg}" == "--image" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--build-args" ]; then + inBuildArgs=true + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inBuildArgs=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inBuildArgs}" == "true" ]; then + buildArgs+=("--build-arg" "${arg}") + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + + # This assumes that the image is passed before the insecure registries which is fair in this context + if [[ ${image} == ${arg}/* ]]; then + tlsVerify=false + fi + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + + # Verify the existence of the context directory + if [ ! -d "${context}" ]; then + echo -e "The context directory '${context}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${context}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + cd "${context}" + + # Verify the existence of the Dockerfile + if [ ! -f "${dockerfile}" ]; then + echo -e "The Dockerfile '${dockerfile}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${dockerfile}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + + EOF + fi + + # Building the image + echo "[INFO] Building image ${image}" + buildah --storage-driver=$(params.storage-driver) \ + bud "${buildArgs[@]}" \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" \ + --file="${dockerfile}" \ + . + + # Push the image + echo "[INFO] Pushing image ${image}" + buildah --storage-driver=$(params.storage-driver) push \ + --digestfile='$(results.shp-image-digest.path)' \ + --tls-verify="${tlsVerify}" \ + "${image}" \ + "docker://${image}" + # That's the separator between the shell script and its args + - -- + - --context + - $(params.shp-source-context) + - --dockerfile + - $(build.dockerfile) + - --image + - $(params.shp-output-image) + - --build-args + - $(params.build-args[*]) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + resources: + limits: + cpu: "1" + memory: 2Gi + requests: + cpu: 250m + memory: 65Mi + parameters: + - name: build-args + description: "The values for the args in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + - name: storage-driver + description: "The storage driver to use, such as 'overlay' or 'vfs'" + type: string + default: "vfs" + # For details see the "--storage-driver" section of https://github.com/containers/buildah/blob/main/docs/buildah.1.md#options + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml new file mode 100644 index 0000000000..ff329d5483 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml @@ -0,0 +1,170 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildkit + annotations: + # See https://github.com/moby/buildkit/blob/master/docs/rootless.md#about---oci-worker-no-process-sandbox for more information + container.apparmor.security.beta.kubernetes.io/step-build-and-push: unconfined + # The usage of seccomp annotation will be deprecate in k8s v1.22.0, see + # https://kubernetes.io/docs/tutorials/clusters/seccomp/#create-a-pod-with-a-seccomp-profile-for-syscall-auditing for more information + container.seccomp.security.alpha.kubernetes.io/step-build-and-push: unconfined +spec: + parameters: + - name: build-args + description: "The values for the ARGs in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: cache + description: "Configure BuildKit's cache usage. Allowed values are 'disabled' and 'registry'. The default is 'registry'." + type: string + default: registry + - name: platforms + description: "Build the image for different platforms. By default, the image is built for the platform used by the FROM image. If that is present for multiple platforms, then it is built for the environment's platform." + type: array + defaults: [] + - name: secrets + description: "The secrets to pass to the build. Values must be in the format ID=FILE_CONTENT." + type: array + defaults: [] + buildSteps: + - name: build-and-push + image: moby/buildkit:nightly-rootless + imagePullPolicy: Always + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - SETGID + - SETUID + workingDir: $(params.shp-source-root) + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + # See https://github.com/moby/buildkit/blob/master/docs/rootless.md#about---oci-worker-no-process-sandbox for more information + - name: BUILDKITD_FLAGS + value: --oci-worker-no-process-sandbox + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_DOCKERFILE + value: $(params.DOCKERFILE) + - name: PARAM_OUTPUT_DIRECTORY + value: $(params.shp-output-directory) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + - name: PARAM_OUTPUT_INSECURE + value: $(params.shp-output-insecure) + - name: PARAM_CACHE + value: $(params.cache) + command: + - /bin/ash + args: + - -c + - | + set -euo pipefail + + # Verify the existence of the context directory + if [ ! -d "${PARAM_SOURCE_CONTEXT}" ]; then + echo -e "The context directory '${PARAM_SOURCE_CONTEXT}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${PARAM_SOURCE_CONTEXT}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + # Prepare the file arguments + DOCKERFILE_PATH="${PARAM_SOURCE_CONTEXT}/${PARAM_DOCKERFILE}" + DOCKERFILE_DIR="$(dirname "${DOCKERFILE_PATH}")" + DOCKERFILE_NAME="$(basename "${DOCKERFILE_PATH}")" + + # Verify the existence of the Dockerfile + if [ ! -f "${DOCKERFILE_PATH}" ]; then + echo -e "The Dockerfile '${DOCKERFILE_PATH}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${DOCKERFILE_PATH}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + # We only have ash here and therefore no bash arrays to help add dynamic arguments (the build-args) to the build command. + + echo "#!/bin/ash" > /tmp/run.sh + echo "set -euo pipefail" >> /tmp/run.sh + echo "buildctl-daemonless.sh \\" >> /tmp/run.sh + echo "build \\" >> /tmp/run.sh + echo "--frontend=dockerfile.v0 \\" >> /tmp/run.sh + echo "--opt=filename=\"${DOCKERFILE_NAME}\" \\" >> /tmp/run.sh + echo "--local=context=\"${PARAM_SOURCE_CONTEXT}\" \\" >> /tmp/run.sh + echo "--local=dockerfile=\"${DOCKERFILE_DIR}\" \\" >> /tmp/run.sh + echo "--output=type=oci,tar=false,dest=\"${PARAM_OUTPUT_DIRECTORY}\" \\" >> /tmp/run.sh + if [ "${PARAM_CACHE}" == "registry" ]; then + echo "--export-cache=type=inline \\" >> /tmp/run.sh + echo "--import-cache=type=registry,ref=\"${PARAM_OUTPUT_IMAGE}\",registry.insecure=\"${PARAM_OUTPUT_INSECURE}\" \\" >> /tmp/run.sh + elif [ "${PARAM_CACHE}" == "disabled" ]; then + echo "--no-cache \\" >> /tmp/run.sh + else + echo -e "An invalid value for the parameter 'cache' has been provided: '${PARAM_CACHE}'. Allowed values are 'disabled' and 'registry'." + echo -n "InvalidParameterValue" > '$(results.shp-error-reason.path)' + echo -n "An invalid value for the parameter 'cache' has been provided: '${PARAM_CACHE}'. Allowed values are 'disabled' and 'registry'." > '$(results.shp-error-message.path)' + exit 1 + fi + + stage="" + platforms="" + for a in "$@" + do + if [ "${a}" == "--build-args" ]; then + stage=build-args + elif [ "${a}" == "--platforms" ]; then + stage=platforms + elif [ "${a}" == "--secrets" ]; then + stage=secrets + elif [ "${stage}" == "build-args" ]; then + echo "--opt=\"build-arg:${a}\" \\" >> /tmp/run.sh + elif [ "${stage}" == "platforms" ]; then + if [ "${platforms}" == "" ]; then + platforms="${a}" + else + platforms="${platforms},${a}" + fi + elif [ "${stage}" == "secrets" ]; then + # Split ID=FILE_CONTENT into variables id and data + + # using head because the data could be multiline + id="$(echo "${a}" | head -1 | sed 's/=.*//')" + + # This is hacky, we remove the suffix ${id}= from all lines of the data. + # If the data would be multiple lines and a line would start with ${id}= + # then we would remove it. We could force users to give us the secret + # base64 encoded. But ultimately, the best solution might be if the user + # mounts the secret and just gives us the path here. + data="$(echo "${a}" | sed "s/^${id}=//")" + + # Write the secret data into a temporary file, once we have volume support + # in the build strategy, we should use a memory based emptyDir for this. + echo -n "${data}" > "/tmp/secret_${id}" + + # Add the secret argument + echo "--secret id=${id},src="/tmp/secret_${id}" \\" >> /tmp/run.sh + fi + done + + if [ "${platforms}" != "" ]; then + echo "--opt=\"platform=${platforms}\" \\" >> /tmp/run.sh + fi + + echo "--progress=plain" >> /tmp/run.sh + + chmod +x /tmp/run.sh + /tmp/run.sh + # That's the separator between the shell script and its args + - -- + - --build-args + - $(params.build-args[*]) + - --platforms + - $(params.platforms[*]) + - --secrets + - $(params.secrets[*]) + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml new file mode 100644 index 0000000000..61eca36ee8 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildpacks-v3-heroku +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: heroku/builder:22 + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml new file mode 100644 index 0000000000..aa01340555 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: buildpacks-v3-heroku +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: heroku/builder:22 + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml new file mode 100644 index 0000000000..f4c11a65f1 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildpacks-v3 +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: docker.io/paketobuildpacks/builder-jammy-full:latest + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1001 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml new file mode 100644 index 0000000000..32dcadc67c --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: buildpacks-v3 +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: docker.io/paketobuildpacks/builder-jammy-full:latest + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1001 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml new file mode 100644 index 0000000000..eefbf8b258 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml @@ -0,0 +1,82 @@ +# This Build Strategy will intentionally fail if the image has any +# critical CVEs. It will not be pushed into the destination registry +# if any critical vulnerabilities are found. +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: kaniko-trivy +spec: + volumes: + - name: layout + emptyDir: {} + - name: tar + emptyDir: {} + buildSteps: + - name: kaniko-build + image: gcr.io/kaniko-project/executor:v1.16.0 + workingDir: $(params.shp-source-root) + securityContext: + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + env: + - name: HOME + value: /tekton/home + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --dockerfile + - $(build.dockerfile) + - --context + - $(params.shp-source-context) + - --destination + - $(params.shp-output-image) + - --snapshot-mode + - redo + - --no-push + - --tar-path + - $(params.shp-output-directory)/image.tar + # https://github.com/GoogleContainerTools/kaniko/issues/2164 + - --ignore-path + - /product_uuid + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + - name: trivy-scan + image: docker.io/aquasec/trivy:0.46.0 + command: + - trivy + args: + - image + - --exit-code=1 + - --severity=CRITICAL + - --input + - $(params.shp-output-directory)/image.tar + env: + - name: HOME + value: /tekton/home + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml new file mode 100644 index 0000000000..728375b0b8 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml @@ -0,0 +1,56 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: kaniko +spec: + buildSteps: + - name: build-and-push + image: gcr.io/kaniko-project/executor:v1.16.0 + workingDir: $(params.shp-source-root) + securityContext: + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + env: + - name: HOME + value: /tekton/home + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --dockerfile + - $(build.dockerfile) + - --context + - $(params.shp-source-context) + - --destination + - $(params.shp-output-image) + - --snapshot-mode + - redo + - --no-push + - --tar-path + - $(params.shp-output-directory)/image.tar + # https://github.com/GoogleContainerTools/kaniko/issues/2164 + - --ignore-path + - /product_uuid + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/ko/buildstrategy_ko_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/ko/buildstrategy_ko_cr.yaml new file mode 100644 index 0000000000..e98b0aede1 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/ko/buildstrategy_ko_cr.yaml @@ -0,0 +1,116 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: ko +spec: + parameters: + - name: go-flags + description: "Value for the GOFLAGS environment variable." + default: "" + - name: go-version + description: "Version of Go, must match a tag from https://hub.docker.com/_/golang?tab=tags" + default: "1.20" + - name: ko-version + description: "Version of ko, must be either 'latest', or a release name from https://github.com/ko-build/ko/releases" + default: latest + - name: package-directory + description: "The directory inside the context directory containing the main package." + default: "." + - name: target-platform + description: "Target platform to be built. For example: 'linux/arm64'. Multiple platforms can be provided separated by comma, for example: 'linux/arm64,linux/amd64'. The value 'all' will build all platforms supported by the base image. The value 'current' will build the platform on which the build runs." + default: current + volumes: + - name: gocache + description: "Volume to contain the GOCACHE. Can be set to a persistent volume to optimize compilation performance for rebuilds." + overridable: true + emptyDir: {} + buildSteps: + - name: build + image: golang:$(params.go-version) + imagePullPolicy: Always + workingDir: $(params.shp-source-root) + volumeMounts: + - mountPath: /gocache + name: gocache + readOnly: false + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + - name: GOFLAGS + value: $(params.go-flags) + - name: GOCACHE + value: /gocache + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + - name: PARAM_OUTPUT_DIRECTORY + value: $(params.shp-output-directory) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_SOURCE_ROOT + value: $(params.shp-source-root) + - name: PARAM_TARGET_PLATFORM + value: $(params.target-platform) + - name: PARAM_PACKAGE_DIRECTORY + value: $(params.package-directory) + - name: PARAM_KO_VERSION + value: $(params.ko-version) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Determine the ko version + KO_VERSION="${PARAM_KO_VERSION}" + if [ "${KO_VERSION}" == "latest" ]; then + KO_VERSION=$(curl --silent "https://api.github.com/repos/ko-build/ko/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + fi + + # Create one variable with v-suffix and one without as we need both for the download URL + if [[ ${KO_VERSION} = v* ]]; then + KO_VERSION_WITH_V=${KO_VERSION} + KO_VERSION_WITHOUT_V=${KO_VERSION:1} + else + KO_VERSION_WITH_V=v${KO_VERSION} + KO_VERSION_WITHOUT_V=${KO_VERSION} + fi + + # Download ko to the temp directory + curl -f -s -L "https://github.com/ko-build/ko/releases/download/${KO_VERSION_WITH_V}/ko_${KO_VERSION_WITHOUT_V}_$(uname)_$(uname -m | sed 's/aarch64/arm64/').tar.gz" | tar xzf - -C /tmp ko + + # Determine the platform + PLATFORM="${PARAM_TARGET_PLATFORM}" + if [ "${PLATFORM}" == "current" ]; then + PLATFORM="$(uname | tr '[:upper:]' '[:lower:]')/$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/')" + fi + + # Print version information + go version + echo "ko version $(/tmp/ko version)" + + # Allow directory to be owned by other user which is normal for a volume-mounted directory. + # This allows Go to run git commands to access repository metadata. + # Documentation: https://git-scm.com/docs/git-config/2.39.0#Documentation/git-config.txt-safedirectory + git config --global --add safe.directory "${PARAM_SOURCE_ROOT}" + + # Run ko + + export GOROOT="$(go env GOROOT)" + + pushd "${PARAM_SOURCE_CONTEXT}" > /dev/null + /tmp/ko build "${PARAM_PACKAGE_DIRECTORY}" --oci-layout-path="${PARAM_OUTPUT_DIRECTORY}" --platform="${PLATFORM}" --push=false + popd > /dev/null + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml new file mode 100644 index 0000000000..09ac150375 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml @@ -0,0 +1,151 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: source-to-image-redhat +spec: + volumes: + - name: s2i + emptyDir: {} + buildSteps: + - name: s2i-generate + image: registry.redhat.io/ocp-tools-43-tech-preview/source-to-image-rhel8:latest + workingDir: $(params.shp-source-root) + args: + - build + - $(params.shp-source-context) + - $(build.builder.image) + - $(params.shp-output-image) + - --as-dockerfile=/s2i/Dockerfile + volumeMounts: + - name: s2i + mountPath: /s2i + - name: buildah + image: quay.io/containers/buildah:v1.32.0 + workingDir: /s2i + securityContext: + privileged: true + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Parse parameters + image= + target= + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + while [[ $# -gt 0 ]]; do + arg="$1" + shift + + if [ "${arg}" == "--image" ]; then + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--target" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + target="$1" + shift + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + + EOF + fi + + # Building the image + echo "[INFO] Building image ${image}" + buildah bud \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" + + # Write the image + echo "[INFO] Writing image ${image}" + buildah push \ + "${image}" \ + "oci:${target}" + # That's the separator between the shell script and its args + - -- + - --image + - $(params.shp-output-image) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + - --target + - $(params.shp-output-directory) + volumeMounts: + - name: s2i + mountPath: /s2i + parameters: + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml b/samples/v1alpha1/buildstrategy/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml new file mode 100644 index 0000000000..ddadb030b0 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml @@ -0,0 +1,69 @@ +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: source-to-image +spec: + volumes: + - name: gen-source + emptyDir: {} + buildSteps: + - command: + - /usr/local/bin/s2i + - build + - $(params.shp-source-context) + - $(build.builder.image) + - '--as-dockerfile' + - /gen-source/Dockerfile.gen + image: quay.io/openshift-pipeline/s2i:nightly + imagePullPolicy: Always + name: s2i-build-as-dockerfile + volumeMounts: + - mountPath: /gen-source + name: gen-source + workingDir: $(params.shp-source-root) + - name: build-and-push + image: gcr.io/kaniko-project/executor:v1.16.0 + command: + - /kaniko/executor + args: + - --dockerfile + - /gen-source/Dockerfile.gen + - --context + - /gen-source + - --destination + - $(params.shp-output-image) + - --snapshot-mode + - redo + - --no-push + - --tar-path + - $(params.shp-output-directory)/image.tar + # https://github.com/GoogleContainerTools/kaniko/issues/2164 + - --ignore-path + - /product_uuid + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + volumeMounts: + - mountPath: /gen-source + name: gen-source + workingDir: /gen-source + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml b/samples/v1alpha1/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml new file mode 100644 index 0000000000..eefbf8b258 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml @@ -0,0 +1,82 @@ +# This Build Strategy will intentionally fail if the image has any +# critical CVEs. It will not be pushed into the destination registry +# if any critical vulnerabilities are found. +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: kaniko-trivy +spec: + volumes: + - name: layout + emptyDir: {} + - name: tar + emptyDir: {} + buildSteps: + - name: kaniko-build + image: gcr.io/kaniko-project/executor:v1.16.0 + workingDir: $(params.shp-source-root) + securityContext: + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + env: + - name: HOME + value: /tekton/home + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --dockerfile + - $(build.dockerfile) + - --context + - $(params.shp-source-context) + - --destination + - $(params.shp-output-image) + - --snapshot-mode + - redo + - --no-push + - --tar-path + - $(params.shp-output-directory)/image.tar + # https://github.com/GoogleContainerTools/kaniko/issues/2164 + - --ignore-path + - /product_uuid + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + - name: trivy-scan + image: docker.io/aquasec/trivy:0.46.0 + command: + - trivy + args: + - image + - --exit-code=1 + - --severity=CRITICAL + - --input + - $(params.shp-output-directory)/image.tar + env: + - name: HOME + value: /tekton/home + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml b/samples/v1alpha1/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml new file mode 100644 index 0000000000..728375b0b8 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml @@ -0,0 +1,56 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: kaniko +spec: + buildSteps: + - name: build-and-push + image: gcr.io/kaniko-project/executor:v1.16.0 + workingDir: $(params.shp-source-root) + securityContext: + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + env: + - name: HOME + value: /tekton/home + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --dockerfile + - $(build.dockerfile) + - --context + - $(params.shp-source-context) + - --destination + - $(params.shp-output-image) + - --snapshot-mode + - redo + - --no-push + - --tar-path + - $(params.shp-output-directory)/image.tar + # https://github.com/GoogleContainerTools/kaniko/issues/2164 + - --ignore-path + - /product_uuid + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/ko/buildstrategy_ko_cr.yaml b/samples/v1alpha1/buildstrategy/ko/buildstrategy_ko_cr.yaml new file mode 100644 index 0000000000..e98b0aede1 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/ko/buildstrategy_ko_cr.yaml @@ -0,0 +1,116 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: ko +spec: + parameters: + - name: go-flags + description: "Value for the GOFLAGS environment variable." + default: "" + - name: go-version + description: "Version of Go, must match a tag from https://hub.docker.com/_/golang?tab=tags" + default: "1.20" + - name: ko-version + description: "Version of ko, must be either 'latest', or a release name from https://github.com/ko-build/ko/releases" + default: latest + - name: package-directory + description: "The directory inside the context directory containing the main package." + default: "." + - name: target-platform + description: "Target platform to be built. For example: 'linux/arm64'. Multiple platforms can be provided separated by comma, for example: 'linux/arm64,linux/amd64'. The value 'all' will build all platforms supported by the base image. The value 'current' will build the platform on which the build runs." + default: current + volumes: + - name: gocache + description: "Volume to contain the GOCACHE. Can be set to a persistent volume to optimize compilation performance for rebuilds." + overridable: true + emptyDir: {} + buildSteps: + - name: build + image: golang:$(params.go-version) + imagePullPolicy: Always + workingDir: $(params.shp-source-root) + volumeMounts: + - mountPath: /gocache + name: gocache + readOnly: false + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + - name: GOFLAGS + value: $(params.go-flags) + - name: GOCACHE + value: /gocache + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + - name: PARAM_OUTPUT_DIRECTORY + value: $(params.shp-output-directory) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_SOURCE_ROOT + value: $(params.shp-source-root) + - name: PARAM_TARGET_PLATFORM + value: $(params.target-platform) + - name: PARAM_PACKAGE_DIRECTORY + value: $(params.package-directory) + - name: PARAM_KO_VERSION + value: $(params.ko-version) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Determine the ko version + KO_VERSION="${PARAM_KO_VERSION}" + if [ "${KO_VERSION}" == "latest" ]; then + KO_VERSION=$(curl --silent "https://api.github.com/repos/ko-build/ko/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + fi + + # Create one variable with v-suffix and one without as we need both for the download URL + if [[ ${KO_VERSION} = v* ]]; then + KO_VERSION_WITH_V=${KO_VERSION} + KO_VERSION_WITHOUT_V=${KO_VERSION:1} + else + KO_VERSION_WITH_V=v${KO_VERSION} + KO_VERSION_WITHOUT_V=${KO_VERSION} + fi + + # Download ko to the temp directory + curl -f -s -L "https://github.com/ko-build/ko/releases/download/${KO_VERSION_WITH_V}/ko_${KO_VERSION_WITHOUT_V}_$(uname)_$(uname -m | sed 's/aarch64/arm64/').tar.gz" | tar xzf - -C /tmp ko + + # Determine the platform + PLATFORM="${PARAM_TARGET_PLATFORM}" + if [ "${PLATFORM}" == "current" ]; then + PLATFORM="$(uname | tr '[:upper:]' '[:lower:]')/$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/')" + fi + + # Print version information + go version + echo "ko version $(/tmp/ko version)" + + # Allow directory to be owned by other user which is normal for a volume-mounted directory. + # This allows Go to run git commands to access repository metadata. + # Documentation: https://git-scm.com/docs/git-config/2.39.0#Documentation/git-config.txt-safedirectory + git config --global --add safe.directory "${PARAM_SOURCE_ROOT}" + + # Run ko + + export GOROOT="$(go env GOROOT)" + + pushd "${PARAM_SOURCE_CONTEXT}" > /dev/null + /tmp/ko build "${PARAM_PACKAGE_DIRECTORY}" --oci-layout-path="${PARAM_OUTPUT_DIRECTORY}" --platform="${PLATFORM}" --push=false + popd > /dev/null + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml b/samples/v1alpha1/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml new file mode 100644 index 0000000000..09ac150375 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml @@ -0,0 +1,151 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: source-to-image-redhat +spec: + volumes: + - name: s2i + emptyDir: {} + buildSteps: + - name: s2i-generate + image: registry.redhat.io/ocp-tools-43-tech-preview/source-to-image-rhel8:latest + workingDir: $(params.shp-source-root) + args: + - build + - $(params.shp-source-context) + - $(build.builder.image) + - $(params.shp-output-image) + - --as-dockerfile=/s2i/Dockerfile + volumeMounts: + - name: s2i + mountPath: /s2i + - name: buildah + image: quay.io/containers/buildah:v1.32.0 + workingDir: /s2i + securityContext: + privileged: true + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Parse parameters + image= + target= + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + while [[ $# -gt 0 ]]; do + arg="$1" + shift + + if [ "${arg}" == "--image" ]; then + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--target" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + target="$1" + shift + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + + EOF + fi + + # Building the image + echo "[INFO] Building image ${image}" + buildah bud \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" + + # Write the image + echo "[INFO] Writing image ${image}" + buildah push \ + "${image}" \ + "oci:${target}" + # That's the separator between the shell script and its args + - -- + - --image + - $(params.shp-output-image) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + - --target + - $(params.shp-output-directory) + volumeMounts: + - name: s2i + mountPath: /s2i + parameters: + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml b/samples/v1alpha1/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml new file mode 100644 index 0000000000..ddadb030b0 --- /dev/null +++ b/samples/v1alpha1/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml @@ -0,0 +1,69 @@ +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: source-to-image +spec: + volumes: + - name: gen-source + emptyDir: {} + buildSteps: + - command: + - /usr/local/bin/s2i + - build + - $(params.shp-source-context) + - $(build.builder.image) + - '--as-dockerfile' + - /gen-source/Dockerfile.gen + image: quay.io/openshift-pipeline/s2i:nightly + imagePullPolicy: Always + name: s2i-build-as-dockerfile + volumeMounts: + - mountPath: /gen-source + name: gen-source + workingDir: $(params.shp-source-root) + - name: build-and-push + image: gcr.io/kaniko-project/executor:v1.16.0 + command: + - /kaniko/executor + args: + - --dockerfile + - /gen-source/Dockerfile.gen + - --context + - /gen-source + - --destination + - $(params.shp-output-image) + - --snapshot-mode + - redo + - --no-push + - --tar-path + - $(params.shp-output-directory)/image.tar + # https://github.com/GoogleContainerTools/kaniko/issues/2164 + - --ignore-path + - /product_uuid + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + volumeMounts: + - mountPath: /gen-source + name: gen-source + workingDir: /gen-source + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/samples/build/build_buildah_shipwright_managed_push_cr.yaml b/samples/v1alpha1/samples/build/build_buildah_shipwright_managed_push_cr.yaml new file mode 100644 index 0000000000..820c5109cc --- /dev/null +++ b/samples/v1alpha1/samples/build/build_buildah_shipwright_managed_push_cr.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildah-golang-build +spec: + source: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + strategy: + name: buildah-shipwright-managed-push + kind: ClusterBuildStrategy + dockerfile: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/samples/build/build_buildah_strategy_managed_push_cr.yaml b/samples/v1alpha1/samples/build/build_buildah_strategy_managed_push_cr.yaml new file mode 100644 index 0000000000..e641a2822a --- /dev/null +++ b/samples/v1alpha1/samples/build/build_buildah_strategy_managed_push_cr.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildah-golang-build +spec: + source: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + strategy: + name: buildah-strategy-managed-push + kind: ClusterBuildStrategy + dockerfile: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/samples/build/build_buildkit_cr.yaml b/samples/v1alpha1/samples/build/build_buildkit_cr.yaml new file mode 100644 index 0000000000..32f03169f1 --- /dev/null +++ b/samples/v1alpha1/samples/build/build_buildkit_cr.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildkit-build + annotations: + build.shipwright.io/build-run-deletion: "true" +spec: + source: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + paramValues: + - name: platforms + values: + - value: linux/amd64 + - value: linux/arm64 + strategy: + name: buildkit + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app + diff --git a/samples/v1alpha1/samples/build/build_buildpacks-v3-heroku_cr.yaml b/samples/v1alpha1/samples/build/build_buildpacks-v3-heroku_cr.yaml new file mode 100644 index 0000000000..c666eca31e --- /dev/null +++ b/samples/v1alpha1/samples/build/build_buildpacks-v3-heroku_cr.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildpack-nodejs-build-heroku +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build-heroku + strategy: + name: buildpacks-v3-heroku + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/samples/build/build_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1alpha1/samples/build/build_buildpacks-v3-heroku_namespaced_cr.yaml new file mode 100644 index 0000000000..b6278d6597 --- /dev/null +++ b/samples/v1alpha1/samples/build/build_buildpacks-v3-heroku_namespaced_cr.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildpack-nodejs-build-namespaced-heroku +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build-heroku + strategy: + name: buildpacks-v3-heroku + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/samples/build/build_buildpacks-v3_cr.yaml b/samples/v1alpha1/samples/build/build_buildpacks-v3_cr.yaml new file mode 100644 index 0000000000..fef649e1a4 --- /dev/null +++ b/samples/v1alpha1/samples/build/build_buildpacks-v3_cr.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildpack-nodejs-build + annotations: + build.shipwright.io/build-run-deletion: "false" +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build + strategy: + name: buildpacks-v3 + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/samples/build/build_buildpacks-v3_namespaced_cr.yaml b/samples/v1alpha1/samples/build/build_buildpacks-v3_namespaced_cr.yaml new file mode 100644 index 0000000000..670efe1119 --- /dev/null +++ b/samples/v1alpha1/samples/build/build_buildpacks-v3_namespaced_cr.yaml @@ -0,0 +1,14 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: buildpack-nodejs-build-namespaced +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build + strategy: + name: buildpacks-v3 + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/samples/build/build_kaniko-trivy-bad_cr.yaml b/samples/v1alpha1/samples/build/build_kaniko-trivy-bad_cr.yaml new file mode 100644 index 0000000000..8752a8cd6a --- /dev/null +++ b/samples/v1alpha1/samples/build/build_kaniko-trivy-bad_cr.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: kaniko-trivy-bad-build + annotations: + build.shipwright.io/build-run-deletion: "true" +spec: + source: + url: https://github.com/shipwright-io/sample-scanning + strategy: + name: kaniko-trivy + kind: ClusterBuildStrategy + dockerfile: Dockerfile.bad + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/bad-trivy diff --git a/samples/v1alpha1/samples/build/build_kaniko-trivy-good_cr.yaml b/samples/v1alpha1/samples/build/build_kaniko-trivy-good_cr.yaml new file mode 100644 index 0000000000..6cc8e41be0 --- /dev/null +++ b/samples/v1alpha1/samples/build/build_kaniko-trivy-good_cr.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: kaniko-trivy-good-build + annotations: + build.shipwright.io/build-run-deletion: "true" +spec: + source: + url: https://github.com/shipwright-io/sample-scanning + strategy: + name: kaniko-trivy + kind: ClusterBuildStrategy + dockerfile: Dockerfile.good + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/good-trivy diff --git a/samples/v1alpha1/samples/build/build_kaniko_cr.yaml b/samples/v1alpha1/samples/build/build_kaniko_cr.yaml new file mode 100644 index 0000000000..014940884d --- /dev/null +++ b/samples/v1alpha1/samples/build/build_kaniko_cr.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: kaniko-golang-build + annotations: + build.shipwright.io/build-run-deletion: "true" +spec: + source: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + strategy: + name: kaniko + kind: ClusterBuildStrategy + dockerfile: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/samples/v1alpha1/samples/build/build_ko_cr.yaml b/samples/v1alpha1/samples/build/build_ko_cr.yaml new file mode 100644 index 0000000000..93af59096d --- /dev/null +++ b/samples/v1alpha1/samples/build/build_ko_cr.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: ko-build + annotations: + build.shipwright.io/build-run-deletion: "false" +spec: + paramValues: + - name: go-flags + value: "-v -mod=vendor -ldflags=-w" + - name: go-version + value: "1.20" + - name: package-directory + value: ./cmd/shipwright-build-controller + source: + url: https://github.com/shipwright-io/build + strategy: + name: ko + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/shipwright-build diff --git a/samples/v1alpha1/samples/build/build_source-to-image_cr.yaml b/samples/v1alpha1/samples/build/build_source-to-image_cr.yaml new file mode 100644 index 0000000000..c9a64b58bf --- /dev/null +++ b/samples/v1alpha1/samples/build/build_source-to-image_cr.yaml @@ -0,0 +1,16 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: Build +metadata: + name: s2i-nodejs-build +spec: + source: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: source-build/ + strategy: + name: source-to-image + kind: ClusterBuildStrategy + builder: + image: docker.io/centos/nodejs-10-centos7 + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/nodejs-ex diff --git a/samples/v1alpha1/samples/buildrun/buildrun_buildah_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_buildah_cr.yaml new file mode 100644 index 0000000000..c34fccc47a --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_buildah_cr.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildah-golang-buildrun +spec: + buildRef: + name: buildah-golang-build diff --git a/samples/v1alpha1/samples/buildrun/buildrun_buildkit_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_buildkit_cr.yaml new file mode 100644 index 0000000000..2ba036e0b6 --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_buildkit_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildkit-buildrun +spec: + buildRef: + name: buildkit-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml new file mode 100644 index 0000000000..b648f0f3d9 --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-buildrun-heroku +spec: + buildRef: + name: buildpack-nodejs-build-heroku + serviceAccount: + generate: true diff --git a/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml new file mode 100644 index 0000000000..dac3232d9f --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-buildrun-namespaced-heroku +spec: + buildRef: + name: buildpack-nodejs-build-namespaced-heroku + serviceAccount: + generate: true diff --git a/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3_cr.yaml new file mode 100644 index 0000000000..39b6439a17 --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-buildrun +spec: + buildRef: + name: buildpack-nodejs-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml new file mode 100644 index 0000000000..a2f48ee823 --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-buildrun-namespaced +spec: + buildRef: + name: buildpack-nodejs-build-namespaced + serviceAccount: + generate: true diff --git a/samples/v1alpha1/samples/buildrun/buildrun_kaniko-trivy-bad_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_kaniko-trivy-bad_cr.yaml new file mode 100644 index 0000000000..7e55cb8601 --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_kaniko-trivy-bad_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: kaniko-trivy-bad-buildrun +spec: + buildRef: + name: kaniko-trivy-bad-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/samples/buildrun/buildrun_kaniko-trivy-good_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_kaniko-trivy-good_cr.yaml new file mode 100644 index 0000000000..4d657f3c6b --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_kaniko-trivy-good_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: kaniko-trivy-good-buildrun +spec: + buildRef: + name: kaniko-trivy-good-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/samples/buildrun/buildrun_kaniko_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_kaniko_cr.yaml new file mode 100644 index 0000000000..227c3d0a0c --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_kaniko_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: kaniko-golang-buildrun +spec: + buildRef: + name: kaniko-golang-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/samples/buildrun/buildrun_ko_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_ko_cr.yaml new file mode 100644 index 0000000000..a7857afd33 --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_ko_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: ko-buildrun +spec: + buildRef: + name: ko-build + serviceAccount: + generate: true diff --git a/samples/v1alpha1/samples/buildrun/buildrun_source-to-image_cr.yaml b/samples/v1alpha1/samples/buildrun/buildrun_source-to-image_cr.yaml new file mode 100644 index 0000000000..196cf0a5f2 --- /dev/null +++ b/samples/v1alpha1/samples/buildrun/buildrun_source-to-image_cr.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: s2i-nodejs-buildrun +spec: + buildRef: + name: s2i-nodejs-build diff --git a/samples/v1alpha1/samples/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml b/samples/v1alpha1/samples/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml new file mode 100644 index 0000000000..c95c2f6da2 --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml @@ -0,0 +1,204 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildah-shipwright-managed-push +spec: + buildSteps: + - name: build + image: quay.io/containers/buildah:v1.32.0 + workingDir: $(params.shp-source-root) + securityContext: + privileged: true + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Parse parameters + context= + dockerfile= + image= + target= + buildArgs=() + inBuildArgs=false + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + while [[ $# -gt 0 ]]; do + arg="$1" + shift + + if [ "${arg}" == "--context" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + context="$1" + shift + elif [ "${arg}" == "--dockerfile" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + dockerfile="$1" + shift + elif [ "${arg}" == "--image" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--target" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + target="$1" + shift + elif [ "${arg}" == "--build-args" ]; then + inBuildArgs=true + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inBuildArgs=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inBuildArgs}" == "true" ]; then + buildArgs+=("--build-arg" "${arg}") + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + + # Verify the existence of the context directory + if [ ! -d "${context}" ]; then + echo -e "The context directory '${context}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${context}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + cd "${context}" + + # Verify the existence of the Dockerfile + if [ ! -f "${dockerfile}" ]; then + echo -e "The Dockerfile '${dockerfile}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${dockerfile}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + + EOF + fi + + # Building the image + echo "[INFO] Building image ${image}" + buildah --storage-driver=$(params.storage-driver) \ + bud "${buildArgs[@]}" \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" \ + --file="${dockerfile}" \ + . + + # Write the image + echo "[INFO] Writing image ${image}" + buildah --storage-driver=$(params.storage-driver) push \ + "${image}" \ + "oci:${target}" + # That's the separator between the shell script and its args + - -- + - --context + - $(params.shp-source-context) + - --dockerfile + - $(build.dockerfile) + - --image + - $(params.shp-output-image) + - --build-args + - $(params.build-args[*]) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + - --target + - $(params.shp-output-directory) + resources: + limits: + cpu: "1" + memory: 2Gi + requests: + cpu: 250m + memory: 65Mi + parameters: + - name: build-args + description: "The values for the args in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + - name: storage-driver + description: "The storage driver to use, such as 'overlay' or 'vfs'." + type: string + default: "vfs" + # For details see the "--storage-driver" section of https://github.com/containers/buildah/blob/main/docs/buildah.1.md#options + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/samples/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml b/samples/v1alpha1/samples/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml new file mode 100644 index 0000000000..03075863cf --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml @@ -0,0 +1,204 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildah-strategy-managed-push +spec: + buildSteps: + - name: build-and-push + image: quay.io/containers/buildah:v1.32.0 + workingDir: $(params.shp-source-root) + securityContext: + capabilities: + add: + - "SETFCAP" + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Parse parameters + context= + dockerfile= + image= + buildArgs=() + inBuildArgs=false + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + tlsVerify=true + while [[ $# -gt 0 ]]; do + arg="$1" + shift + + if [ "${arg}" == "--context" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + context="$1" + shift + elif [ "${arg}" == "--dockerfile" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + dockerfile="$1" + shift + elif [ "${arg}" == "--image" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--build-args" ]; then + inBuildArgs=true + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inBuildArgs=false + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inBuildArgs}" == "true" ]; then + buildArgs+=("--build-arg" "${arg}") + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + + # This assumes that the image is passed before the insecure registries which is fair in this context + if [[ ${image} == ${arg}/* ]]; then + tlsVerify=false + fi + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + + # Verify the existence of the context directory + if [ ! -d "${context}" ]; then + echo -e "The context directory '${context}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${context}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + cd "${context}" + + # Verify the existence of the Dockerfile + if [ ! -f "${dockerfile}" ]; then + echo -e "The Dockerfile '${dockerfile}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${dockerfile}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + + EOF + fi + + # Building the image + echo "[INFO] Building image ${image}" + buildah --storage-driver=$(params.storage-driver) \ + bud "${buildArgs[@]}" \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" \ + --file="${dockerfile}" \ + . + + # Push the image + echo "[INFO] Pushing image ${image}" + buildah --storage-driver=$(params.storage-driver) push \ + --digestfile='$(results.shp-image-digest.path)' \ + --tls-verify="${tlsVerify}" \ + "${image}" \ + "docker://${image}" + # That's the separator between the shell script and its args + - -- + - --context + - $(params.shp-source-context) + - --dockerfile + - $(build.dockerfile) + - --image + - $(params.shp-output-image) + - --build-args + - $(params.build-args[*]) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + resources: + limits: + cpu: "1" + memory: 2Gi + requests: + cpu: 250m + memory: 65Mi + parameters: + - name: build-args + description: "The values for the args in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + - name: storage-driver + description: "The storage driver to use, such as 'overlay' or 'vfs'" + type: string + default: "vfs" + # For details see the "--storage-driver" section of https://github.com/containers/buildah/blob/main/docs/buildah.1.md#options + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/samples/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml b/samples/v1alpha1/samples/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml new file mode 100644 index 0000000000..ff329d5483 --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml @@ -0,0 +1,170 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildkit + annotations: + # See https://github.com/moby/buildkit/blob/master/docs/rootless.md#about---oci-worker-no-process-sandbox for more information + container.apparmor.security.beta.kubernetes.io/step-build-and-push: unconfined + # The usage of seccomp annotation will be deprecate in k8s v1.22.0, see + # https://kubernetes.io/docs/tutorials/clusters/seccomp/#create-a-pod-with-a-seccomp-profile-for-syscall-auditing for more information + container.seccomp.security.alpha.kubernetes.io/step-build-and-push: unconfined +spec: + parameters: + - name: build-args + description: "The values for the ARGs in the Dockerfile. Values must be in the format KEY=VALUE." + type: array + defaults: [] + - name: cache + description: "Configure BuildKit's cache usage. Allowed values are 'disabled' and 'registry'. The default is 'registry'." + type: string + default: registry + - name: platforms + description: "Build the image for different platforms. By default, the image is built for the platform used by the FROM image. If that is present for multiple platforms, then it is built for the environment's platform." + type: array + defaults: [] + - name: secrets + description: "The secrets to pass to the build. Values must be in the format ID=FILE_CONTENT." + type: array + defaults: [] + buildSteps: + - name: build-and-push + image: moby/buildkit:nightly-rootless + imagePullPolicy: Always + securityContext: + allowPrivilegeEscalation: true + capabilities: + add: + - SETGID + - SETUID + workingDir: $(params.shp-source-root) + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + # See https://github.com/moby/buildkit/blob/master/docs/rootless.md#about---oci-worker-no-process-sandbox for more information + - name: BUILDKITD_FLAGS + value: --oci-worker-no-process-sandbox + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_DOCKERFILE + value: $(params.DOCKERFILE) + - name: PARAM_OUTPUT_DIRECTORY + value: $(params.shp-output-directory) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + - name: PARAM_OUTPUT_INSECURE + value: $(params.shp-output-insecure) + - name: PARAM_CACHE + value: $(params.cache) + command: + - /bin/ash + args: + - -c + - | + set -euo pipefail + + # Verify the existence of the context directory + if [ ! -d "${PARAM_SOURCE_CONTEXT}" ]; then + echo -e "The context directory '${PARAM_SOURCE_CONTEXT}' does not exist." + echo -n "ContextDirNotFound" > '$(results.shp-error-reason.path)' + echo -n "The context directory '${PARAM_SOURCE_CONTEXT}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + # Prepare the file arguments + DOCKERFILE_PATH="${PARAM_SOURCE_CONTEXT}/${PARAM_DOCKERFILE}" + DOCKERFILE_DIR="$(dirname "${DOCKERFILE_PATH}")" + DOCKERFILE_NAME="$(basename "${DOCKERFILE_PATH}")" + + # Verify the existence of the Dockerfile + if [ ! -f "${DOCKERFILE_PATH}" ]; then + echo -e "The Dockerfile '${DOCKERFILE_PATH}' does not exist." + echo -n "DockerfileNotFound" > '$(results.shp-error-reason.path)' + echo -n "The Dockerfile '${DOCKERFILE_PATH}' does not exist." > '$(results.shp-error-message.path)' + exit 1 + fi + + # We only have ash here and therefore no bash arrays to help add dynamic arguments (the build-args) to the build command. + + echo "#!/bin/ash" > /tmp/run.sh + echo "set -euo pipefail" >> /tmp/run.sh + echo "buildctl-daemonless.sh \\" >> /tmp/run.sh + echo "build \\" >> /tmp/run.sh + echo "--frontend=dockerfile.v0 \\" >> /tmp/run.sh + echo "--opt=filename=\"${DOCKERFILE_NAME}\" \\" >> /tmp/run.sh + echo "--local=context=\"${PARAM_SOURCE_CONTEXT}\" \\" >> /tmp/run.sh + echo "--local=dockerfile=\"${DOCKERFILE_DIR}\" \\" >> /tmp/run.sh + echo "--output=type=oci,tar=false,dest=\"${PARAM_OUTPUT_DIRECTORY}\" \\" >> /tmp/run.sh + if [ "${PARAM_CACHE}" == "registry" ]; then + echo "--export-cache=type=inline \\" >> /tmp/run.sh + echo "--import-cache=type=registry,ref=\"${PARAM_OUTPUT_IMAGE}\",registry.insecure=\"${PARAM_OUTPUT_INSECURE}\" \\" >> /tmp/run.sh + elif [ "${PARAM_CACHE}" == "disabled" ]; then + echo "--no-cache \\" >> /tmp/run.sh + else + echo -e "An invalid value for the parameter 'cache' has been provided: '${PARAM_CACHE}'. Allowed values are 'disabled' and 'registry'." + echo -n "InvalidParameterValue" > '$(results.shp-error-reason.path)' + echo -n "An invalid value for the parameter 'cache' has been provided: '${PARAM_CACHE}'. Allowed values are 'disabled' and 'registry'." > '$(results.shp-error-message.path)' + exit 1 + fi + + stage="" + platforms="" + for a in "$@" + do + if [ "${a}" == "--build-args" ]; then + stage=build-args + elif [ "${a}" == "--platforms" ]; then + stage=platforms + elif [ "${a}" == "--secrets" ]; then + stage=secrets + elif [ "${stage}" == "build-args" ]; then + echo "--opt=\"build-arg:${a}\" \\" >> /tmp/run.sh + elif [ "${stage}" == "platforms" ]; then + if [ "${platforms}" == "" ]; then + platforms="${a}" + else + platforms="${platforms},${a}" + fi + elif [ "${stage}" == "secrets" ]; then + # Split ID=FILE_CONTENT into variables id and data + + # using head because the data could be multiline + id="$(echo "${a}" | head -1 | sed 's/=.*//')" + + # This is hacky, we remove the suffix ${id}= from all lines of the data. + # If the data would be multiple lines and a line would start with ${id}= + # then we would remove it. We could force users to give us the secret + # base64 encoded. But ultimately, the best solution might be if the user + # mounts the secret and just gives us the path here. + data="$(echo "${a}" | sed "s/^${id}=//")" + + # Write the secret data into a temporary file, once we have volume support + # in the build strategy, we should use a memory based emptyDir for this. + echo -n "${data}" > "/tmp/secret_${id}" + + # Add the secret argument + echo "--secret id=${id},src="/tmp/secret_${id}" \\" >> /tmp/run.sh + fi + done + + if [ "${platforms}" != "" ]; then + echo "--opt=\"platform=${platforms}\" \\" >> /tmp/run.sh + fi + + echo "--progress=plain" >> /tmp/run.sh + + chmod +x /tmp/run.sh + /tmp/run.sh + # That's the separator between the shell script and its args + - -- + - --build-args + - $(params.build-args[*]) + - --platforms + - $(params.platforms[*]) + - --secrets + - $(params.secrets[*]) + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml b/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml new file mode 100644 index 0000000000..61eca36ee8 --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildpacks-v3-heroku +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: heroku/builder:22 + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml new file mode 100644 index 0000000000..aa01340555 --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: buildpacks-v3-heroku +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: heroku/builder:22 + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml b/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml new file mode 100644 index 0000000000..f4c11a65f1 --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: buildpacks-v3 +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: docker.io/paketobuildpacks/builder-jammy-full:latest + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1001 + runAsGroup: 1000 diff --git a/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml b/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml new file mode 100644 index 0000000000..32dcadc67c --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml @@ -0,0 +1,100 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildStrategy +metadata: + name: buildpacks-v3 +spec: + volumes: + - name: platform-env + emptyDir: {} + parameters: + - name: platform-api-version + description: The referenced version is the minimum version that all relevant buildpack implementations support. + default: "0.7" + buildSteps: + - name: build-and-push + image: docker.io/paketobuildpacks/builder-jammy-full:latest + env: + - name: CNB_PLATFORM_API + value: $(params.platform-api-version) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + echo "> Processing environment variables..." + ENV_DIR="/platform/env" + + envs=($(env)) + + # Denying the creation of non required files from system environments. + # The creation of a file named PATH (corresponding to PATH system environment) + # caused failure for python source during pip install (https://github.com/Azure-Samples/python-docs-hello-world) + block_list=("PATH" "HOSTNAME" "PWD" "_" "SHLVL" "HOME" "") + + for env in "${envs[@]}"; do + blocked=false + + IFS='=' read -r key value string <<< "$env" + + for str in "${block_list[@]}"; do + if [[ "$key" == "$str" ]]; then + blocked=true + break + fi + done + + if [ "$blocked" == "false" ]; then + path="${ENV_DIR}/${key}" + echo -n "$value" > "$path" + fi + done + + LAYERS_DIR=/tmp/.shp/layers + CACHE_DIR=/tmp/.shp/cache + + mkdir -p "$CACHE_DIR" "$LAYERS_DIR" + + function announce_phase { + printf "===> %s\n" "$1" + } + + announce_phase "ANALYZING" + /cnb/lifecycle/analyzer -layers="$LAYERS_DIR" "${PARAM_OUTPUT_IMAGE}" + + announce_phase "DETECTING" + /cnb/lifecycle/detector -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + announce_phase "RESTORING" + /cnb/lifecycle/restorer -cache-dir="$CACHE_DIR" -layers="$LAYERS_DIR" + + announce_phase "BUILDING" + /cnb/lifecycle/builder -app="${PARAM_SOURCE_CONTEXT}" -layers="$LAYERS_DIR" + + exporter_args=( -layers="$LAYERS_DIR" -report=/tmp/report.toml -cache-dir="$CACHE_DIR" -app="${PARAM_SOURCE_CONTEXT}") + grep -q "buildpack-default-process-type" "$LAYERS_DIR/config/metadata.toml" || exporter_args+=( -process-type web ) + + announce_phase "EXPORTING" + /cnb/lifecycle/exporter "${exporter_args[@]}" "${PARAM_OUTPUT_IMAGE}" + + # Store the image digest + grep digest /tmp/report.toml | tail -n 1 | tr -d ' \"\n' | sed s/digest=// > "$(results.shp-image-digest.path)" + volumeMounts: + - mountPath: /platform/env + name: platform-env + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1001 + runAsGroup: 1000 diff --git a/samples/v1alpha1/samples/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml b/samples/v1alpha1/samples/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml new file mode 100644 index 0000000000..eefbf8b258 --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml @@ -0,0 +1,82 @@ +# This Build Strategy will intentionally fail if the image has any +# critical CVEs. It will not be pushed into the destination registry +# if any critical vulnerabilities are found. +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: kaniko-trivy +spec: + volumes: + - name: layout + emptyDir: {} + - name: tar + emptyDir: {} + buildSteps: + - name: kaniko-build + image: gcr.io/kaniko-project/executor:v1.16.0 + workingDir: $(params.shp-source-root) + securityContext: + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + env: + - name: HOME + value: /tekton/home + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --dockerfile + - $(build.dockerfile) + - --context + - $(params.shp-source-context) + - --destination + - $(params.shp-output-image) + - --snapshot-mode + - redo + - --no-push + - --tar-path + - $(params.shp-output-directory)/image.tar + # https://github.com/GoogleContainerTools/kaniko/issues/2164 + - --ignore-path + - /product_uuid + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + - name: trivy-scan + image: docker.io/aquasec/trivy:0.46.0 + command: + - trivy + args: + - image + - --exit-code=1 + - --severity=CRITICAL + - --input + - $(params.shp-output-directory)/image.tar + env: + - name: HOME + value: /tekton/home + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/samples/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml b/samples/v1alpha1/samples/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml new file mode 100644 index 0000000000..728375b0b8 --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml @@ -0,0 +1,56 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: kaniko +spec: + buildSteps: + - name: build-and-push + image: gcr.io/kaniko-project/executor:v1.16.0 + workingDir: $(params.shp-source-root) + securityContext: + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + env: + - name: HOME + value: /tekton/home + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --dockerfile + - $(build.dockerfile) + - --context + - $(params.shp-source-context) + - --destination + - $(params.shp-output-image) + - --snapshot-mode + - redo + - --no-push + - --tar-path + - $(params.shp-output-directory)/image.tar + # https://github.com/GoogleContainerTools/kaniko/issues/2164 + - --ignore-path + - /product_uuid + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/samples/buildstrategy/ko/buildstrategy_ko_cr.yaml b/samples/v1alpha1/samples/buildstrategy/ko/buildstrategy_ko_cr.yaml new file mode 100644 index 0000000000..e98b0aede1 --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/ko/buildstrategy_ko_cr.yaml @@ -0,0 +1,116 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: ko +spec: + parameters: + - name: go-flags + description: "Value for the GOFLAGS environment variable." + default: "" + - name: go-version + description: "Version of Go, must match a tag from https://hub.docker.com/_/golang?tab=tags" + default: "1.20" + - name: ko-version + description: "Version of ko, must be either 'latest', or a release name from https://github.com/ko-build/ko/releases" + default: latest + - name: package-directory + description: "The directory inside the context directory containing the main package." + default: "." + - name: target-platform + description: "Target platform to be built. For example: 'linux/arm64'. Multiple platforms can be provided separated by comma, for example: 'linux/arm64,linux/amd64'. The value 'all' will build all platforms supported by the base image. The value 'current' will build the platform on which the build runs." + default: current + volumes: + - name: gocache + description: "Volume to contain the GOCACHE. Can be set to a persistent volume to optimize compilation performance for rebuilds." + overridable: true + emptyDir: {} + buildSteps: + - name: build + image: golang:$(params.go-version) + imagePullPolicy: Always + workingDir: $(params.shp-source-root) + volumeMounts: + - mountPath: /gocache + name: gocache + readOnly: false + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + - name: GOFLAGS + value: $(params.go-flags) + - name: GOCACHE + value: /gocache + - name: PARAM_OUTPUT_IMAGE + value: $(params.shp-output-image) + - name: PARAM_OUTPUT_DIRECTORY + value: $(params.shp-output-directory) + - name: PARAM_SOURCE_CONTEXT + value: $(params.shp-source-context) + - name: PARAM_SOURCE_ROOT + value: $(params.shp-source-root) + - name: PARAM_TARGET_PLATFORM + value: $(params.target-platform) + - name: PARAM_PACKAGE_DIRECTORY + value: $(params.package-directory) + - name: PARAM_KO_VERSION + value: $(params.ko-version) + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Determine the ko version + KO_VERSION="${PARAM_KO_VERSION}" + if [ "${KO_VERSION}" == "latest" ]; then + KO_VERSION=$(curl --silent "https://api.github.com/repos/ko-build/ko/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/') + fi + + # Create one variable with v-suffix and one without as we need both for the download URL + if [[ ${KO_VERSION} = v* ]]; then + KO_VERSION_WITH_V=${KO_VERSION} + KO_VERSION_WITHOUT_V=${KO_VERSION:1} + else + KO_VERSION_WITH_V=v${KO_VERSION} + KO_VERSION_WITHOUT_V=${KO_VERSION} + fi + + # Download ko to the temp directory + curl -f -s -L "https://github.com/ko-build/ko/releases/download/${KO_VERSION_WITH_V}/ko_${KO_VERSION_WITHOUT_V}_$(uname)_$(uname -m | sed 's/aarch64/arm64/').tar.gz" | tar xzf - -C /tmp ko + + # Determine the platform + PLATFORM="${PARAM_TARGET_PLATFORM}" + if [ "${PLATFORM}" == "current" ]; then + PLATFORM="$(uname | tr '[:upper:]' '[:lower:]')/$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/')" + fi + + # Print version information + go version + echo "ko version $(/tmp/ko version)" + + # Allow directory to be owned by other user which is normal for a volume-mounted directory. + # This allows Go to run git commands to access repository metadata. + # Documentation: https://git-scm.com/docs/git-config/2.39.0#Documentation/git-config.txt-safedirectory + git config --global --add safe.directory "${PARAM_SOURCE_ROOT}" + + # Run ko + + export GOROOT="$(go env GOROOT)" + + pushd "${PARAM_SOURCE_CONTEXT}" > /dev/null + /tmp/ko build "${PARAM_PACKAGE_DIRECTORY}" --oci-layout-path="${PARAM_OUTPUT_DIRECTORY}" --platform="${PLATFORM}" --push=false + popd > /dev/null + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + securityContext: + runAsUser: 1000 + runAsGroup: 1000 diff --git a/samples/v1alpha1/samples/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml b/samples/v1alpha1/samples/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml new file mode 100644 index 0000000000..09ac150375 --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml @@ -0,0 +1,151 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: source-to-image-redhat +spec: + volumes: + - name: s2i + emptyDir: {} + buildSteps: + - name: s2i-generate + image: registry.redhat.io/ocp-tools-43-tech-preview/source-to-image-rhel8:latest + workingDir: $(params.shp-source-root) + args: + - build + - $(params.shp-source-context) + - $(build.builder.image) + - $(params.shp-output-image) + - --as-dockerfile=/s2i/Dockerfile + volumeMounts: + - name: s2i + mountPath: /s2i + - name: buildah + image: quay.io/containers/buildah:v1.32.0 + workingDir: /s2i + securityContext: + privileged: true + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + # Parse parameters + image= + target= + registriesBlock="" + inRegistriesBlock=false + registriesInsecure="" + inRegistriesInsecure=false + registriesSearch="" + inRegistriesSearch=false + while [[ $# -gt 0 ]]; do + arg="$1" + shift + + if [ "${arg}" == "--image" ]; then + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + image="$1" + shift + elif [ "${arg}" == "--target" ]; then + inBuildArgs=false + inRegistriesBlock=false + inRegistriesInsecure=false + inRegistriesSearch=false + target="$1" + shift + elif [ "${arg}" == "--registries-block" ]; then + inRegistriesBlock=true + inRegistriesInsecure=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-insecure" ]; then + inRegistriesInsecure=true + inRegistriesBlock=false + inRegistriesSearch=false + elif [ "${arg}" == "--registries-search" ]; then + inRegistriesSearch=true + inRegistriesBlock=false + inRegistriesInsecure=false + elif [ "${inRegistriesBlock}" == "true" ]; then + registriesBlock="${registriesBlock}'${arg}', " + elif [ "${inRegistriesInsecure}" == "true" ]; then + registriesInsecure="${registriesInsecure}'${arg}', " + elif [ "${inRegistriesSearch}" == "true" ]; then + registriesSearch="${registriesSearch}'${arg}', " + else + echo "Invalid usage" + exit 1 + fi + done + + echo "[INFO] Creating registries config file..." + if [ "${registriesSearch}" != "" ]; then + cat <>/tmp/registries.conf + [registries.search] + registries = [${registriesSearch::-2}] + + EOF + fi + if [ "${registriesInsecure}" != "" ]; then + cat <>/tmp/registries.conf + [registries.insecure] + registries = [${registriesInsecure::-2}] + + EOF + fi + if [ "${registriesBlock}" != "" ]; then + cat <>/tmp/registries.conf + [registries.block] + registries = [${registriesBlock::-2}] + + EOF + fi + + # Building the image + echo "[INFO] Building image ${image}" + buildah bud \ + --registries-conf=/tmp/registries.conf \ + --tag="${image}" + + # Write the image + echo "[INFO] Writing image ${image}" + buildah push \ + "${image}" \ + "oci:${target}" + # That's the separator between the shell script and its args + - -- + - --image + - $(params.shp-output-image) + - --registries-block + - $(params.registries-block[*]) + - --registries-insecure + - $(params.registries-insecure[*]) + - --registries-search + - $(params.registries-search[*]) + - --target + - $(params.shp-output-directory) + volumeMounts: + - name: s2i + mountPath: /s2i + parameters: + - name: registries-block + description: The registries that need to block pull access. + type: array + defaults: [] + - name: registries-insecure + description: The fully-qualified name of insecure registries. An insecure registry is one that does not have a valid SSL certificate or only supports HTTP. + type: array + defaults: [] + - name: registries-search + description: The registries for searching short name images such as `golang:latest`. + type: array + defaults: + - docker.io + - quay.io + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/v1alpha1/samples/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml b/samples/v1alpha1/samples/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml new file mode 100644 index 0000000000..ddadb030b0 --- /dev/null +++ b/samples/v1alpha1/samples/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml @@ -0,0 +1,69 @@ +apiVersion: shipwright.io/v1alpha1 +kind: ClusterBuildStrategy +metadata: + name: source-to-image +spec: + volumes: + - name: gen-source + emptyDir: {} + buildSteps: + - command: + - /usr/local/bin/s2i + - build + - $(params.shp-source-context) + - $(build.builder.image) + - '--as-dockerfile' + - /gen-source/Dockerfile.gen + image: quay.io/openshift-pipeline/s2i:nightly + imagePullPolicy: Always + name: s2i-build-as-dockerfile + volumeMounts: + - mountPath: /gen-source + name: gen-source + workingDir: $(params.shp-source-root) + - name: build-and-push + image: gcr.io/kaniko-project/executor:v1.16.0 + command: + - /kaniko/executor + args: + - --dockerfile + - /gen-source/Dockerfile.gen + - --context + - /gen-source + - --destination + - $(params.shp-output-image) + - --snapshot-mode + - redo + - --no-push + - --tar-path + - $(params.shp-output-directory)/image.tar + # https://github.com/GoogleContainerTools/kaniko/issues/2164 + - --ignore-path + - /product_uuid + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: HOME + value: /tekton/home + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + securityContext: + allowPrivilegeEscalation: false + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + volumeMounts: + - mountPath: /gen-source + name: gen-source + workingDir: /gen-source + securityContext: + runAsUser: 0 + runAsGroup: 0 diff --git a/samples/build/build_buildah_shipwright_managed_push_cr.yaml b/samples/v1beta1/build/build_buildah_shipwright_managed_push_cr.yaml similarity index 100% rename from samples/build/build_buildah_shipwright_managed_push_cr.yaml rename to samples/v1beta1/build/build_buildah_shipwright_managed_push_cr.yaml diff --git a/samples/build/build_buildah_strategy_managed_push_cr.yaml b/samples/v1beta1/build/build_buildah_strategy_managed_push_cr.yaml similarity index 100% rename from samples/build/build_buildah_strategy_managed_push_cr.yaml rename to samples/v1beta1/build/build_buildah_strategy_managed_push_cr.yaml diff --git a/samples/build/build_buildkit_cr.yaml b/samples/v1beta1/build/build_buildkit_cr.yaml similarity index 100% rename from samples/build/build_buildkit_cr.yaml rename to samples/v1beta1/build/build_buildkit_cr.yaml diff --git a/samples/build/build_buildpacks-v3-heroku_cr.yaml b/samples/v1beta1/build/build_buildpacks-v3-heroku_cr.yaml similarity index 100% rename from samples/build/build_buildpacks-v3-heroku_cr.yaml rename to samples/v1beta1/build/build_buildpacks-v3-heroku_cr.yaml diff --git a/samples/build/build_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1beta1/build/build_buildpacks-v3-heroku_namespaced_cr.yaml similarity index 100% rename from samples/build/build_buildpacks-v3-heroku_namespaced_cr.yaml rename to samples/v1beta1/build/build_buildpacks-v3-heroku_namespaced_cr.yaml diff --git a/samples/build/build_buildpacks-v3_cr.yaml b/samples/v1beta1/build/build_buildpacks-v3_cr.yaml similarity index 100% rename from samples/build/build_buildpacks-v3_cr.yaml rename to samples/v1beta1/build/build_buildpacks-v3_cr.yaml diff --git a/samples/build/build_buildpacks-v3_namespaced_cr.yaml b/samples/v1beta1/build/build_buildpacks-v3_namespaced_cr.yaml similarity index 100% rename from samples/build/build_buildpacks-v3_namespaced_cr.yaml rename to samples/v1beta1/build/build_buildpacks-v3_namespaced_cr.yaml diff --git a/samples/build/build_kaniko-trivy-bad_cr.yaml b/samples/v1beta1/build/build_kaniko-trivy-bad_cr.yaml similarity index 100% rename from samples/build/build_kaniko-trivy-bad_cr.yaml rename to samples/v1beta1/build/build_kaniko-trivy-bad_cr.yaml diff --git a/samples/build/build_kaniko-trivy-good_cr.yaml b/samples/v1beta1/build/build_kaniko-trivy-good_cr.yaml similarity index 100% rename from samples/build/build_kaniko-trivy-good_cr.yaml rename to samples/v1beta1/build/build_kaniko-trivy-good_cr.yaml diff --git a/samples/build/build_kaniko_cr.yaml b/samples/v1beta1/build/build_kaniko_cr.yaml similarity index 100% rename from samples/build/build_kaniko_cr.yaml rename to samples/v1beta1/build/build_kaniko_cr.yaml diff --git a/samples/build/build_ko_cr.yaml b/samples/v1beta1/build/build_ko_cr.yaml similarity index 100% rename from samples/build/build_ko_cr.yaml rename to samples/v1beta1/build/build_ko_cr.yaml diff --git a/samples/build/build_source-to-image_cr.yaml b/samples/v1beta1/build/build_source-to-image_cr.yaml similarity index 100% rename from samples/build/build_source-to-image_cr.yaml rename to samples/v1beta1/build/build_source-to-image_cr.yaml diff --git a/samples/buildrun/buildrun_buildah_cr.yaml b/samples/v1beta1/buildrun/buildrun_buildah_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_buildah_cr.yaml rename to samples/v1beta1/buildrun/buildrun_buildah_cr.yaml diff --git a/samples/buildrun/buildrun_buildkit_cr.yaml b/samples/v1beta1/buildrun/buildrun_buildkit_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_buildkit_cr.yaml rename to samples/v1beta1/buildrun/buildrun_buildkit_cr.yaml diff --git a/samples/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml b/samples/v1beta1/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml rename to samples/v1beta1/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml diff --git a/samples/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1beta1/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml rename to samples/v1beta1/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml diff --git a/samples/buildrun/buildrun_buildpacks-v3_cr.yaml b/samples/v1beta1/buildrun/buildrun_buildpacks-v3_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_buildpacks-v3_cr.yaml rename to samples/v1beta1/buildrun/buildrun_buildpacks-v3_cr.yaml diff --git a/samples/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml b/samples/v1beta1/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml rename to samples/v1beta1/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml diff --git a/samples/buildrun/buildrun_kaniko-trivy-bad_cr.yaml b/samples/v1beta1/buildrun/buildrun_kaniko-trivy-bad_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_kaniko-trivy-bad_cr.yaml rename to samples/v1beta1/buildrun/buildrun_kaniko-trivy-bad_cr.yaml diff --git a/samples/buildrun/buildrun_kaniko-trivy-good_cr.yaml b/samples/v1beta1/buildrun/buildrun_kaniko-trivy-good_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_kaniko-trivy-good_cr.yaml rename to samples/v1beta1/buildrun/buildrun_kaniko-trivy-good_cr.yaml diff --git a/samples/buildrun/buildrun_kaniko_cr.yaml b/samples/v1beta1/buildrun/buildrun_kaniko_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_kaniko_cr.yaml rename to samples/v1beta1/buildrun/buildrun_kaniko_cr.yaml diff --git a/samples/buildrun/buildrun_ko_cr.yaml b/samples/v1beta1/buildrun/buildrun_ko_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_ko_cr.yaml rename to samples/v1beta1/buildrun/buildrun_ko_cr.yaml diff --git a/samples/buildrun/buildrun_source-to-image_cr.yaml b/samples/v1beta1/buildrun/buildrun_source-to-image_cr.yaml similarity index 100% rename from samples/buildrun/buildrun_source-to-image_cr.yaml rename to samples/v1beta1/buildrun/buildrun_source-to-image_cr.yaml diff --git a/samples/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml b/samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml similarity index 100% rename from samples/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml rename to samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_shipwright_managed_push_cr.yaml diff --git a/samples/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml b/samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml similarity index 100% rename from samples/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml rename to samples/v1beta1/buildstrategy/buildah/buildstrategy_buildah_strategy_managed_push_cr.yaml diff --git a/samples/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml b/samples/v1beta1/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml similarity index 100% rename from samples/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml rename to samples/v1beta1/buildstrategy/buildkit/buildstrategy_buildkit_cr.yaml diff --git a/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml similarity index 100% rename from samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml rename to samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_cr.yaml diff --git a/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml similarity index 100% rename from samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml rename to samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml diff --git a/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml similarity index 100% rename from samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml rename to samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_cr.yaml diff --git a/samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml b/samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml similarity index 100% rename from samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml rename to samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml diff --git a/samples/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml b/samples/v1beta1/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml similarity index 100% rename from samples/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml rename to samples/v1beta1/buildstrategy/kaniko/buildstrategy_kaniko-trivy_cr.yaml diff --git a/samples/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml b/samples/v1beta1/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml similarity index 100% rename from samples/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml rename to samples/v1beta1/buildstrategy/kaniko/buildstrategy_kaniko_cr.yaml diff --git a/samples/buildstrategy/ko/buildstrategy_ko_cr.yaml b/samples/v1beta1/buildstrategy/ko/buildstrategy_ko_cr.yaml similarity index 100% rename from samples/buildstrategy/ko/buildstrategy_ko_cr.yaml rename to samples/v1beta1/buildstrategy/ko/buildstrategy_ko_cr.yaml diff --git a/samples/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml b/samples/v1beta1/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml similarity index 100% rename from samples/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml rename to samples/v1beta1/buildstrategy/source-to-image/buildstrategy_source-to-image-redhat_cr.yaml diff --git a/samples/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml b/samples/v1beta1/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml similarity index 100% rename from samples/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml rename to samples/v1beta1/buildstrategy/source-to-image/buildstrategy_source-to-image_cr.yaml diff --git a/test/data/build_buildah_cr_custom_context+dockerfile.yaml b/test/data/v1alpha1/build_buildah_cr_custom_context+dockerfile.yaml similarity index 100% rename from test/data/build_buildah_cr_custom_context+dockerfile.yaml rename to test/data/v1alpha1/build_buildah_cr_custom_context+dockerfile.yaml diff --git a/test/data/build_buildah_cr_local_source_upload.yaml b/test/data/v1alpha1/build_buildah_cr_local_source_upload.yaml similarity index 100% rename from test/data/build_buildah_cr_local_source_upload.yaml rename to test/data/v1alpha1/build_buildah_cr_local_source_upload.yaml diff --git a/test/data/build_buildah_cr_mutate.yaml b/test/data/v1alpha1/build_buildah_cr_mutate.yaml similarity index 100% rename from test/data/build_buildah_cr_mutate.yaml rename to test/data/v1alpha1/build_buildah_cr_mutate.yaml diff --git a/test/data/build_buildah_cr_private_github.yaml b/test/data/v1alpha1/build_buildah_cr_private_github.yaml similarity index 100% rename from test/data/build_buildah_cr_private_github.yaml rename to test/data/v1alpha1/build_buildah_cr_private_github.yaml diff --git a/test/data/build_buildah_cr_private_gitlab.yaml b/test/data/v1alpha1/build_buildah_cr_private_gitlab.yaml similarity index 100% rename from test/data/build_buildah_cr_private_gitlab.yaml rename to test/data/v1alpha1/build_buildah_cr_private_gitlab.yaml diff --git a/test/data/build_buildkit_cr_insecure_registry.yaml b/test/data/v1alpha1/build_buildkit_cr_insecure_registry.yaml similarity index 100% rename from test/data/build_buildkit_cr_insecure_registry.yaml rename to test/data/v1alpha1/build_buildkit_cr_insecure_registry.yaml diff --git a/test/data/build_buildpacks-v3_golang_cr.yaml b/test/data/v1alpha1/build_buildpacks-v3_golang_cr.yaml similarity index 100% rename from test/data/build_buildpacks-v3_golang_cr.yaml rename to test/data/v1alpha1/build_buildpacks-v3_golang_cr.yaml diff --git a/test/data/build_buildpacks-v3_golang_cr_env.yaml b/test/data/v1alpha1/build_buildpacks-v3_golang_cr_env.yaml similarity index 100% rename from test/data/build_buildpacks-v3_golang_cr_env.yaml rename to test/data/v1alpha1/build_buildpacks-v3_golang_cr_env.yaml diff --git a/test/data/build_buildpacks-v3_golang_delete_cr.yaml b/test/data/v1alpha1/build_buildpacks-v3_golang_delete_cr.yaml similarity index 100% rename from test/data/build_buildpacks-v3_golang_delete_cr.yaml rename to test/data/v1alpha1/build_buildpacks-v3_golang_delete_cr.yaml diff --git a/test/data/build_buildpacks-v3_java_cr.yaml b/test/data/v1alpha1/build_buildpacks-v3_java_cr.yaml similarity index 100% rename from test/data/build_buildpacks-v3_java_cr.yaml rename to test/data/v1alpha1/build_buildpacks-v3_java_cr.yaml diff --git a/test/data/build_buildpacks-v3_php_cr.yaml b/test/data/v1alpha1/build_buildpacks-v3_php_cr.yaml similarity index 100% rename from test/data/build_buildpacks-v3_php_cr.yaml rename to test/data/v1alpha1/build_buildpacks-v3_php_cr.yaml diff --git a/test/data/build_buildpacks-v3_ruby_cr.yaml b/test/data/v1alpha1/build_buildpacks-v3_ruby_cr.yaml similarity index 100% rename from test/data/build_buildpacks-v3_ruby_cr.yaml rename to test/data/v1alpha1/build_buildpacks-v3_ruby_cr.yaml diff --git a/test/data/build_kaniko_cr_advanced_dockerfile.yaml b/test/data/v1alpha1/build_kaniko_cr_advanced_dockerfile.yaml similarity index 100% rename from test/data/build_kaniko_cr_advanced_dockerfile.yaml rename to test/data/v1alpha1/build_kaniko_cr_advanced_dockerfile.yaml diff --git a/test/data/build_kaniko_cr_custom_context+dockerfile.yaml b/test/data/v1alpha1/build_kaniko_cr_custom_context+dockerfile.yaml similarity index 100% rename from test/data/build_kaniko_cr_custom_context+dockerfile.yaml rename to test/data/v1alpha1/build_kaniko_cr_custom_context+dockerfile.yaml diff --git a/test/data/build_kaniko_cr_private_github.yaml b/test/data/v1alpha1/build_kaniko_cr_private_github.yaml similarity index 100% rename from test/data/build_kaniko_cr_private_github.yaml rename to test/data/v1alpha1/build_kaniko_cr_private_github.yaml diff --git a/test/data/build_kaniko_cr_private_gitlab.yaml b/test/data/v1alpha1/build_kaniko_cr_private_gitlab.yaml similarity index 100% rename from test/data/build_kaniko_cr_private_gitlab.yaml rename to test/data/v1alpha1/build_kaniko_cr_private_gitlab.yaml diff --git a/test/data/build_non_existing_repo.yaml b/test/data/v1alpha1/build_non_existing_repo.yaml similarity index 100% rename from test/data/build_non_existing_repo.yaml rename to test/data/v1alpha1/build_non_existing_repo.yaml diff --git a/test/data/build_source-to-image_cr_private_github.yaml b/test/data/v1alpha1/build_source-to-image_cr_private_github.yaml similarity index 100% rename from test/data/build_source-to-image_cr_private_github.yaml rename to test/data/v1alpha1/build_source-to-image_cr_private_github.yaml diff --git a/test/data/buildrun_buildah_cr_custom_context+dockerfile.yaml b/test/data/v1alpha1/buildrun_buildah_cr_custom_context+dockerfile.yaml similarity index 100% rename from test/data/buildrun_buildah_cr_custom_context+dockerfile.yaml rename to test/data/v1alpha1/buildrun_buildah_cr_custom_context+dockerfile.yaml diff --git a/test/data/buildrun_buildah_cr_local_source_upload.yaml b/test/data/v1alpha1/buildrun_buildah_cr_local_source_upload.yaml similarity index 100% rename from test/data/buildrun_buildah_cr_local_source_upload.yaml rename to test/data/v1alpha1/buildrun_buildah_cr_local_source_upload.yaml diff --git a/test/data/buildrun_buildah_cr_mutate.yaml b/test/data/v1alpha1/buildrun_buildah_cr_mutate.yaml similarity index 100% rename from test/data/buildrun_buildah_cr_mutate.yaml rename to test/data/v1alpha1/buildrun_buildah_cr_mutate.yaml diff --git a/test/data/buildrun_buildpacks-v3_golang_cr.yaml b/test/data/v1alpha1/buildrun_buildpacks-v3_golang_cr.yaml similarity index 100% rename from test/data/buildrun_buildpacks-v3_golang_cr.yaml rename to test/data/v1alpha1/buildrun_buildpacks-v3_golang_cr.yaml diff --git a/test/data/buildrun_buildpacks-v3_java_cr.yaml b/test/data/v1alpha1/buildrun_buildpacks-v3_java_cr.yaml similarity index 100% rename from test/data/buildrun_buildpacks-v3_java_cr.yaml rename to test/data/v1alpha1/buildrun_buildpacks-v3_java_cr.yaml diff --git a/test/data/v1alpha1/buildrun_buildpacks-v3_nodejs_runtime-image_cr.yaml b/test/data/v1alpha1/buildrun_buildpacks-v3_nodejs_runtime-image_cr.yaml new file mode 100644 index 0000000000..b648f0f3d9 --- /dev/null +++ b/test/data/v1alpha1/buildrun_buildpacks-v3_nodejs_runtime-image_cr.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1alpha1 +kind: BuildRun +metadata: + name: buildpack-nodejs-buildrun-heroku +spec: + buildRef: + name: buildpack-nodejs-build-heroku + serviceAccount: + generate: true diff --git a/test/data/buildrun_buildpacks-v3_php_cr.yaml b/test/data/v1alpha1/buildrun_buildpacks-v3_php_cr.yaml similarity index 100% rename from test/data/buildrun_buildpacks-v3_php_cr.yaml rename to test/data/v1alpha1/buildrun_buildpacks-v3_php_cr.yaml diff --git a/test/data/buildrun_buildpacks-v3_ruby_cr.yaml b/test/data/v1alpha1/buildrun_buildpacks-v3_ruby_cr.yaml similarity index 100% rename from test/data/buildrun_buildpacks-v3_ruby_cr.yaml rename to test/data/v1alpha1/buildrun_buildpacks-v3_ruby_cr.yaml diff --git a/test/data/buildrun_kaniko_cr_advanced_dockerfile.yaml b/test/data/v1alpha1/buildrun_kaniko_cr_advanced_dockerfile.yaml similarity index 100% rename from test/data/buildrun_kaniko_cr_advanced_dockerfile.yaml rename to test/data/v1alpha1/buildrun_kaniko_cr_advanced_dockerfile.yaml diff --git a/test/data/buildrun_kaniko_cr_custom_context+dockerfile.yaml b/test/data/v1alpha1/buildrun_kaniko_cr_custom_context+dockerfile.yaml similarity index 100% rename from test/data/buildrun_kaniko_cr_custom_context+dockerfile.yaml rename to test/data/v1alpha1/buildrun_kaniko_cr_custom_context+dockerfile.yaml diff --git a/test/data/buildrun_non_existing_repo.yaml b/test/data/v1alpha1/buildrun_non_existing_repo.yaml similarity index 100% rename from test/data/buildrun_non_existing_repo.yaml rename to test/data/v1alpha1/buildrun_non_existing_repo.yaml diff --git a/test/data/v1beta1/build_buildah_cr_custom_context+dockerfile.yaml b/test/data/v1beta1/build_buildah_cr_custom_context+dockerfile.yaml new file mode 100644 index 0000000000..84dce74654 --- /dev/null +++ b/test/data/v1beta1/build_buildah_cr_custom_context+dockerfile.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah-custom-context-dockerfile +spec: + source: + git: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: docker-build-renamed + strategy: + name: buildah-shipwright-managed-push + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: RenamedDockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/renamed-dockerfile diff --git a/test/data/v1beta1/build_buildah_cr_local_source_upload.yaml b/test/data/v1beta1/build_buildah_cr_local_source_upload.yaml new file mode 100644 index 0000000000..4a0e5f160a --- /dev/null +++ b/test/data/v1beta1/build_buildah_cr_local_source_upload.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah-golang-build-local-source-upload +spec: + source: + git: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + strategy: + name: buildah-shipwright-managed-push + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_buildah_cr_mutate.yaml b/test/data/v1beta1/build_buildah_cr_mutate.yaml new file mode 100644 index 0000000000..ae7cb9b5c2 --- /dev/null +++ b/test/data/v1beta1/build_buildah_cr_mutate.yaml @@ -0,0 +1,22 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah-golang-build-mutate +spec: + source: + git: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + strategy: + name: buildah-shipwright-managed-push + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app + annotations: + "org.opencontainers.image.url": "https://my-company.com/images" + labels: + "maintainer": "team@my-company.com" diff --git a/test/data/v1beta1/build_buildah_cr_private_github.yaml b/test/data/v1beta1/build_buildah_cr_private_github.yaml new file mode 100644 index 0000000000..81ef768b7c --- /dev/null +++ b/test/data/v1beta1/build_buildah_cr_private_github.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah-golang-build +spec: + source: + git: + url: git@github.com:qu1queee/newtaxi.git + cloneSecret: github-ssh-all + strategy: + name: buildah-shipwright-managed-push + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_buildah_cr_private_gitlab.yaml b/test/data/v1beta1/build_buildah_cr_private_gitlab.yaml new file mode 100644 index 0000000000..13b19a0693 --- /dev/null +++ b/test/data/v1beta1/build_buildah_cr_private_gitlab.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah-golang-build +spec: + source: + git: + url: git@gitlab.com:eduardooli/newtaxi.git + strategy: + name: buildah-shipwright-managed-push + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_buildkit_cr_insecure_registry.yaml b/test/data/v1beta1/build_buildkit_cr_insecure_registry.yaml new file mode 100644 index 0000000000..a870298db1 --- /dev/null +++ b/test/data/v1beta1/build_buildkit_cr_insecure_registry.yaml @@ -0,0 +1,24 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildkit-build +spec: + source: + git: + url: https://github.com/shipwright-io/sample-go + contextDir: docker-build + paramValues: + - name: insecure-registry + value: "true" + - name: platforms + values: + - value: linux/amd64 + - value: linux/arm64 + strategy: + name: buildkit + kind: ClusterBuildStrategy + retention: + atBuildDeletion: true + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app \ No newline at end of file diff --git a/test/data/v1beta1/build_buildpacks-v3_golang_cr.yaml b/test/data/v1beta1/build_buildpacks-v3_golang_cr.yaml new file mode 100644 index 0000000000..f097c9aba4 --- /dev/null +++ b/test/data/v1beta1/build_buildpacks-v3_golang_cr.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildpack-golang-build +spec: + source: + git: + url: https://github.com/shipwright-io/sample-go + contextDir: source-build + strategy: + name: buildpacks-v3 + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_buildpacks-v3_golang_cr_env.yaml b/test/data/v1beta1/build_buildpacks-v3_golang_cr_env.yaml new file mode 100644 index 0000000000..9806e5114a --- /dev/null +++ b/test/data/v1beta1/build_buildpacks-v3_golang_cr_env.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildpack-golang-build +spec: + source: + git: + url: https://github.com/shipwright-io/sample-go + contextDir: source-build-with-package + env: + - name: BP_GO_TARGETS + value: "main-package" + strategy: + name: buildpacks-v3 + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_buildpacks-v3_golang_delete_cr.yaml b/test/data/v1beta1/build_buildpacks-v3_golang_delete_cr.yaml new file mode 100644 index 0000000000..4826426153 --- /dev/null +++ b/test/data/v1beta1/build_buildpacks-v3_golang_delete_cr.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildpack-golang-build +spec: + source: + git: + url: https://github.com/shipwright-io/sample-go + contextDir: source-build + strategy: + name: buildpacks-v3 + kind: ClusterBuildStrategy + retention: + atBuildDeletion: true + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_buildpacks-v3_java_cr.yaml b/test/data/v1beta1/build_buildpacks-v3_java_cr.yaml new file mode 100644 index 0000000000..8628426e2b --- /dev/null +++ b/test/data/v1beta1/build_buildpacks-v3_java_cr.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildpack-java-build +spec: + source: + git: + url: https://github.com/shipwright-io/sample-java + contextDir: source-build + strategy: + name: buildpacks-v3 + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_buildpacks-v3_php_cr.yaml b/test/data/v1beta1/build_buildpacks-v3_php_cr.yaml new file mode 100644 index 0000000000..4966f5b6a8 --- /dev/null +++ b/test/data/v1beta1/build_buildpacks-v3_php_cr.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildpack-php-build +spec: + source: + git: + url: https://github.com/shipwright-io/sample-php + contextDir: source-build + strategy: + name: buildpacks-v3 + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_buildpacks-v3_ruby_cr.yaml b/test/data/v1beta1/build_buildpacks-v3_ruby_cr.yaml new file mode 100644 index 0000000000..440dc37c96 --- /dev/null +++ b/test/data/v1beta1/build_buildpacks-v3_ruby_cr.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildpack-ruby-build +spec: + source: + git: + url: https://github.com/shipwright-io/sample-ruby + contextDir: source-build + strategy: + name: buildpacks-v3 + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_kaniko_cr_advanced_dockerfile.yaml b/test/data/v1beta1/build_kaniko_cr_advanced_dockerfile.yaml new file mode 100644 index 0000000000..46818a38c2 --- /dev/null +++ b/test/data/v1beta1/build_kaniko_cr_advanced_dockerfile.yaml @@ -0,0 +1,20 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: kaniko-advanced-dockerfile +spec: + source: + git: + url: https://github.com/shipwright-io/sample-java + contextDir: docker-build + strategy: + name: kaniko + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + retention: + atBuildDeletion: false + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/advanced-dockerfile diff --git a/test/data/v1beta1/build_kaniko_cr_custom_context+dockerfile.yaml b/test/data/v1beta1/build_kaniko_cr_custom_context+dockerfile.yaml new file mode 100644 index 0000000000..2d6ccc5966 --- /dev/null +++ b/test/data/v1beta1/build_kaniko_cr_custom_context+dockerfile.yaml @@ -0,0 +1,18 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: kaniko-custom-context-dockerfile +spec: + source: + git: + url: https://github.com/shipwright-io/sample-nodejs + contextDir: docker-build + strategy: + name: kaniko + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/renamed-dockerfile diff --git a/test/data/v1beta1/build_kaniko_cr_private_github.yaml b/test/data/v1beta1/build_kaniko_cr_private_github.yaml new file mode 100644 index 0000000000..26fdfd6e3f --- /dev/null +++ b/test/data/v1beta1/build_kaniko_cr_private_github.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: kaniko-golang-build +spec: + source: + git: + url: git@github.com:qu1queee/newtaxi.git + strategy: + name: kaniko + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_kaniko_cr_private_gitlab.yaml b/test/data/v1beta1/build_kaniko_cr_private_gitlab.yaml new file mode 100644 index 0000000000..a0a4c87505 --- /dev/null +++ b/test/data/v1beta1/build_kaniko_cr_private_gitlab.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: kaniko-golang-build +spec: + source: + git: + url: git@gitlab.com:eduardooli/newtaxi.git + strategy: + name: kaniko + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/taxi-app diff --git a/test/data/v1beta1/build_non_existing_repo.yaml b/test/data/v1beta1/build_non_existing_repo.yaml new file mode 100644 index 0000000000..6c8869fd6a --- /dev/null +++ b/test/data/v1beta1/build_non_existing_repo.yaml @@ -0,0 +1,15 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: build-non-existing-repo +spec: + source: + git: + url: https://github.com/shipwright-io/sample-nodejs-no-exists + strategy: + name: kaniko + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/no-exists + diff --git a/test/data/v1beta1/build_source-to-image_cr_private_github.yaml b/test/data/v1beta1/build_source-to-image_cr_private_github.yaml new file mode 100644 index 0000000000..747de724b0 --- /dev/null +++ b/test/data/v1beta1/build_source-to-image_cr_private_github.yaml @@ -0,0 +1,17 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: s2i-nodejs-build +spec: + source: + git: + url: git@github.com:shipwright-io/sample-nodejs-private.git + strategy: + name: source-to-image + kind: ClusterBuildStrategy + paramValues: + - name: builder-image + value: docker.io/centos/nodejs-10-centos7 + output: + image: image-registry.openshift-image-registry.svc:5000/build-examples/nodejs-ex diff --git a/test/data/v1beta1/buildrun_buildah_cr_custom_context+dockerfile.yaml b/test/data/v1beta1/buildrun_buildah_cr_custom_context+dockerfile.yaml new file mode 100644 index 0000000000..c3b2201be6 --- /dev/null +++ b/test/data/v1beta1/buildrun_buildah_cr_custom_context+dockerfile.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildah-custom-context-dockerfile +spec: + build: + name: buildah-custom-context-dockerfile diff --git a/test/data/v1beta1/buildrun_buildah_cr_local_source_upload.yaml b/test/data/v1beta1/buildrun_buildah_cr_local_source_upload.yaml new file mode 100644 index 0000000000..33e531c84c --- /dev/null +++ b/test/data/v1beta1/buildrun_buildah_cr_local_source_upload.yaml @@ -0,0 +1,10 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildah-golang-local-source-upload +spec: + build: + name: buildah-local-source-upload + sources: + - name: local-copy diff --git a/test/data/v1beta1/buildrun_buildah_cr_mutate.yaml b/test/data/v1beta1/buildrun_buildah_cr_mutate.yaml new file mode 100644 index 0000000000..4bc58d2c98 --- /dev/null +++ b/test/data/v1beta1/buildrun_buildah_cr_mutate.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildah-golang-build-mutate +spec: + build: + name: buildah-golang-build-mutate diff --git a/test/data/v1beta1/buildrun_buildpacks-v3_golang_cr.yaml b/test/data/v1beta1/buildrun_buildpacks-v3_golang_cr.yaml new file mode 100644 index 0000000000..da98647892 --- /dev/null +++ b/test/data/v1beta1/buildrun_buildpacks-v3_golang_cr.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildpack-golang-buildrun +spec: + build: + name: buildpack-golang-build + serviceAccount: ".generate" diff --git a/test/data/v1beta1/buildrun_buildpacks-v3_java_cr.yaml b/test/data/v1beta1/buildrun_buildpacks-v3_java_cr.yaml new file mode 100644 index 0000000000..294697cafb --- /dev/null +++ b/test/data/v1beta1/buildrun_buildpacks-v3_java_cr.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildpack-java-buildrun +spec: + build: + name: buildpack-java-build + serviceAccount: ".generate" diff --git a/test/data/v1beta1/buildrun_buildpacks-v3_nodejs_runtime-image_cr.yaml b/test/data/v1beta1/buildrun_buildpacks-v3_nodejs_runtime-image_cr.yaml new file mode 100644 index 0000000000..074f6dea5b --- /dev/null +++ b/test/data/v1beta1/buildrun_buildpacks-v3_nodejs_runtime-image_cr.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildpack-nodejs-buildrun-heroku +spec: + build: + name: buildpack-nodejs-build-heroku + serviceAccount: ".generate" diff --git a/test/data/v1beta1/buildrun_buildpacks-v3_php_cr.yaml b/test/data/v1beta1/buildrun_buildpacks-v3_php_cr.yaml new file mode 100644 index 0000000000..0bcd8731d2 --- /dev/null +++ b/test/data/v1beta1/buildrun_buildpacks-v3_php_cr.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildpack-php-buildrun +spec: + build: + name: buildpack-php-build + serviceAccount: ".generate" diff --git a/test/data/v1beta1/buildrun_buildpacks-v3_ruby_cr.yaml b/test/data/v1beta1/buildrun_buildpacks-v3_ruby_cr.yaml new file mode 100644 index 0000000000..d8a6a1cfdb --- /dev/null +++ b/test/data/v1beta1/buildrun_buildpacks-v3_ruby_cr.yaml @@ -0,0 +1,9 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildpack-ruby-buildrun +spec: + build: + name: buildpack-ruby-build + serviceAccount: ".generate" diff --git a/test/data/v1beta1/buildrun_kaniko_cr_advanced_dockerfile.yaml b/test/data/v1beta1/buildrun_kaniko_cr_advanced_dockerfile.yaml new file mode 100644 index 0000000000..9a754e63be --- /dev/null +++ b/test/data/v1beta1/buildrun_kaniko_cr_advanced_dockerfile.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: kaniko-advanced-dockerfile +spec: + build: + name: kaniko-advanced-dockerfile diff --git a/test/data/v1beta1/buildrun_kaniko_cr_custom_context+dockerfile.yaml b/test/data/v1beta1/buildrun_kaniko_cr_custom_context+dockerfile.yaml new file mode 100644 index 0000000000..ba796cabb2 --- /dev/null +++ b/test/data/v1beta1/buildrun_kaniko_cr_custom_context+dockerfile.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: kaniko-custom-context-dockerfile +spec: + build: + name: kaniko-custom-context-dockerfile diff --git a/test/data/v1beta1/buildrun_non_existing_repo.yaml b/test/data/v1beta1/buildrun_non_existing_repo.yaml new file mode 100644 index 0000000000..eac965a18d --- /dev/null +++ b/test/data/v1beta1/buildrun_non_existing_repo.yaml @@ -0,0 +1,8 @@ +--- +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildrun-non-existing-repo +spec: + build: + name: buildrun-non-existing-repo diff --git a/test/e2e/common_suite_test.go b/test/e2e/v1alpha1/common_suite_test.go similarity index 98% rename from test/e2e/common_suite_test.go rename to test/e2e/v1alpha1/common_suite_test.go index 14a166fc49..b4b453d214 100644 --- a/test/e2e/common_suite_test.go +++ b/test/e2e/v1alpha1/common_suite_test.go @@ -17,7 +17,7 @@ import ( core "k8s.io/api/core/v1" meta "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" ) @@ -73,7 +73,7 @@ func (b *buildPrototype) SourceCredentials(name string) *buildPrototype { } func (b *buildPrototype) SourceGit(repository string) *buildPrototype { - b.build.Spec.Source.URL = pointer.String(repository) + b.build.Spec.Source.URL = ptr.To[string](repository) b.build.Spec.Source.BundleContainer = nil return b } @@ -95,7 +95,7 @@ func (b *buildPrototype) SourceBundlePrune(prune buildv1alpha1.PruneOption) *bui } func (b *buildPrototype) SourceContextDir(contextDir string) *buildPrototype { - b.build.Spec.Source.ContextDir = pointer.String(contextDir) + b.build.Spec.Source.ContextDir = ptr.To[string](contextDir) return b } @@ -280,7 +280,7 @@ func (b *buildRunPrototype) GenerateServiceAccount() *buildRunPrototype { if b.buildRun.Spec.ServiceAccount == nil { b.buildRun.Spec.ServiceAccount = &buildv1alpha1.ServiceAccount{} } - b.buildRun.Spec.ServiceAccount.Generate = pointer.Bool(true) + b.buildRun.Spec.ServiceAccount.Generate = ptr.To[bool](true) return b } diff --git a/test/e2e/common_test.go b/test/e2e/v1alpha1/common_test.go similarity index 99% rename from test/e2e/common_test.go rename to test/e2e/v1alpha1/common_test.go index 87443e450e..4c3c9ba7ce 100644 --- a/test/e2e/common_test.go +++ b/test/e2e/v1alpha1/common_test.go @@ -25,7 +25,7 @@ import ( buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" - "github.com/shipwright-io/build/test/utils" + utils "github.com/shipwright-io/build/test/utils/v1alpha1" ) func generateTestID(id string) string { diff --git a/test/e2e/e2e_bundle_test.go b/test/e2e/v1alpha1/e2e_bundle_test.go similarity index 100% rename from test/e2e/e2e_bundle_test.go rename to test/e2e/v1alpha1/e2e_bundle_test.go diff --git a/test/e2e/e2e_image_mutate_test.go b/test/e2e/v1alpha1/e2e_image_mutate_test.go similarity index 94% rename from test/e2e/e2e_image_mutate_test.go rename to test/e2e/v1alpha1/e2e_image_mutate_test.go index 04fd005725..d2fdacb5f0 100644 --- a/test/e2e/e2e_image_mutate_test.go +++ b/test/e2e/v1alpha1/e2e_image_mutate_test.go @@ -46,14 +46,14 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildah_cr_mutate.yaml", + "test/data/v1alpha1/build_buildah_cr_mutate.yaml", ) }) It("should mutate an image with annotation and label", func() { buildRun, err = buildRunTestData( testBuild.Namespace, testID, - "test/data/buildrun_buildah_cr_mutate.yaml", + "test/data/v1alpha1/buildrun_buildah_cr_mutate.yaml", ) Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") appendRegistryInsecureParamValue(build, buildRun) diff --git a/test/e2e/e2e_local_source_upload_test.go b/test/e2e/v1alpha1/e2e_local_source_upload_test.go similarity index 93% rename from test/e2e/e2e_local_source_upload_test.go rename to test/e2e/v1alpha1/e2e_local_source_upload_test.go index d3972fa4b5..273bf3191d 100644 --- a/test/e2e/e2e_local_source_upload_test.go +++ b/test/e2e/v1alpha1/e2e_local_source_upload_test.go @@ -13,7 +13,7 @@ import ( "k8s.io/apimachinery/pkg/types" buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test/utils" + utils "github.com/shipwright-io/build/test/utils/v1alpha1" ) var _ = Describe("For a Kubernetes cluster with Tekton and build installed", func() { @@ -41,7 +41,7 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildah_cr_local_source_upload.yaml", + "test/data/v1alpha1/build_buildah_cr_local_source_upload.yaml", ) }) @@ -50,7 +50,7 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun buildRun, err = buildRunTestData( testBuild.Namespace, testID, - "test/data/buildrun_buildah_cr_local_source_upload.yaml", + "test/data/v1alpha1/buildrun_buildah_cr_local_source_upload.yaml", ) Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") diff --git a/test/e2e/e2e_one_off_builds_test.go b/test/e2e/v1alpha1/e2e_one_off_builds_test.go similarity index 100% rename from test/e2e/e2e_one_off_builds_test.go rename to test/e2e/v1alpha1/e2e_one_off_builds_test.go diff --git a/test/e2e/e2e_params_test.go b/test/e2e/v1alpha1/e2e_params_test.go similarity index 96% rename from test/e2e/e2e_params_test.go rename to test/e2e/v1alpha1/e2e_params_test.go index 96c2900282..608b5adf24 100644 --- a/test/e2e/e2e_params_test.go +++ b/test/e2e/v1alpha1/e2e_params_test.go @@ -9,10 +9,10 @@ import ( . "github.com/onsi/gomega" buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" ) var _ = Describe("For a Kubernetes cluster with Tekton and build installed", func() { @@ -101,7 +101,7 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun OutputImage("dummy"). // The parameters StringParamValue("env1", "13"). - StringParamValueFromConfigMap("env2", "a-configmap", "number1", pointer.String("2${CONFIGMAP_VALUE}")). + StringParamValueFromConfigMap("env2", "a-configmap", "number1", ptr.To[string]("2${CONFIGMAP_VALUE}")). ArrayParamValueFromConfigMap("commands", "a-configmap", "shell", nil). ArrayParamValue("commands", "-c"). Create() @@ -115,7 +115,7 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun GenerateServiceAccount(). StringParamValue("image", "registry.access.redhat.com/ubi9/ubi-minimal"). StringParamValueFromSecret("env3", "a-secret", "number2", nil). - ArrayParamValueFromSecret("args", "a-secret", "number3", pointer.String("${SECRET_VALUE}9")). + ArrayParamValueFromSecret("args", "a-secret", "number3", ptr.To[string]("${SECRET_VALUE}9")). ArrayParamValue("args", "47"). Create() Expect(err).ToNot(HaveOccurred()) diff --git a/test/e2e/e2e_rbac_test.go b/test/e2e/v1alpha1/e2e_rbac_test.go similarity index 100% rename from test/e2e/e2e_rbac_test.go rename to test/e2e/v1alpha1/e2e_rbac_test.go diff --git a/test/e2e/v1alpha1/e2e_suite_test.go b/test/e2e/v1alpha1/e2e_suite_test.go new file mode 100644 index 0000000000..a3a186ee67 --- /dev/null +++ b/test/e2e/v1alpha1/e2e_suite_test.go @@ -0,0 +1,52 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + "os" + "testing" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + utils "github.com/shipwright-io/build/test/utils/v1alpha1" +) + +var ( + testBuild *utils.TestBuild + stop = make(chan struct{}) +) + +func TestE2E(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "E2E Suite") +} + +var ( + _ = BeforeSuite(func() { + var ( + ok bool + err error + ) + + testBuild, err = utils.NewTestBuild() + Expect(err).ToNot(HaveOccurred()) + + testBuild.Namespace, ok = os.LookupEnv("TEST_NAMESPACE") + Expect(ok).To(BeTrue(), "TEST_NAMESPACE should be set") + Expect(testBuild.Namespace).ToNot(BeEmpty()) + + // create the pipeline service account + Logf("Creating the pipeline service account") + createPipelineServiceAccount(testBuild) + + // create the container registry secret + Logf("Creating the container registry secret") + createContainerRegistrySecret(testBuild) + }) + + _ = AfterSuite(func() { + close(stop) + }) +) diff --git a/test/e2e/e2e_test.go b/test/e2e/v1alpha1/e2e_test.go similarity index 83% rename from test/e2e/e2e_test.go rename to test/e2e/v1alpha1/e2e_test.go index 9d234d5db6..98ed07c4c7 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/v1alpha1/e2e_test.go @@ -55,12 +55,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_buildah_shipwright_managed_push_cr.yaml", + "samples/v1alpha1/build/build_buildah_shipwright_managed_push_cr.yaml", ) }) It("successfully runs a build and surface results to BuildRun", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_buildah_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_buildah_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") appendRegistryInsecureParamValue(build, buildRun) @@ -79,12 +79,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_buildah_strategy_managed_push_cr.yaml", + "samples/v1alpha1/build/build_buildah_strategy_managed_push_cr.yaml", ) }) It("successfully runs a build and surface results to BuildRun", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_buildah_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_buildah_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") appendRegistryInsecureParamValue(build, buildRun) @@ -103,12 +103,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildah_cr_custom_context+dockerfile.yaml", + "test/data/v1alpha1/build_buildah_cr_custom_context+dockerfile.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/buildrun_buildah_cr_custom_context+dockerfile.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1alpha1/buildrun_buildah_cr_custom_context+dockerfile.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") appendRegistryInsecureParamValue(build, buildRun) @@ -126,12 +126,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_buildpacks-v3-heroku_cr.yaml", + "samples/v1alpha1/build/build_buildpacks-v3-heroku_cr.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -145,7 +145,7 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun BeforeEach(func() { testID = generateTestID("buildpacks-v3-heroku-namespaced") - buildStrategy, err = buildStrategyTestData(testBuild.Namespace, "samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml") + buildStrategy, err = buildStrategyTestData(testBuild.Namespace, "samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml") Expect(err).ToNot(HaveOccurred()) err = testBuild.CreateBuildStrategy(buildStrategy) @@ -155,12 +155,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_buildpacks-v3-heroku_namespaced_cr.yaml", + "samples/v1alpha1/build/build_buildpacks-v3-heroku_namespaced_cr.yaml", ) }) It("successfully runs a build and surface results to BuildRun", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml") Expect(err).ToNot(HaveOccurred()) buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -183,12 +183,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_buildpacks-v3_cr.yaml", + "samples/v1alpha1/build/build_buildpacks-v3_cr.yaml", ) }) It("successfully runs a build and surface results to BuildRun", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_buildpacks-v3_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_buildpacks-v3_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -203,7 +203,7 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun BeforeEach(func() { testID = generateTestID("buildpacks-v3-namespaced") - buildStrategy, err = buildStrategyTestData(testBuild.Namespace, "samples/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml") + buildStrategy, err = buildStrategyTestData(testBuild.Namespace, "samples/v1alpha1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml") Expect(err).ToNot(HaveOccurred()) err = testBuild.CreateBuildStrategy(buildStrategy) @@ -213,12 +213,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_buildpacks-v3_namespaced_cr.yaml", + "samples/v1alpha1/build/build_buildpacks-v3_namespaced_cr.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -240,12 +240,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildpacks-v3_php_cr.yaml", + "test/data/v1alpha1/build_buildpacks-v3_php_cr.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/buildrun_buildpacks-v3_php_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1alpha1/buildrun_buildpacks-v3_php_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -262,12 +262,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildpacks-v3_ruby_cr.yaml", + "test/data/v1alpha1/build_buildpacks-v3_ruby_cr.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/buildrun_buildpacks-v3_ruby_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1alpha1/buildrun_buildpacks-v3_ruby_cr.yaml") Expect(err).ToNot(HaveOccurred()) buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -284,12 +284,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildpacks-v3_golang_cr.yaml", + "test/data/v1alpha1/build_buildpacks-v3_golang_cr.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/buildrun_buildpacks-v3_golang_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1alpha1/buildrun_buildpacks-v3_golang_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -305,12 +305,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildpacks-v3_golang_cr_env.yaml", + "test/data/v1alpha1/build_buildpacks-v3_golang_cr_env.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/buildrun_buildpacks-v3_golang_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1alpha1/buildrun_buildpacks-v3_golang_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -327,13 +327,13 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildpacks-v3_golang_delete_cr.yaml", + "test/data/v1alpha1/build_buildpacks-v3_golang_delete_cr.yaml", ) }) It("successfully deletes the BuildRun after the Build is deleted", func() { By("running a build and expecting it to succeed") - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/buildrun_buildpacks-v3_golang_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1alpha1/buildrun_buildpacks-v3_golang_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -364,12 +364,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildpacks-v3_java_cr.yaml", + "test/data/v1alpha1/build_buildpacks-v3_java_cr.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/buildrun_buildpacks-v3_java_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1alpha1/buildrun_buildpacks-v3_java_cr.yaml") Expect(err).ToNot(HaveOccurred()) buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -386,12 +386,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_kaniko_cr.yaml", + "samples/v1alpha1/build/build_kaniko_cr.yaml", ) }) It("successfully runs a build and surface results to BuildRun", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_kaniko_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_kaniko_cr.yaml") Expect(err).ToNot(HaveOccurred()) buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -409,12 +409,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_kaniko_cr_advanced_dockerfile.yaml", + "test/data/v1alpha1/build_kaniko_cr_advanced_dockerfile.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/buildrun_kaniko_cr_advanced_dockerfile.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1alpha1/buildrun_kaniko_cr_advanced_dockerfile.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -431,12 +431,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_kaniko_cr_custom_context+dockerfile.yaml", + "test/data/v1alpha1/build_kaniko_cr_custom_context+dockerfile.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/buildrun_kaniko_cr_custom_context+dockerfile.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1alpha1/buildrun_kaniko_cr_custom_context+dockerfile.yaml") Expect(err).ToNot(HaveOccurred()) buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -453,12 +453,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_kaniko-trivy-good_cr.yaml", + "samples/v1alpha1/build/build_kaniko-trivy-good_cr.yaml", ) }) It("successfully runs a build and surface results to BuildRun", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_kaniko-trivy-good_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_kaniko-trivy-good_cr.yaml") Expect(err).ToNot(HaveOccurred()) buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -476,12 +476,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_kaniko-trivy-bad_cr.yaml", + "samples/v1alpha1/build/build_kaniko-trivy-bad_cr.yaml", ) }) It("fails to run a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_kaniko-trivy-bad_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_kaniko-trivy-bad_cr.yaml") Expect(err).ToNot(HaveOccurred()) validateBuildRunToFail(testBuild, buildRun) @@ -497,12 +497,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_buildkit_cr.yaml", + "samples/v1alpha1/build/build_buildkit_cr.yaml", ) }) It("successfully runs a build and surface results to BuildRun", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_buildkit_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_buildkit_cr.yaml") Expect(err).ToNot(HaveOccurred()) buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -529,12 +529,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "samples/build/build_source-to-image_cr.yaml", + "samples/v1alpha1/build/build_source-to-image_cr.yaml", ) }) It("successfully runs a build and surface results to BuildRun", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_source-to-image_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_source-to-image_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -560,12 +560,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildah_cr_private_github.yaml", + "test/data/v1alpha1/build_buildah_cr_private_github.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_buildah_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_buildah_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -582,12 +582,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_buildah_cr_private_gitlab.yaml", + "test/data/v1alpha1/build_buildah_cr_private_gitlab.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_buildah_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_buildah_cr.yaml") Expect(err).ToNot(HaveOccurred()) buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -604,12 +604,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_kaniko_cr_private_github.yaml", + "test/data/v1alpha1/build_kaniko_cr_private_github.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_kaniko_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_kaniko_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -626,12 +626,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_kaniko_cr_private_gitlab.yaml", + "test/data/v1alpha1/build_kaniko_cr_private_gitlab.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_kaniko_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_kaniko_cr.yaml") Expect(err).ToNot(HaveOccurred()) buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -648,12 +648,12 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_source-to-image_cr_private_github.yaml", + "test/data/v1alpha1/build_source-to-image_cr_private_github.yaml", ) }) It("successfully runs a build", func() { - buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/buildrun/buildrun_source-to-image_cr.yaml") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1alpha1/buildrun/buildrun_source-to-image_cr.yaml") Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") buildRun = validateBuildRunToSucceed(testBuild, buildRun) @@ -669,10 +669,10 @@ var _ = Describe("For a Kubernetes cluster with Tekton and build installed", fun build = createBuild( testBuild, testID, - "test/data/build_non_existing_repo.yaml", + "test/data/v1alpha1/build_non_existing_repo.yaml", ) - buildRun, err = buildRunTestData(build.Namespace, testID, "test/data/buildrun_non_existing_repo.yaml") + buildRun, err = buildRunTestData(build.Namespace, testID, "test/data/v1alpha1/buildrun_non_existing_repo.yaml") Expect(err).ToNot(HaveOccurred()) validateBuildRunToFail(testBuild, buildRun) diff --git a/test/e2e/validators_test.go b/test/e2e/v1alpha1/validators_test.go similarity index 98% rename from test/e2e/validators_test.go rename to test/e2e/v1alpha1/validators_test.go index fb48b9a166..ba68b0a583 100644 --- a/test/e2e/validators_test.go +++ b/test/e2e/v1alpha1/validators_test.go @@ -20,11 +20,11 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" "k8s.io/kubectl/pkg/scheme" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "github.com/shipwright-io/build/pkg/apis" buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test/utils" + utils "github.com/shipwright-io/build/test/utils/v1alpha1" ) const ( @@ -280,7 +280,7 @@ func readAndDecode(filePath string) (runtime.Object, error) { return nil, err } - payload, err := os.ReadFile(filepath.Join("..", "..", filePath)) + payload, err := os.ReadFile(filepath.Join("..", "..", "..", filePath)) if err != nil { return nil, err } @@ -337,7 +337,7 @@ func buildRunTestData(ns string, identifier string, filePath string) (*buildv1al serviceAccountName := os.Getenv(EnvVarServiceAccountName) if serviceAccountName == "generated" { buildRun.Spec.ServiceAccount = &buildv1alpha1.ServiceAccount{ - Generate: pointer.Bool(true), + Generate: ptr.To[bool](true), } } else { buildRun.Spec.ServiceAccount = &buildv1alpha1.ServiceAccount{ diff --git a/test/e2e/v1beta1/common_suite_test.go b/test/e2e/v1beta1/common_suite_test.go new file mode 100644 index 0000000000..21b5fbc526 --- /dev/null +++ b/test/e2e/v1beta1/common_suite_test.go @@ -0,0 +1,447 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + "context" + "fmt" + "os" + "strconv" + "strings" + "time" + + . "github.com/onsi/ginkgo/v2" + + core "k8s.io/api/core/v1" + meta "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/utils/ptr" + + buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +const ( + pollCreateInterval = 1 * time.Second + pollCreateTimeout = 10 * time.Second +) + +type buildPrototype struct{ build buildv1beta1.Build } +type buildRunPrototype struct{ buildRun buildv1beta1.BuildRun } + +func NewBuildPrototype() *buildPrototype { + return &buildPrototype{ + build: buildv1beta1.Build{}, + } +} + +func (b *buildPrototype) Name(name string) *buildPrototype { + b.build.ObjectMeta.Name = name + return b +} + +func (b *buildPrototype) Namespace(namespace string) *buildPrototype { + b.build.ObjectMeta.Namespace = namespace + return b +} + +func (b *buildPrototype) BuildStrategy(name string) *buildPrototype { + var bs = buildv1beta1.NamespacedBuildStrategyKind + b.build.Spec.Strategy = buildv1beta1.Strategy{ + Kind: &bs, + Name: name, + } + return b +} + +func (b *buildPrototype) ClusterBuildStrategy(name string) *buildPrototype { + var cbs = buildv1beta1.ClusterBuildStrategyKind + b.build.Spec.Strategy = buildv1beta1.Strategy{ + Kind: &cbs, + Name: name, + } + return b +} + +func (b *buildPrototype) SourceCredentials(name string) *buildPrototype { + if name != "" { + if b.build.Spec.Source.GitSource == nil { + b.build.Spec.Source.GitSource = &buildv1beta1.Git{} + } + b.build.Spec.Source.GitSource.CloneSecret = &name + } + + return b +} + +func (b *buildPrototype) SourceGit(repository string) *buildPrototype { + if b.build.Spec.Source.GitSource == nil { + b.build.Spec.Source.GitSource = &buildv1beta1.Git{} + } + b.build.Spec.Source.GitSource.URL = ptr.To[string](repository) + b.build.Spec.Source.OCIArtifact = nil + return b +} + +func (b *buildPrototype) SourceBundle(image string) *buildPrototype { + if b.build.Spec.Source.OCIArtifact == nil { + b.build.Spec.Source.OCIArtifact = &buildv1beta1.OCIArtifact{} + } + b.build.Spec.Source.Type = buildv1beta1.OCIArtifactType + b.build.Spec.Source.OCIArtifact.Image = image + return b +} + +func (b *buildPrototype) SourceBundlePrune(prune buildv1beta1.PruneOption) *buildPrototype { + if b.build.Spec.Source.OCIArtifact == nil { + b.build.Spec.Source.OCIArtifact = &buildv1beta1.OCIArtifact{} + } + b.build.Spec.Source.OCIArtifact.Prune = &prune + return b +} + +func (b *buildPrototype) SourceContextDir(contextDir string) *buildPrototype { + b.build.Spec.Source.ContextDir = ptr.To[string](contextDir) + return b +} + +func (b *buildPrototype) Dockerfile(dockerfile string) *buildPrototype { + b.build.Spec.ParamValues = append( + b.build.Spec.ParamValues, + buildv1beta1.ParamValue{ + Name: "dockerfile", + SingleValue: &buildv1beta1.SingleValue{ + Value: &dockerfile, + }, + }, + ) + return b +} + +func (b *buildPrototype) OutputImage(image string) *buildPrototype { + b.build.Spec.Output.Image = image + return b +} + +func (b *buildPrototype) determineParameterIndex(name string) int { + index := -1 + for i, paramValue := range b.build.Spec.ParamValues { + if paramValue.Name == name { + index = i + break + } + } + + if index == -1 { + index = len(b.build.Spec.ParamValues) + b.build.Spec.ParamValues = append(b.build.Spec.ParamValues, buildv1beta1.ParamValue{ + Name: name, + }) + } + + return index +} + +// ArrayParamValue adds an item to an array parameter, if the parameter is not yet present, it is being added +func (b *buildPrototype) ArrayParamValue(name string, value string) *buildPrototype { + index := b.determineParameterIndex(name) + b.build.Spec.ParamValues[index].Values = append(b.build.Spec.ParamValues[index].Values, buildv1beta1.SingleValue{ + Value: &value, + }) + + return b +} + +// ArrayParamValueFromConfigMap adds an item to an array parameter, if the parameter is not yet present, it is being added +func (b *buildPrototype) ArrayParamValueFromConfigMap(name string, configMapName string, configMapKey string, format *string) *buildPrototype { + index := b.determineParameterIndex(name) + b.build.Spec.ParamValues[index].Values = append(b.build.Spec.ParamValues[index].Values, buildv1beta1.SingleValue{ + ConfigMapValue: &buildv1beta1.ObjectKeyRef{ + Name: configMapName, + Key: configMapKey, + Format: format, + }, + }) + + return b +} + +// ArrayParamValueFromSecret adds an item to an array parameter, if the parameter is not yet present, it is being added +func (b *buildPrototype) ArrayParamValueFromSecret(name string, secretName string, secretKey string, format *string) *buildPrototype { + index := b.determineParameterIndex(name) + b.build.Spec.ParamValues[index].Values = append(b.build.Spec.ParamValues[index].Values, buildv1beta1.SingleValue{ + SecretValue: &buildv1beta1.ObjectKeyRef{ + Name: secretName, + Key: secretKey, + Format: format, + }, + }) + + return b +} + +func (b *buildPrototype) StringParamValue(name string, value string) *buildPrototype { + b.build.Spec.ParamValues = append(b.build.Spec.ParamValues, buildv1beta1.ParamValue{ + Name: name, + SingleValue: &buildv1beta1.SingleValue{ + Value: &value, + }, + }) + + return b +} + +func (b *buildPrototype) StringParamValueFromConfigMap(name string, configMapName string, configMapKey string, format *string) *buildPrototype { + b.build.Spec.ParamValues = append(b.build.Spec.ParamValues, buildv1beta1.ParamValue{ + Name: name, + SingleValue: &buildv1beta1.SingleValue{ + ConfigMapValue: &buildv1beta1.ObjectKeyRef{ + Name: configMapName, + Key: configMapKey, + Format: format, + }, + }, + }) + + return b +} + +func (b *buildPrototype) StringParamValueFromSecret(name string, secretName string, secretKey string, format *string) *buildPrototype { + b.build.Spec.ParamValues = append(b.build.Spec.ParamValues, buildv1beta1.ParamValue{ + Name: name, + SingleValue: &buildv1beta1.SingleValue{ + SecretValue: &buildv1beta1.ObjectKeyRef{ + Name: secretName, + Key: secretKey, + Format: format, + }, + }, + }) + + return b +} + +func (b *buildPrototype) OutputImageCredentials(name string) *buildPrototype { + if name != "" { + b.build.Spec.Output.PushSecret = &name + } + return b +} + +func (b *buildPrototype) OutputImageInsecure(insecure bool) *buildPrototype { + b.build.Spec.Output.Insecure = &insecure + + return b +} + +func (b buildPrototype) Create() (build *buildv1beta1.Build, err error) { + ctx := context.Background() + + _, err = testBuild. + BuildClientSet. + ShipwrightV1beta1(). + Builds(b.build.Namespace). + Create(ctx, &b.build, meta.CreateOptions{}) + + if err != nil { + return nil, err + } + + err = wait.PollImmediate(pollCreateInterval, pollCreateTimeout, func() (done bool, err error) { + build, err = testBuild.BuildClientSet.ShipwrightV1beta1().Builds(b.build.Namespace).Get(ctx, b.build.Name, meta.GetOptions{}) + if err != nil { + return false, err + } + + return build.Status.Registered != nil && *build.Status.Registered == core.ConditionTrue, nil + }) + + return +} + +// BuildSpec returns the BuildSpec of this Build (no cluster resource is created) +func (b buildPrototype) BuildSpec() (build *buildv1beta1.BuildSpec) { + return &b.build.Spec +} + +func NewBuildRunPrototype() *buildRunPrototype { + return &buildRunPrototype{buildRun: buildv1beta1.BuildRun{}} +} + +func (b *buildRunPrototype) Name(name string) *buildRunPrototype { + b.buildRun.ObjectMeta.Name = name + return b +} + +func (b *buildRunPrototype) Namespace(namespace string) *buildRunPrototype { + b.buildRun.Namespace = namespace + return b +} + +func (b *buildRunPrototype) ForBuild(build *buildv1beta1.Build) *buildRunPrototype { + if b.buildRun.Spec.Build == nil { + b.buildRun.Spec.Build = &buildv1beta1.ReferencedBuild{} + } + b.buildRun.Spec.Build.Name = build.Name + b.buildRun.ObjectMeta.Namespace = build.Namespace + return b +} + +func (b *buildRunPrototype) WithBuildSpec(buildSpec *buildv1beta1.BuildSpec) *buildRunPrototype { + if b.buildRun.Spec.Build == nil { + b.buildRun.Spec.Build = &buildv1beta1.ReferencedBuild{} + } + b.buildRun.Spec.Build.Build = buildSpec + return b +} + +func (b *buildRunPrototype) GenerateServiceAccount() *buildRunPrototype { + generate := ".generate" + if b.buildRun.Spec.ServiceAccount == nil { + b.buildRun.Spec.ServiceAccount = &generate + } + return b +} + +func (b *buildRunPrototype) determineParameterIndex(name string) int { + index := -1 + for i, paramValue := range b.buildRun.Spec.ParamValues { + if paramValue.Name == name { + index = i + break + } + } + + if index == -1 { + index = len(b.buildRun.Spec.ParamValues) + b.buildRun.Spec.ParamValues = append(b.buildRun.Spec.ParamValues, buildv1beta1.ParamValue{ + Name: name, + }) + } + + return index +} + +// ArrayParamValue adds an item to an array parameter, if the parameter is not yet present, it is being added +func (b *buildRunPrototype) ArrayParamValue(name string, value string) *buildRunPrototype { + index := b.determineParameterIndex(name) + b.buildRun.Spec.ParamValues[index].Values = append(b.buildRun.Spec.ParamValues[index].Values, buildv1beta1.SingleValue{ + Value: &value, + }) + + return b +} + +// ArrayParamValueFromConfigMap adds an item to an array parameter, if the parameter is not yet present, it is being added +func (b *buildRunPrototype) ArrayParamValueFromConfigMap(name string, configMapName string, configMapKey string, format *string) *buildRunPrototype { + index := b.determineParameterIndex(name) + b.buildRun.Spec.ParamValues[index].Values = append(b.buildRun.Spec.ParamValues[index].Values, buildv1beta1.SingleValue{ + ConfigMapValue: &buildv1beta1.ObjectKeyRef{ + Name: configMapName, + Key: configMapKey, + Format: format, + }, + }) + + return b +} + +// ArrayParamValueFromSecret adds an item to an array parameter, if the parameter is not yet present, it is being added +func (b *buildRunPrototype) ArrayParamValueFromSecret(name string, secretName string, secretKey string, format *string) *buildRunPrototype { + index := b.determineParameterIndex(name) + b.buildRun.Spec.ParamValues[index].Values = append(b.buildRun.Spec.ParamValues[index].Values, buildv1beta1.SingleValue{ + SecretValue: &buildv1beta1.ObjectKeyRef{ + Name: secretName, + Key: secretKey, + Format: format, + }, + }) + + return b +} + +func (b *buildRunPrototype) StringParamValue(name string, value string) *buildRunPrototype { + b.buildRun.Spec.ParamValues = append(b.buildRun.Spec.ParamValues, buildv1beta1.ParamValue{ + Name: name, + SingleValue: &buildv1beta1.SingleValue{ + Value: &value, + }, + }) + + return b +} + +func (b *buildRunPrototype) StringParamValueFromConfigMap(name string, configMapName string, configMapKey string, format *string) *buildRunPrototype { + b.buildRun.Spec.ParamValues = append(b.buildRun.Spec.ParamValues, buildv1beta1.ParamValue{ + Name: name, + SingleValue: &buildv1beta1.SingleValue{ + ConfigMapValue: &buildv1beta1.ObjectKeyRef{ + Name: configMapName, + Key: configMapKey, + Format: format, + }, + }, + }) + + return b +} + +func (b *buildRunPrototype) StringParamValueFromSecret(name string, secretName string, secretKey string, format *string) *buildRunPrototype { + b.buildRun.Spec.ParamValues = append(b.buildRun.Spec.ParamValues, buildv1beta1.ParamValue{ + Name: name, + SingleValue: &buildv1beta1.SingleValue{ + SecretValue: &buildv1beta1.ObjectKeyRef{ + Name: secretName, + Key: secretKey, + Format: format, + }, + }, + }) + + return b +} + +func (b *buildRunPrototype) Create() (*buildv1beta1.BuildRun, error) { + return testBuild. + BuildClientSet. + ShipwrightV1beta1(). + BuildRuns(b.buildRun.Namespace). + Create(context.Background(), &b.buildRun, meta.CreateOptions{}) +} + +// Logf logs data +func Logf(format string, args ...interface{}) { + currentTime := time.Now().UTC().Format(time.RFC3339) + + fmt.Fprintf( + GinkgoWriter, + fmt.Sprintf("%s %d %s\n", currentTime, getGinkgoNode(), format), + args..., + ) +} + +func getArg(argName string) (bool, string) { + for i, arg := range os.Args { + if arg == argName { + return true, os.Args[i+1] + } else if strings.HasPrefix(arg, argName+"=") { + argAndValue := strings.SplitN(arg, "=", 2) + return true, argAndValue[1] + } + } + return false, "" +} + +func getGinkgoNode() int { + defined, ginkgoNodeString := getArg("--ginkgo.parallel.node") + if !defined { + return 1 + } + ginkgoNode, err := strconv.Atoi(ginkgoNodeString) + if err != nil { + fmt.Printf("Error: %s", err.Error()) + return 0 + } + return ginkgoNode +} diff --git a/test/e2e/v1beta1/common_test.go b/test/e2e/v1beta1/common_test.go new file mode 100644 index 0000000000..4ba907bb44 --- /dev/null +++ b/test/e2e/v1beta1/common_test.go @@ -0,0 +1,269 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "os" + "strconv" + "strings" + "time" + + . "github.com/onsi/gomega" + knativeapis "knative.dev/pkg/apis" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/rand" + + buildv1alpha1 "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" + buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1" + "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" + utils "github.com/shipwright-io/build/test/utils/v1beta1" +) + +func generateTestID(id string) string { + return id + "-" + rand.String(5) +} + +func removeTestIDSuffix(id string) string { + return id[:len(id)-6] +} + +func createBuild(testBuild *utils.TestBuild, identifier string, filePath string) *buildv1beta1.Build { + build, err := buildTestData(testBuild.Namespace, identifier, filePath) + Expect(err).ToNot(HaveOccurred(), "Error retrieving build test data") + + amendBuild(identifier, build) + + // For Builds that use a namespaces build strategy, there is a race condition: we just created the + // build strategy and it might be that the build controller does not yet have this in his cache + // and therefore marks the build as not registered with reason BuildStrategyNotFound + Eventually(func() buildv1beta1.BuildReason { + // cleanup the build of the previous try + if build.Status.Registered != nil && *build.Status.Registered != "" { + err = testBuild.DeleteBuild(build.Name) + Expect(err).ToNot(HaveOccurred()) + + // create a fresh object + build, err = buildTestData(testBuild.Namespace, identifier, filePath) + Expect(err).ToNot(HaveOccurred(), "Error retrieving build test data") + + amendBuild(identifier, build) + } + + err = testBuild.CreateBuild(build) + Expect(err).ToNot(HaveOccurred(), "Unable to create build %s", identifier) + Logf("Build %s created", identifier) + + build, err = testBuild.GetBuildTillValidation(build.Name) + Expect(err).ToNot(HaveOccurred()) + + return *build.Status.Reason + }, time.Duration(10*time.Second), time.Second).Should(Equal(buildv1beta1.SucceedStatus)) + + return build +} + +// amendOutputImage amend container image URL based on informed image repository. +func amendOutputImage(b *buildv1beta1.Build, imageRepo string, insecure bool) { + if imageRepo == "" { + return + } + + // image tag is the build name without the test id suffix as this would pollute the container registry + imageTag := removeTestIDSuffix(b.Name) + + imageURL := fmt.Sprintf("%s:%s", imageRepo, imageTag) + b.Spec.Output.Image = imageURL + b.Spec.Output.Insecure = &insecure + + Logf("Amended object: name='%s', image-url='%s'", b.Name, imageURL) +} + +// amendOutputCredentials amend secret-ref for output image. +func amendOutputCredentials(b *buildv1beta1.Build, secretName string) { + if secretName == "" { + return + } + b.Spec.Output.PushSecret = &secretName + Logf("Amended object: name='%s', secret-ref='%s'", b.Name, secretName) +} + +// amendSourceSecretName patch Build source.Credentials with secret name. +func amendSourceSecretName(b *buildv1beta1.Build, secretName string) { + if secretName == "" { + return + } + b.Spec.Source.GitSource.CloneSecret = &secretName +} + +// amendSourceURL patch Build source.URL with informed string. +func amendSourceURL(b *buildv1beta1.Build, sourceURL string) { + if sourceURL == "" { + return + } + b.Spec.Source.GitSource.URL = &sourceURL +} + +// amendBuild make changes on build object. +func amendBuild(identifier string, b *buildv1beta1.Build) { + if strings.Contains(identifier, "github") { + amendSourceSecretName(b, os.Getenv(EnvVarSourceURLSecret)) + amendSourceURL(b, os.Getenv(EnvVarSourceURLGithub)) + } else if strings.Contains(identifier, "gitlab") { + amendSourceSecretName(b, os.Getenv(EnvVarSourceURLSecret)) + amendSourceURL(b, os.Getenv(EnvVarSourceURLGitlab)) + } + + insecure := false + value, found := os.LookupEnv(EnvVarImageRepoInsecure) + if found { + var err error + insecure, err = strconv.ParseBool(value) + Expect(err).ToNot(HaveOccurred()) + } + + amendOutputImage(b, os.Getenv(EnvVarImageRepo), insecure) + amendOutputCredentials(b, os.Getenv(EnvVarImageRepoSecret)) +} + +// retrieveBuildAndBuildRun will retrieve the build and buildRun +func retrieveBuildAndBuildRun(testBuild *utils.TestBuild, namespace string, buildRunName string) (*buildv1beta1.Build, *buildv1beta1.BuildRun, error) { + buildRun, err := testBuild.LookupBuildRun(types.NamespacedName{Name: buildRunName, Namespace: namespace}) + if err != nil { + Logf("Failed to get BuildRun %q: %s", buildRunName, err) + return nil, nil, err + } + + var alphaBuild buildv1alpha1.Build + var obj unstructured.Unstructured + + buildRun.ConvertTo(testBuild.Context, &obj) + jsonData, err := json.Marshal(obj.Object) + if err != nil { + Logf("Failed to convert the buildRun to v1alpha1: %s", err) + } + + var alphaBuildRun buildv1alpha1.BuildRun + json.Unmarshal(jsonData, &alphaBuildRun) + + if err := resources.GetBuildObject(testBuild.Context, testBuild.ControllerRuntimeClient, &alphaBuildRun, &alphaBuild); err != nil { + Logf("Failed to get Build from BuildRun %s: %s", buildRunName, err) + return nil, buildRun, err + } + + alphaBuild.ConvertTo(testBuild.Context, &obj) + jsonData, err = json.Marshal(obj.Object) + if err != nil { + Logf("Failed to convert the build to v1beta1: %s", err) + } + var betaBuild buildv1beta1.Build + json.Unmarshal(jsonData, &betaBuild) + + return &betaBuild, buildRun, nil +} + +// printTestFailureDebugInfo will output the status of Build, BuildRun, TaskRun and Pod, also print logs of Pod +func printTestFailureDebugInfo(testBuild *utils.TestBuild, namespace string, buildRunName string) { + Logf("Print failed BuildRun's log") + + build, buildRun, err := retrieveBuildAndBuildRun(testBuild, namespace, buildRunName) + if err != nil { + Logf("Failed to retrieve build and buildrun logs: %v", err) + } + + if build != nil { + Logf("The status of Build %s: registered=%s, reason=%s", build.Name, *build.Status.Registered, *build.Status.Reason) + if buildJSON, err := json.Marshal(build); err == nil { + Logf("The full Build: %s", string(buildJSON)) + } + } + + if buildRun != nil { + brCondition := buildRun.Status.GetCondition(buildv1beta1.Succeeded) + if brCondition != nil { + Logf("The status of BuildRun %s: status=%s, reason=%s", buildRun.Name, brCondition.Status, brCondition.Reason) + } + if buildRunJSON, err := json.Marshal(buildRun); err == nil { + Logf("The full BuildRun: %s", string(buildRunJSON)) + } + + podName := "" + + // Only log details of TaskRun if Tekton objects can be accessed + if os.Getenv(EnvVarVerifyTektonObjects) == "true" { + if taskRun, _ := testBuild.LookupTaskRunUsingBuildRun(buildRun); taskRun != nil { + condition := taskRun.Status.GetCondition(knativeapis.ConditionSucceeded) + if condition != nil { + Logf("The status of TaskRun %s: reason=%s, message=%s", taskRun.Name, condition.Reason, condition.Message) + } + + if taskRunJSON, err := json.Marshal(taskRun); err == nil { + Logf("The full TaskRun: %s", string(taskRunJSON)) + } + + podName = taskRun.Status.PodName + } + } + + // retrieve or query pod depending on whether we have the pod name from the TaskRun + var pod *corev1.Pod + if podName != "" { + pod, err = testBuild.LookupPod(types.NamespacedName{Name: podName, Namespace: namespace}) + if err != nil { + Logf("Error retrieving pod %s: %v", podName, err) + pod = nil + } + } else { + podList, err := testBuild.Clientset.CoreV1().Pods(namespace).List(testBuild.Context, metav1.ListOptions{ + LabelSelector: labels.FormatLabels(map[string]string{ + buildv1beta1.LabelBuildRun: buildRunName, + }), + }) + + if err == nil && len(podList.Items) > 0 { + pod = &podList.Items[0] + } + } + + if pod != nil { + Logf("The status of Pod %s: phase=%s, reason=%s, message=%s", pod.Name, pod.Status.Phase, pod.Status.Reason, pod.Status.Message) + if podJSON, err := json.Marshal(pod); err == nil { + Logf("The full Pod: %s", string(podJSON)) + } + + // Loop through the containers to print their logs + for _, container := range pod.Spec.Containers { + req := testBuild.Clientset.CoreV1().Pods(namespace).GetLogs(pod.Name, &corev1.PodLogOptions{ + TypeMeta: metav1.TypeMeta{}, + Container: container.Name, + Follow: false, + }) + + podLogs, err := req.Stream(testBuild.Context) + if err != nil { + Logf("Failed to retrieve the logs of container %s: %v", container.Name, err) + continue + } + + buf := new(bytes.Buffer) + _, err = io.Copy(buf, podLogs) + if err != nil { + Logf("Failed to copy logs of container %s to buffer: %v", container.Name, err) + continue + } + + Logf("Logs of container %s: %s", container.Name, buf.String()) + } + } + } +} diff --git a/test/e2e/v1beta1/e2e_image_mutate_test.go b/test/e2e/v1beta1/e2e_image_mutate_test.go new file mode 100644 index 0000000000..965a58f1ac --- /dev/null +++ b/test/e2e/v1beta1/e2e_image_mutate_test.go @@ -0,0 +1,89 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + containerreg "github.com/google/go-containerregistry/pkg/v1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +var _ = Describe("For a Kubernetes cluster with Tekton and build installed", func() { + var ( + err error + testID string + build *buildv1beta1.Build + buildRun *buildv1beta1.BuildRun + ) + + AfterEach(func() { + if CurrentSpecReport().Failed() { + printTestFailureDebugInfo(testBuild, testBuild.Namespace, testID) + } else if buildRun != nil { + validateServiceAccountDeletion(buildRun, testBuild.Namespace) + } + + if buildRun != nil { + testBuild.DeleteBR(buildRun.Name) + buildRun = nil + } + + if build != nil { + testBuild.DeleteBuild(build.Name) + build = nil + } + }) + + Context("when a Buildah build with label and annotation is defined", func() { + BeforeEach(func() { + testID = generateTestID("buildah-mutate") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_buildah_cr_mutate.yaml", + ) + }) + + It("should mutate an image with annotation and label", func() { + buildRun, err = buildRunTestData( + testBuild.Namespace, testID, + "test/data/v1beta1/buildrun_buildah_cr_mutate.yaml", + ) + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + appendRegistryInsecureParamValue(build, buildRun) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + + image := testBuild.GetImage(buildRun) + + Expect( + getImageAnnotation(image, "org.opencontainers.image.url"), + ).To(Equal("https://my-company.com/images")) + + Expect( + getImageLabel(image, "maintainer"), + ).To(Equal("team@my-company.com")) + }) + }) +}) + +func getImageAnnotation(img containerreg.Image, annotation string) string { + manifest, err := img.Manifest() + Expect(err).To(BeNil()) + + return manifest.Annotations[annotation] +} + +func getImageLabel(img containerreg.Image, label string) string { + config, err := img.ConfigFile() + Expect(err).To(BeNil()) + + return config.Config.Labels[label] +} diff --git a/test/e2e/v1beta1/e2e_ociartifact_test.go b/test/e2e/v1beta1/e2e_ociartifact_test.go new file mode 100644 index 0000000000..c3dd381c96 --- /dev/null +++ b/test/e2e/v1beta1/e2e_ociartifact_test.go @@ -0,0 +1,276 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + "bytes" + "fmt" + "os" + "strconv" + "strings" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/docker/cli/cli/config" + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + "github.com/google/go-containerregistry/pkg/v1/remote" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +var _ = Describe("Test local source code (bundle) functionality", func() { + + insecure := false + value, found := os.LookupEnv(EnvVarImageRepoInsecure) + if found { + var err error + insecure, err = strconv.ParseBool(value) + Expect(err).ToNot(HaveOccurred()) + } + + var ( + testID string + err error + + build *buildv1beta1.Build + buildRun *buildv1beta1.BuildRun + ) + + AfterEach(func() { + if CurrentSpecReport().Failed() { + printTestFailureDebugInfo(testBuild, testBuild.Namespace, testID) + } else if buildRun != nil { + validateServiceAccountDeletion(buildRun, testBuild.Namespace) + } + + if buildRun != nil { + testBuild.DeleteBR(buildRun.Name) + buildRun = nil + } + + if build != nil { + testBuild.DeleteBuild(build.Name) + build = nil + } + }) + + Context("when using local source code bundle images as input", func() { + var inputImage, outputImage string + + BeforeEach(func() { + testID = generateTestID("bundle") + + inputImage = "ghcr.io/shipwright-io/sample-go/source-bundle:latest" + outputImage = fmt.Sprintf("%s/%s:%s", + os.Getenv(EnvVarImageRepo), + testID, + "latest", + ) + }) + + It("should work with Kaniko build strategy", func() { + build, err = NewBuildPrototype(). + ClusterBuildStrategy("kaniko"). + Name(testID). + Namespace(testBuild.Namespace). + SourceBundle(inputImage). + SourceContextDir("docker-build"). + Dockerfile("Dockerfile"). + OutputImage(outputImage). + OutputImageCredentials(os.Getenv(EnvVarImageRepoSecret)). + OutputImageInsecure(insecure). + Create() + Expect(err).ToNot(HaveOccurred()) + + buildRun, err = NewBuildRunPrototype(). + Name(testID). + ForBuild(build). + GenerateServiceAccount(). + Create() + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromBundleSource(buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + + It("should work with Buildpacks build strategy", func() { + build, err = NewBuildPrototype(). + ClusterBuildStrategy("buildpacks-v3"). + Name(testID). + Namespace(testBuild.Namespace). + SourceBundle(inputImage). + SourceContextDir("source-build"). + OutputImage(outputImage). + OutputImageCredentials(os.Getenv(EnvVarImageRepoSecret)). + OutputImageInsecure(insecure). + Create() + Expect(err).ToNot(HaveOccurred()) + + buildRun, err = NewBuildRunPrototype(). + Name(testID). + ForBuild(build). + GenerateServiceAccount(). + Create() + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromBundleSource(buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + + It("should work with Buildah build strategy", func() { + buildPrototype := NewBuildPrototype(). + ClusterBuildStrategy("buildah-shipwright-managed-push"). + Name(testID). + Namespace(testBuild.Namespace). + SourceBundle(inputImage). + SourceContextDir("docker-build"). + Dockerfile("Dockerfile"). + OutputImage(outputImage). + OutputImageCredentials(os.Getenv(EnvVarImageRepoSecret)). + OutputImageInsecure(insecure) + + if strings.Contains(outputImage, "cluster.local") { + parts := strings.Split(outputImage, "/") + host := parts[0] + buildPrototype.ArrayParamValue("registries-insecure", host) + } + + build, err = buildPrototype.Create() + Expect(err).ToNot(HaveOccurred()) + + buildRun, err = NewBuildRunPrototype(). + Name(testID). + ForBuild(build). + GenerateServiceAccount(). + Create() + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromBundleSource(buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + + It("should prune the source image after pulling it", func() { + var secretName = os.Getenv(EnvVarImageRepoSecret) + var registryName string + var auth authn.Authenticator + var tmpImage = fmt.Sprintf("%s/source-%s:%s", + os.Getenv(EnvVarImageRepo), + testID, + "latest", + ) + + By("looking up the registry name", func() { + ref, err := name.ParseReference(outputImage) + Expect(err).ToNot(HaveOccurred()) + + registryName = ref.Context().RegistryStr() + }) + + By("setting up the respective authenticator", func() { + switch { + case secretName != "": + secret, err := testBuild.Clientset. + CoreV1(). + Secrets(testBuild.Namespace). + Get(testBuild.Context, secretName, v1.GetOptions{}) + Expect(err).ToNot(HaveOccurred()) + + dockerConfigJSON, ok := secret.Data[".dockerconfigjson"] + Expect(ok).To(BeTrue()) + + configFile, err := config.LoadFromReader(bytes.NewReader(dockerConfigJSON)) + Expect(err).ToNot(HaveOccurred()) + + authConfig, err := configFile.GetAuthConfig(registryName) + Expect(err).ToNot(HaveOccurred()) + + auth = authn.FromConfig(authn.AuthConfig{ + Username: authConfig.Username, + Password: authConfig.Password, + Auth: authConfig.Auth, + IdentityToken: authConfig.IdentityToken, + RegistryToken: authConfig.RegistryToken, + }) + + default: + auth = authn.Anonymous + } + }) + + By("creating a temporary new input image based on the default input image", func() { + src, err := name.ParseReference(inputImage) + Expect(err).ToNot(HaveOccurred()) + + // Special case for a local registry in the cluster: + // Since the test client is not running in the cluster, it relies on being able to + // reach the same registry via a local port. Therefore, the image name needs to be + // different for the image copy preparation step. + var dstImage = tmpImage + if strings.Contains(dstImage, "cluster.local") { + dstImage = strings.ReplaceAll( + dstImage, + "registry.registry.svc.cluster.local", + "localhost", + ) + } + + dst, err := name.ParseReference(dstImage) + Expect(err).ToNot(HaveOccurred()) + + srcDesc, err := remote.Get(src) + Expect(err).ToNot(HaveOccurred()) + + image, err := srcDesc.Image() + Expect(err).ToNot(HaveOccurred()) + + Expect(remote.Write( + dst, + image, + remote.WithContext(testBuild.Context), + remote.WithAuth(auth), + )).ToNot(HaveOccurred()) + }) + + By("eventually running the actual build with prune option", func() { + build, err = NewBuildPrototype(). + ClusterBuildStrategy("kaniko"). + Name(testID). + Namespace(testBuild.Namespace). + SourceBundle(tmpImage). + SourceBundlePrune(buildv1beta1.PruneAfterPull). + SourceCredentials(secretName). + SourceContextDir("docker-build"). + Dockerfile("Dockerfile"). + OutputImage(outputImage). + OutputImageCredentials(secretName). + OutputImageInsecure(insecure). + Create() + Expect(err).ToNot(HaveOccurred()) + + buildRun, err = NewBuildRunPrototype(). + Name(testID). + ForBuild(build). + GenerateServiceAccount(). + Create() + Expect(err).ToNot(HaveOccurred()) + validateBuildRunToSucceed(testBuild, buildRun) + }) + + By("checking the temporary input image was removed", func() { + tmp, err := name.ParseReference(tmpImage) + Expect(err).ToNot(HaveOccurred()) + + _, err = remote.Head(tmp, remote.WithContext(testBuild.Context), remote.WithAuth(auth)) + Expect(err).To(HaveOccurred()) + }) + }) + }) +}) diff --git a/test/e2e/v1beta1/e2e_one_off_builds_test.go b/test/e2e/v1beta1/e2e_one_off_builds_test.go new file mode 100644 index 0000000000..fc85ca21c8 --- /dev/null +++ b/test/e2e/v1beta1/e2e_one_off_builds_test.go @@ -0,0 +1,123 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + "fmt" + "os" + "strconv" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + "github.com/google/go-containerregistry/pkg/name" + buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +var _ = Describe("Using One-Off Builds", func() { + + insecure := false + value, found := os.LookupEnv(EnvVarImageRepoInsecure) + if found { + var err error + insecure, err = strconv.ParseBool(value) + Expect(err).ToNot(HaveOccurred()) + } + + var ( + testID string + err error + + buildRun *buildv1beta1.BuildRun + ) + + AfterEach(func() { + if CurrentSpecReport().Failed() { + printTestFailureDebugInfo(testBuild, testBuild.Namespace, testID) + + } else if buildRun != nil { + validateServiceAccountDeletion(buildRun, testBuild.Namespace) + } + + if buildRun != nil { + testBuild.DeleteBR(buildRun.Name) + buildRun = nil + } + }) + + Context("Embed BuildSpec in BuildRun", func() { + var outputImage name.Reference + + BeforeEach(func() { + testID = generateTestID("onoff") + + outputImage, err = name.ParseReference(fmt.Sprintf("%s/%s:%s", + os.Getenv(EnvVarImageRepo), + testID, + "latest", + )) + Expect(err).ToNot(HaveOccurred()) + }) + + It("should build an image using Buildpacks and a Git source", func() { + buildRun, err = NewBuildRunPrototype(). + Namespace(testBuild.Namespace). + Name(testID). + WithBuildSpec(NewBuildPrototype(). + ClusterBuildStrategy("buildpacks-v3"). + Namespace(testBuild.Namespace). + Name(testID). + SourceGit("https://github.com/shipwright-io/sample-go.git"). + SourceContextDir("source-build"). + OutputImage(outputImage.String()). + OutputImageCredentials(os.Getenv(EnvVarImageRepoSecret)). + OutputImageInsecure(insecure). + BuildSpec()). + Create() + Expect(err).ToNot(HaveOccurred()) + validateBuildRunToSucceed(testBuild, buildRun) + }) + + It("should build an image using Buildah and a Git source", func() { + buildRun, err = NewBuildRunPrototype(). + Namespace(testBuild.Namespace). + Name(testID). + WithBuildSpec(NewBuildPrototype(). + ClusterBuildStrategy("buildah-shipwright-managed-push"). + Namespace(testBuild.Namespace). + Name(testID). + SourceGit("https://github.com/shipwright-io/sample-go.git"). + SourceContextDir("docker-build"). + Dockerfile("Dockerfile"). + ArrayParamValue("registries-insecure", outputImage.Context().RegistryStr()). + OutputImage(outputImage.String()). + OutputImageCredentials(os.Getenv(EnvVarImageRepoSecret)). + OutputImageInsecure(insecure). + BuildSpec()). + Create() + Expect(err).ToNot(HaveOccurred()) + validateBuildRunToSucceed(testBuild, buildRun) + }) + + It("should build an image using Buildpacks and a ociArtifact source", func() { + buildRun, err = NewBuildRunPrototype(). + Namespace(testBuild.Namespace). + Name(testID). + WithBuildSpec(NewBuildPrototype(). + ClusterBuildStrategy("buildpacks-v3"). + Namespace(testBuild.Namespace). + Name(testID). + SourceBundle("ghcr.io/shipwright-io/sample-go/source-bundle:latest"). + SourceContextDir("source-build"). + OutputImage(outputImage.String()). + OutputImageCredentials(os.Getenv(EnvVarImageRepoSecret)). + OutputImageInsecure(insecure). + BuildSpec()). + Create() + Expect(err).ToNot(HaveOccurred()) + validateBuildRunToSucceed(testBuild, buildRun) + }) + }) +}) diff --git a/test/e2e/v1beta1/e2e_params_test.go b/test/e2e/v1beta1/e2e_params_test.go new file mode 100644 index 0000000000..9f018e9450 --- /dev/null +++ b/test/e2e/v1beta1/e2e_params_test.go @@ -0,0 +1,138 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1" + test "github.com/shipwright-io/build/test/v1beta1_samples" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" +) + +var _ = Describe("For a Kubernetes cluster with Tekton and build installed", func() { + var ( + testID string + err error + + build *buildv1beta1.Build + buildRun *buildv1beta1.BuildRun + buildStrategy *buildv1beta1.BuildStrategy + configMap *corev1.ConfigMap + secret *corev1.Secret + ) + + AfterEach(func() { + if CurrentSpecReport().Failed() { + printTestFailureDebugInfo(testBuild, testBuild.Namespace, testID) + } else if buildRun != nil { + validateServiceAccountDeletion(buildRun, testBuild.Namespace) + } + + if buildRun != nil { + testBuild.DeleteBR(buildRun.Name) + buildRun = nil + } + + if build != nil { + testBuild.DeleteBuild(build.Name) + build = nil + } + + if buildStrategy != nil { + testBuild.DeleteBuildStrategy(buildStrategy.Name) + buildStrategy = nil + } + + if configMap != nil { + testBuild.DeleteConfigMap(configMap.Name) + configMap = nil + } + + if secret != nil { + testBuild.DeleteSecret(secret.Name) + secret = nil + } + }) + + Context("when using a cluster build strategy is used that uses a lot parameters", func() { + BeforeEach(func() { + buildStrategy, err = testBuild.Catalog.LoadBuildStrategyFromBytes([]byte(test.BuildStrategyWithParameterVerification)) + Expect(err).ToNot(HaveOccurred()) + err = testBuild.CreateBuildStrategy(buildStrategy) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("when a secret and a configmap are in place with suitable values", func() { + BeforeEach(func() { + // prepare a ConfigMap + configMap = testBuild.Catalog.ConfigMapWithData("a-configmap", testBuild.Namespace, map[string]string{ + "number1": "1", + "shell": "/bin/bash", + }) + err = testBuild.CreateConfigMap(configMap) + Expect(err).ToNot(HaveOccurred()) + + // prepare a secret + secret = testBuild.Catalog.SecretWithStringData("a-secret", testBuild.Namespace, map[string]string{ + "number2": "2", + "number3": "3", + }) + err = testBuild.CreateSecret(secret) + Expect(err).ToNot(HaveOccurred()) + }) + + Context("when a Build is in place that sets some of the parameters", func() { + BeforeEach(func() { + testID = generateTestID("params") + + build, err = NewBuildPrototype(). + BuildStrategy(buildStrategy.Name). + Name(testID). + Namespace(testBuild.Namespace). + // The source is not actually used by the build, so just take a small one + SourceGit("https://github.com/shipwright-io/sample-go.git"). + // There is not actually an image pushed + OutputImage("dummy"). + // The parameters + StringParamValue("env1", "13"). + StringParamValueFromConfigMap("env2", "a-configmap", "number1", ptr.To[string]("2${CONFIGMAP_VALUE}")). + ArrayParamValueFromConfigMap("commands", "a-configmap", "shell", nil). + ArrayParamValue("commands", "-c"). + Create() + Expect(err).ToNot(HaveOccurred()) + }) + + It("correctly runs a BuildRun that passes the remaining parameters", func() { + buildRun, err = NewBuildRunPrototype(). + ForBuild(build). + Name(testID). + GenerateServiceAccount(). + StringParamValue("image", "registry.access.redhat.com/ubi9/ubi-minimal"). + StringParamValueFromSecret("env3", "a-secret", "number2", nil). + ArrayParamValueFromSecret("args", "a-secret", "number3", ptr.To[string]("${SECRET_VALUE}9")). + ArrayParamValue("args", "47"). + Create() + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + + // we verify the image digest here which is mis-used by the strategy to store a calculated sum + // 13 (env1) + 21 (env2 = 2${a-configmap:number1}) + 2 (env3 = ${a-secret:number2}) + 39 (args[0] = ${a-secret:number3}9) + 47 (args[1]) = 122 + buildRun, err = testBuild.LookupBuildRun(types.NamespacedName{ + Namespace: buildRun.Namespace, + Name: buildRun.Name, + }) + Expect(err).ToNot(HaveOccurred()) + Expect(buildRun.Status.Output).NotTo(BeNil()) + Expect(buildRun.Status.Output.Size).To(BeEquivalentTo(122)) + }) + }) + }) + }) +}) diff --git a/test/e2e/v1beta1/e2e_rbac_test.go b/test/e2e/v1beta1/e2e_rbac_test.go new file mode 100644 index 0000000000..6fbd6a89db --- /dev/null +++ b/test/e2e/v1beta1/e2e_rbac_test.go @@ -0,0 +1,75 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + "context" + + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +var _ = Describe("User RBAC for Shipwright", func() { + + var ctx context.Context + + BeforeEach(func() { + ctx = context.Background() + }) + + It("should install an aggregated edit role for developers", func() { + editRole, err := testBuild.Clientset.RbacV1().ClusterRoles().Get(ctx, "shipwright-build-aggregate-edit", metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + expectedAggregates := []string{ + "rbac.authorization.k8s.io/aggregate-to-edit", + "rbac.authorization.k8s.io/aggregate-to-admin", + } + for _, aggregate := range expectedAggregates { + aggregateValue, exists := editRole.Labels[aggregate] + Expect(exists).To(BeTrue()) + Expect(aggregateValue).To(Equal("true")) + } + // We should have at least two rules - one for ClusterBuildStrategy, another for all else + // More than two rules is acceptable. + Expect(len(editRole.Rules)).To(BeNumerically(">=", 2)) + for _, rule := range editRole.Rules { + Expect(rule.APIGroups).To(ContainElement("shipwright.io")) + for _, resource := range rule.Resources { + if resource == "clusterbuildstrategies" { + Expect(rule.Verbs).To(ContainElements("get", "list", "watch")) + Expect(rule.Verbs).NotTo(ContainElement("create")) + Expect(rule.Verbs).NotTo(ContainElement("update")) + Expect(rule.Verbs).NotTo(ContainElement("patch")) + Expect(rule.Verbs).NotTo(ContainElement("delete")) + } else { + Expect(rule.Verbs).To(ContainElements("get", "list", "watch", "create", "update", "patch", "delete")) + } + } + } + }) + + It("should install an aggregated view role for all users", func() { + viewRole, err := testBuild.Clientset.RbacV1().ClusterRoles().Get(ctx, "shipwright-build-aggregate-view", metav1.GetOptions{}) + Expect(err).NotTo(HaveOccurred()) + + aggregateValue, exists := viewRole.Labels["rbac.authorization.k8s.io/aggregate-to-view"] + Expect(exists).To(BeTrue()) + Expect(aggregateValue).To(Equal("true")) + // We should have at least one rule, as this applies "view" permissions to all Shipwright Build objects + // More rules are acceptable for future fine-grained controls. + Expect(len(viewRole.Rules)).To(BeNumerically(">=", 1)) + for _, rule := range viewRole.Rules { + Expect(rule.APIGroups).To(ContainElement("shipwright.io")) + Expect(rule.Verbs).To(ContainElements("get", "list", "watch")) + Expect(rule.Verbs).NotTo(ContainElement("create")) + Expect(rule.Verbs).NotTo(ContainElement("update")) + Expect(rule.Verbs).NotTo(ContainElement("patch")) + Expect(rule.Verbs).NotTo(ContainElement("delete")) + } + }) + +}) diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/v1beta1/e2e_suite_test.go similarity index 94% rename from test/e2e/e2e_suite_test.go rename to test/e2e/v1beta1/e2e_suite_test.go index ff8448cf6a..aeed2e27d6 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/v1beta1/e2e_suite_test.go @@ -10,8 +10,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - - "github.com/shipwright-io/build/test/utils" + utils "github.com/shipwright-io/build/test/utils/v1beta1" ) var ( diff --git a/test/e2e/v1beta1/e2e_test.go b/test/e2e/v1beta1/e2e_test.go new file mode 100644 index 0000000000..0ca8f59e26 --- /dev/null +++ b/test/e2e/v1beta1/e2e_test.go @@ -0,0 +1,685 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + "os" + + v1 "github.com/google/go-containerregistry/pkg/v1" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + + buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1" + shpgit "github.com/shipwright-io/build/pkg/git" +) + +var _ = Describe("For a Kubernetes cluster with Tekton and build installed", func() { + var ( + testID string + err error + + build *buildv1beta1.Build + buildRun *buildv1beta1.BuildRun + ) + + AfterEach(func() { + if CurrentSpecReport().Failed() { + printTestFailureDebugInfo(testBuild, testBuild.Namespace, testID) + + } else if buildRun != nil { + validateServiceAccountDeletion(buildRun, testBuild.Namespace) + } + + if buildRun != nil { + testBuild.DeleteBR(buildRun.Name) + buildRun = nil + } + + if build != nil { + testBuild.DeleteBuild(build.Name) + build = nil + } + }) + + Context("when a Buildah build is defined that is using shipwright-managed push", func() { + + BeforeEach(func() { + testID = generateTestID("buildah") + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_buildah_shipwright_managed_push_cr.yaml", + ) + }) + + It("successfully runs a build and surface results to BuildRun", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_buildah_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + appendRegistryInsecureParamValue(build, buildRun) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromGitSource(buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Buildah build is defined that is using strategy-managed push", func() { + + BeforeEach(func() { + testID = generateTestID("buildah") + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_buildah_strategy_managed_push_cr.yaml", + ) + }) + + It("successfully runs a build and surface results to BuildRun", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_buildah_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + appendRegistryInsecureParamValue(build, buildRun) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromGitSource(buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Buildah build with a contextDir and a custom Dockerfile name is defined", func() { + + BeforeEach(func() { + testID = generateTestID("buildah-custom-context-dockerfile") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_buildah_cr_custom_context+dockerfile.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1beta1/buildrun_buildah_cr_custom_context+dockerfile.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + appendRegistryInsecureParamValue(build, buildRun) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a heroku Buildpacks build is defined using a cluster strategy", func() { + + BeforeEach(func() { + testID = generateTestID("buildpacks-v3-heroku") + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_buildpacks-v3-heroku_cr.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_buildpacks-v3-heroku_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a heroku Buildpacks build is defined using a namespaced strategy", func() { + var buildStrategy *buildv1beta1.BuildStrategy + + BeforeEach(func() { + testID = generateTestID("buildpacks-v3-heroku-namespaced") + + buildStrategy, err = buildStrategyTestData(testBuild.Namespace, "samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3-heroku_namespaced_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + err = testBuild.CreateBuildStrategy(buildStrategy) + Expect(err).ToNot(HaveOccurred()) + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_buildpacks-v3-heroku_namespaced_cr.yaml", + ) + }) + + It("successfully runs a build and surface results to BuildRun", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_buildpacks-v3-heroku_namespaced_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromGitSource(buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + + AfterEach(func() { + err = testBuild.DeleteBuildStrategy(buildStrategy.Name) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when a Buildpacks v3 build is defined using a cluster strategy", func() { + + BeforeEach(func() { + testID = generateTestID("buildpacks-v3") + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_buildpacks-v3_cr.yaml", + ) + }) + + It("successfully runs a build and surface results to BuildRun", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_buildpacks-v3_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromGitSource(buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Buildpacks v3 build is defined using a namespaced strategy", func() { + var buildStrategy *buildv1beta1.BuildStrategy + + BeforeEach(func() { + testID = generateTestID("buildpacks-v3-namespaced") + + buildStrategy, err = buildStrategyTestData(testBuild.Namespace, "samples/v1beta1/buildstrategy/buildpacks-v3/buildstrategy_buildpacks-v3_namespaced_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + err = testBuild.CreateBuildStrategy(buildStrategy) + Expect(err).ToNot(HaveOccurred()) + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_buildpacks-v3_namespaced_cr.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_buildpacks-v3_namespaced_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + + AfterEach(func() { + err = testBuild.DeleteBuildStrategy(buildStrategy.Name) + Expect(err).ToNot(HaveOccurred()) + }) + }) + + Context("when a Buildpacks v3 build is defined for a php runtime", func() { + + BeforeEach(func() { + testID = generateTestID("buildpacks-v3-php") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_buildpacks-v3_php_cr.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1beta1/buildrun_buildpacks-v3_php_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Buildpacks v3 build is defined for a ruby runtime", func() { + + BeforeEach(func() { + testID = generateTestID("buildpacks-v3-ruby") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_buildpacks-v3_ruby_cr.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1beta1/buildrun_buildpacks-v3_ruby_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Buildpacks v3 build is defined for a golang runtime", func() { + + BeforeEach(func() { + testID = generateTestID("buildpacks-v3-golang") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_buildpacks-v3_golang_cr.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1beta1/buildrun_buildpacks-v3_golang_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Buildpacks v3 build is defined for a golang runtime with `BP_GO_TARGETS` env", func() { + BeforeEach(func() { + testID = generateTestID("buildpacks-v3-golang") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_buildpacks-v3_golang_cr_env.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1beta1/buildrun_buildpacks-v3_golang_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a build uses the build-run-deletion annotation", func() { + + BeforeEach(func() { + testID = generateTestID("buildpacks-v3-golang") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_buildpacks-v3_golang_delete_cr.yaml", + ) + }) + + It("successfully deletes the BuildRun after the Build is deleted", func() { + By("running a build and expecting it to succeed") + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1beta1/buildrun_buildpacks-v3_golang_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + + By("deleting the parent Build object") + err = testBuild.DeleteBuild(build.Name) + Expect(err).NotTo(HaveOccurred(), "error deleting the parent Build") + Eventually(func() bool { + _, err = testBuild.GetBR(buildRun.Name) + if err == nil { + return false + } + if !errors.IsNotFound(err) { + return false + } + return true + }).Should(BeTrue()) + }) + }) + + Context("when a Buildpacks v3 build is defined for a java runtime", func() { + + BeforeEach(func() { + testID = generateTestID("buildpacks-v3-java") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_buildpacks-v3_java_cr.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1beta1/buildrun_buildpacks-v3_java_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Kaniko build is defined to use public GitHub", func() { + + BeforeEach(func() { + testID = generateTestID("kaniko") + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_kaniko_cr.yaml", + ) + }) + + It("successfully runs a build and surface results to BuildRun", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_kaniko_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromGitSource(buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Kaniko build with a Dockerfile that requires advanced permissions is defined", func() { + + BeforeEach(func() { + testID = generateTestID("kaniko-advanced-dockerfile") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_kaniko_cr_advanced_dockerfile.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1beta1/buildrun_kaniko_cr_advanced_dockerfile.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Kaniko build with a contextDir and a custom Dockerfile name is defined", func() { + + BeforeEach(func() { + testID = generateTestID("kaniko-custom-context-dockerfile") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_kaniko_cr_custom_context+dockerfile.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "test/data/v1beta1/buildrun_kaniko_cr_custom_context+dockerfile.yaml") + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Kaniko+Trivy build is defined to use an image with no critical CVEs", func() { + + BeforeEach(func() { + testID = generateTestID("kaniko-trivy-good") + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_kaniko-trivy-good_cr.yaml", + ) + }) + + It("successfully runs a build and surface results to BuildRun", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_kaniko-trivy-good_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromGitSource(buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Kaniko+Trivy build is defined to use an image with a critical CVE", func() { + + BeforeEach(func() { + testID = generateTestID("kaniko-trivy-bad") + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_kaniko-trivy-bad_cr.yaml", + ) + }) + + It("fails to run a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_kaniko-trivy-bad_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + validateBuildRunToFail(testBuild, buildRun) + }) + }) + + Context("when a Buildkit build with a contextDir and a path to a Dockerfile is defined", func() { + + BeforeEach(func() { + testID = generateTestID("buildkit-custom-context") + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_buildkit_cr.yaml", + ) + }) + + It("successfully runs a build and surface results to BuildRun", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_buildkit_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromGitSource(buildRun) + testBuild.ValidateImagePlatformsExist(buildRun, []v1.Platform{ + { + Architecture: "amd64", + OS: "linux", + }, + { + Architecture: "arm64", + OS: "linux", + }, + }) + }) + }) + + Context("when a s2i build is defined", func() { + + BeforeEach(func() { + testID = generateTestID("s2i") + + // create the build definition + build = createBuild( + testBuild, + testID, + "samples/v1beta1/build/build_source-to-image_cr.yaml", + ) + }) + + It("successfully runs a build and surface results to BuildRun", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_source-to-image_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + validateBuildRunResultsFromGitSource(buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a private source repository is used", func() { + + BeforeEach(func() { + if os.Getenv(EnvVarEnablePrivateRepos) != "true" { + Skip("Skipping test cases that use a private source repository") + } + }) + + Context("when a Buildah build is defined to use a private GitHub repository", func() { + + BeforeEach(func() { + testID = generateTestID("private-github-buildah") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_buildah_cr_private_github.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_buildah_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Buildah build is defined to use a private GitLab repository", func() { + + BeforeEach(func() { + testID = generateTestID("private-gitlab-buildah") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_buildah_cr_private_gitlab.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_buildah_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Kaniko build is defined to use a private GitHub repository", func() { + + BeforeEach(func() { + testID = generateTestID("private-github-kaniko") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_kaniko_cr_private_github.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_kaniko_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a Kaniko build is defined to use a private GitLab repository", func() { + + BeforeEach(func() { + testID = generateTestID("private-gitlab-kaniko") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_kaniko_cr_private_gitlab.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_kaniko_cr.yaml") + Expect(err).ToNot(HaveOccurred()) + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + + Context("when a s2i build is defined to use a private GitHub repository", func() { + + BeforeEach(func() { + testID = generateTestID("private-github-s2i") + + // create the build definition + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_source-to-image_cr_private_github.yaml", + ) + }) + + It("successfully runs a build", func() { + buildRun, err = buildRunTestData(testBuild.Namespace, testID, "samples/v1beta1/buildrun/buildrun_source-to-image_cr.yaml") + Expect(err).ToNot(HaveOccurred(), "Error retrieving buildrun test data") + + buildRun = validateBuildRunToSucceed(testBuild, buildRun) + testBuild.ValidateImageDigest(buildRun) + }) + }) + }) + + Context("when a s2i build uses a non-existent git repository as source", func() { + It("fails because of prompted authentication which surfaces the to the BuildRun", func() { + testID = generateTestID("s2i-failing") + + build = createBuild( + testBuild, + testID, + "test/data/v1beta1/build_non_existing_repo.yaml", + ) + + buildRun, err = buildRunTestData(build.Namespace, testID, "test/data/v1beta1/buildrun_non_existing_repo.yaml") + Expect(err).ToNot(HaveOccurred()) + + validateBuildRunToFail(testBuild, buildRun) + buildRun, err = testBuild.LookupBuildRun(types.NamespacedName{Name: buildRun.Name, Namespace: testBuild.Namespace}) + + Expect(buildRun.Status.FailureDetails.Message).To(Equal(shpgit.AuthPrompted.ToMessage())) + Expect(buildRun.Status.FailureDetails.Reason).To(Equal(shpgit.AuthPrompted.String())) + }) + }) + +}) diff --git a/test/e2e/v1beta1/validators_test.go b/test/e2e/v1beta1/validators_test.go new file mode 100644 index 0000000000..34cc8e99d4 --- /dev/null +++ b/test/e2e/v1beta1/validators_test.go @@ -0,0 +1,371 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package e2e_test + +import ( + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + "time" + + . "github.com/onsi/gomega" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/kubectl/pkg/scheme" + + "github.com/shipwright-io/build/pkg/apis" + buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1" + utils "github.com/shipwright-io/build/test/utils/v1beta1" +) + +const ( + EnvVarServiceAccountName = "TEST_E2E_SERVICEACCOUNT_NAME" + EnvVarVerifyTektonObjects = "TEST_E2E_VERIFY_TEKTONOBJECTS" + EnvVarTimeoutMultiplier = "TEST_E2E_TIMEOUT_MULTIPLIER" + EnvVarImageRepo = "TEST_IMAGE_REPO" + EnvVarImageRepoInsecure = "TEST_IMAGE_REPO_INSECURE" + EnvVarEnablePrivateRepos = "TEST_PRIVATE_REPO" + EnvVarImageRepoSecret = "TEST_IMAGE_REPO_SECRET" + EnvVarSourceRepoSecretJSON = "TEST_IMAGE_REPO_DOCKERCONFIGJSON" + EnvVarSourceURLGithub = "TEST_PRIVATE_GITHUB" + EnvVarSourceURLGitlab = "TEST_PRIVATE_GITLAB" + EnvVarSourceURLSecret = "TEST_SOURCE_SECRET" +) + +// createPipelineServiceAccount reads the TEST_E2E_SERVICEACCOUNT_NAME environment variable. If the value is "generated", then nothing is done. +// Otherwise it will create the service account. No error occurs if the service account already exists. +func createPipelineServiceAccount(testBuild *utils.TestBuild) { + serviceAccountName, ok := os.LookupEnv(EnvVarServiceAccountName) + Expect(ok).To(BeTrue(), "environment variable "+EnvVarServiceAccountName+" is not set") + Expect(serviceAccountName).ToNot(BeEmpty()) + + if serviceAccountName == "generated" { + Logf("Skipping creation of service account, generated one will be used per build run.") + return + } + + if _, err := testBuild.LookupServiceAccount(types.NamespacedName{Namespace: testBuild.Namespace, Name: serviceAccountName}); err == nil { + Logf("Skipping creation of service account, reusing existing one.") + return + } + + Logf("Creating '%s' service-account", serviceAccountName) + _, err := testBuild.Clientset.CoreV1(). + ServiceAccounts(testBuild.Namespace). + Create(testBuild.Context, + &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testBuild.Namespace, + Name: serviceAccountName, + }}, + metav1.CreateOptions{}) + + // Due to concurrency, it could be that some other routine already finished creating the service-account + if err != nil && apierrors.IsAlreadyExists(err) { + Logf("Creation failed, because service-account %q is already in the system.", serviceAccountName) + return + } + + Expect(err).ToNot(HaveOccurred(), "Error creating service account") +} + +// createContainerRegistrySecret use environment variables to check for container registry +// credentials secret, when not found a new secret is created. +func createContainerRegistrySecret(testBuild *utils.TestBuild) { + secretName := os.Getenv(EnvVarImageRepoSecret) + secretPayload := os.Getenv(EnvVarSourceRepoSecretJSON) + if secretName == "" || secretPayload == "" { + Logf("Container registry secret won't be created.") + return + } + + _, err := testBuild.LookupSecret(types.NamespacedName{Namespace: testBuild.Namespace, Name: secretName}) + if err == nil { + Logf("Container registry secret is found at '%s/%s'", testBuild.Namespace, secretName) + return + } + + payload := []byte(secretPayload) + secret := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: testBuild.Namespace, + Name: secretName, + }, + Type: corev1.SecretTypeDockerConfigJson, + Data: map[string][]byte{ + ".dockerconfigjson": payload, + }, + } + + Logf("Creating container-registry secret '%s/%s' (%d bytes)", testBuild.Namespace, secretName, len(payload)) + err = testBuild.CreateSecret(secret) + Expect(err).ToNot(HaveOccurred(), "on creating container registry secret") +} + +// validateBuildRunToSucceed creates the build run and watches its flow until it succeeds. +func validateBuildRunToSucceed(testBuild *utils.TestBuild, testBuildRun *buildv1beta1.BuildRun) *buildv1beta1.BuildRun { + trueCondition := corev1.ConditionTrue + falseCondition := corev1.ConditionFalse + + // Ensure the BuildRun has been created + if _, err := testBuild.GetBR(testBuildRun.Name); err != nil { + Expect(testBuild.CreateBR(testBuildRun)). + ToNot(HaveOccurred(), "Failed to create BuildRun") + } + + // Ensure a BuildRun eventually moves to a succeeded TRUE status + nextStatusLog := time.Now().Add(60 * time.Second) + Eventually(func() corev1.ConditionStatus { + testBuildRun, err := testBuild.LookupBuildRun(types.NamespacedName{Name: testBuildRun.Name, Namespace: testBuild.Namespace}) + Expect(err).ToNot(HaveOccurred(), "Error retrieving a buildRun") + + if testBuildRun.Status.GetCondition(buildv1beta1.Succeeded) == nil { + return corev1.ConditionUnknown + } + + Expect(testBuildRun.Status.GetCondition(buildv1beta1.Succeeded).Status).ToNot(Equal(falseCondition), "BuildRun status doesn't move to Succeeded") + + now := time.Now() + if now.After(nextStatusLog) { + Logf("Still waiting for build run '%s' to succeed.", testBuildRun.Name) + nextStatusLog = time.Now().Add(60 * time.Second) + } + + return testBuildRun.Status.GetCondition(buildv1beta1.Succeeded).Status + + }, time.Duration(1100*getTimeoutMultiplier())*time.Second, 5*time.Second).Should(Equal(trueCondition), "BuildRun did not succeed") + + // Verify that the BuildSpec is still available in the status + testBuildRun, err := testBuild.GetBR(testBuildRun.Name) + Expect(err).ToNot(HaveOccurred()) + Expect(testBuildRun.Status.BuildSpec).ToNot(BeNil(), "BuildSpec is not available in the status") + + Logf("Test build '%s' is completed after %v !", testBuildRun.GetName(), testBuildRun.Status.CompletionTime.Time.Sub(testBuildRun.Status.StartTime.Time)) + + return testBuildRun +} + +func validateBuildRunResultsFromGitSource(testBuildRun *buildv1beta1.BuildRun) { + testBuildRun, err := testBuild.GetBR(testBuildRun.Name) + Expect(err).ToNot(HaveOccurred()) + + Expect(len(testBuildRun.Status.Sources)).To(Equal(1)) + + // Only run the TaskRun checks if Tekton objects can be accessed + if os.Getenv(EnvVarVerifyTektonObjects) == "true" { + tr, err := testBuild.GetTaskRunFromBuildRun(testBuildRun.Name) + Expect(err).ToNot(HaveOccurred()) + + for _, result := range tr.Status.TaskRunResults { + switch result.Name { + case "shp-source-default-commit-sha": + Expect(result.Value.StringVal).To(Equal(testBuildRun.Status.Sources[0].Git.CommitSha)) + case "shp-source-default-commit-author": + Expect(result.Value.StringVal).To(Equal(testBuildRun.Status.Sources[0].Git.CommitAuthor)) + case "shp-source-default-branch-name": + Expect(result.Value.StringVal).To(Equal(testBuildRun.Status.Sources[0].Git.BranchName)) + case "shp-image-digest": + Expect(result.Value.StringVal).To(Equal(testBuildRun.Status.Output.Digest)) + case "shp-image-size": + size, err := strconv.ParseInt(result.Value.StringVal, 10, 64) + Expect(err).To(BeNil()) + Expect(size).To(Equal(testBuildRun.Status.Output.Size)) + } + } + } +} + +func validateBuildRunResultsFromBundleSource(testBuildRun *buildv1beta1.BuildRun) { + testBuildRun, err := testBuild.GetBR(testBuildRun.Name) + Expect(err).ToNot(HaveOccurred()) + + Expect(len(testBuildRun.Status.Sources)).To(Equal(1)) + + // Only run the TaskRun checks if Tekton objects can be accessed + if os.Getenv(EnvVarVerifyTektonObjects) == "true" { + tr, err := testBuild.GetTaskRunFromBuildRun(testBuildRun.Name) + Expect(err).ToNot(HaveOccurred()) + + for _, result := range tr.Status.TaskRunResults { + switch result.Name { + case "shp-source-default-image-digest": + Expect(result.Value.StringVal).To(Equal(testBuildRun.Status.Sources[0].OciArtifact.Digest)) + case "shp-image-digest": + Expect(result.Value.StringVal).To(Equal(testBuildRun.Status.Output.Digest)) + case "shp-image-size": + size, err := strconv.ParseInt(result.Value.StringVal, 10, 64) + Expect(err).To(BeNil()) + Expect(size).To(Equal(testBuildRun.Status.Output.Size)) + } + } + } +} + +// validateBuildRunToFail creates the build run and watches its flow until it fails. +func validateBuildRunToFail(testBuild *utils.TestBuild, testBuildRun *buildv1beta1.BuildRun) { + trueCondition := corev1.ConditionTrue + falseCondition := corev1.ConditionFalse + + // Ensure the BuildRun has been created + err := testBuild.CreateBR(testBuildRun) + Expect(err).ToNot(HaveOccurred(), "Failed to create BuildRun") + + // Ensure a BuildRun eventually moves to a succeeded FALSE status + nextStatusLog := time.Now().Add(60 * time.Second) + Eventually(func() corev1.ConditionStatus { + testBuildRun, err = testBuild.LookupBuildRun(types.NamespacedName{Name: testBuildRun.Name, Namespace: testBuild.Namespace}) + Expect(err).ToNot(HaveOccurred(), "Error retrieving a buildRun") + + if testBuildRun.Status.GetCondition(buildv1beta1.Succeeded) == nil { + return corev1.ConditionUnknown + } + + Expect(testBuildRun.Status.GetCondition(buildv1beta1.Succeeded).Status).NotTo(Equal(trueCondition), "BuildRun status moves to Succeeded") + + now := time.Now() + if now.After(nextStatusLog) { + Logf("Still waiting for build run '%s' to fail.", testBuildRun.Name) + nextStatusLog = time.Now().Add(60 * time.Second) + } + + return testBuildRun.Status.GetCondition(buildv1beta1.Succeeded).Status + + }, time.Duration(1100*getTimeoutMultiplier())*time.Second, 5*time.Second).Should(Equal(falseCondition), "BuildRun did not succeed") + + // Verify that the BuildSpec is still available in the status + Expect(testBuildRun.Status.BuildSpec).ToNot(BeNil(), "BuildSpec is not available in the status") + + Logf("Test build '%s' is completed after %v !", testBuildRun.GetName(), testBuildRun.Status.CompletionTime.Time.Sub(testBuildRun.Status.StartTime.Time)) +} + +// validateServiceAccountDeletion validates that a service account is correctly deleted after the end of +// a build run and depending on the state of the build run +func validateServiceAccountDeletion(buildRun *buildv1beta1.BuildRun, namespace string) { + buildRunCondition := buildRun.Status.GetCondition(buildv1beta1.Succeeded) + if buildRunCondition != nil { + if buildRunCondition.Status == "" || buildRunCondition.Status == corev1.ConditionUnknown { + Logf("Skipping validation of service account deletion because build run did not end.") + return + } + } + + if buildRun.Spec.ServiceAccount == nil { + Logf("Skipping validation of service account deletion because service account is not generated") + return + } + + saNamespacedName := types.NamespacedName{ + Name: buildRun.Name, + Namespace: namespace, + } + + Logf("Verifying that service account '%s' has been deleted.", saNamespacedName.Name) + _, err := testBuild.LookupServiceAccount(saNamespacedName) + Expect(err).To(HaveOccurred(), "Expected error to retrieve the generated service account after build run completion.") + Expect(apierrors.IsNotFound(err)).To(BeTrue(), "Expected service account to be deleted.") +} + +func readAndDecode(filePath string) (runtime.Object, error) { + decode := scheme.Codecs.UniversalDeserializer().Decode + if err := apis.AddToScheme(scheme.Scheme); err != nil { + return nil, err + } + + payload, err := os.ReadFile(filepath.Join("..", "..", "..", filePath)) + if err != nil { + return nil, err + } + + obj, _, err := decode(payload, nil, nil) + return obj, err +} + +// buildStrategyTestData gets the us the BuildStrategy test data set up +func buildStrategyTestData(ns string, buildStrategyCRPath string) (*buildv1beta1.BuildStrategy, error) { + obj, err := readAndDecode(buildStrategyCRPath) + if err != nil { + return nil, err + } + + buildStrategy := obj.(*buildv1beta1.BuildStrategy) + buildStrategy.SetNamespace(ns) + + return buildStrategy, err +} + +func buildTestData(namespace string, identifier string, filePath string) (*buildv1beta1.Build, error) { + obj, err := readAndDecode(filePath) + if err != nil { + return nil, err + } + + build, ok := obj.(*buildv1beta1.Build) + if !ok { + return nil, fmt.Errorf("failed to use the content of %s as a Build runtime object", filePath) + } + + build.SetNamespace(namespace) + build.SetName(identifier) + return build, nil +} + +// buildTestData gets the us the Build test data set up +func buildRunTestData(ns string, identifier string, filePath string) (*buildv1beta1.BuildRun, error) { + obj, err := readAndDecode(filePath) + if err != nil { + return nil, err + } + + buildRun, ok := obj.(*buildv1beta1.BuildRun) + if !ok { + return nil, fmt.Errorf("failed to use the content of %s as a BuildRun runtime object", filePath) + } + + buildRun.SetNamespace(ns) + buildRun.SetName(identifier) + buildRun.Spec.Build.Name = identifier + + serviceAccountName := os.Getenv(EnvVarServiceAccountName) + if serviceAccountName == "generated" { + generate := ".generate" + buildRun.Spec.ServiceAccount = &generate + } else { + buildRun.Spec.ServiceAccount = &serviceAccountName + } + + return buildRun, nil +} + +func appendRegistryInsecureParamValue(build *buildv1beta1.Build, buildRun *buildv1beta1.BuildRun) { + if strings.Contains(build.Spec.Output.Image, "cluster.local") { + parts := strings.Split(build.Spec.Output.Image, "/") + host := parts[0] + buildRun.Spec.ParamValues = append(buildRun.Spec.ParamValues, buildv1beta1.ParamValue{ + Name: "registries-insecure", + Values: []buildv1beta1.SingleValue{ + { + Value: &host, + }, + }, + }) + } +} + +func getTimeoutMultiplier() int64 { + value := os.Getenv(EnvVarTimeoutMultiplier) + if value == "" { + return 1 + } + + intValue, err := strconv.ParseInt(value, 10, 64) + Expect(err).ToNot(HaveOccurred(), "Failed to parse EnvVarTimeoutMultiplier to integer") + return intValue +} diff --git a/test/integration/build_to_buildruns_test.go b/test/integration/build_to_buildruns_test.go index 0748562ef4..ccae8c58a2 100644 --- a/test/integration/build_to_buildruns_test.go +++ b/test/integration/build_to_buildruns_test.go @@ -17,7 +17,7 @@ import ( "k8s.io/apimachinery/pkg/types" "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" ) var _ = Describe("Integration tests Build and BuildRuns", func() { diff --git a/test/integration/build_to_git_test.go b/test/integration/build_to_git_test.go index 745f4e207c..0dc6f3777c 100644 --- a/test/integration/build_to_git_test.go +++ b/test/integration/build_to_git_test.go @@ -8,9 +8,9 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" corev1 "k8s.io/api/core/v1" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" ) var _ = Describe("Integration tests Build and referenced Source url", func() { @@ -47,7 +47,7 @@ var _ = Describe("Integration tests Build and referenced Source url", func() { Expect(err).To(BeNil()) buildObject.ObjectMeta.Annotations["build.shipwright.io/verify.repository"] = "true" - buildObject.Spec.Source.URL = pointer.String("http://github.com/shipwright-io/sample-go") + buildObject.Spec.Source.URL = ptr.To[string]("http://github.com/shipwright-io/sample-go") Expect(tb.CreateBuild(buildObject)).To(BeNil()) @@ -72,7 +72,7 @@ var _ = Describe("Integration tests Build and referenced Source url", func() { ) Expect(err).To(BeNil()) - buildObject.Spec.Source.URL = pointer.String("http://github.com/shipwright-io/sample-go-fake") + buildObject.Spec.Source.URL = ptr.To[string]("http://github.com/shipwright-io/sample-go-fake") Expect(tb.CreateBuild(buildObject)).To(BeNil()) // wait until the Build finish the validation @@ -98,7 +98,7 @@ var _ = Describe("Integration tests Build and referenced Source url", func() { Expect(err).To(BeNil()) buildObject.ObjectMeta.Annotations["build.shipwright.io/verify.repository"] = "true" - buildObject.Spec.Source.URL = pointer.String("https://github.com/shipwright-io/sample-go") + buildObject.Spec.Source.URL = ptr.To[string]("https://github.com/shipwright-io/sample-go") Expect(tb.CreateBuild(buildObject)).To(BeNil()) @@ -123,7 +123,7 @@ var _ = Describe("Integration tests Build and referenced Source url", func() { ) Expect(err).To(BeNil()) - buildObject.Spec.Source.URL = pointer.String("https://github.com/shipwright-io/sample-go-fake") + buildObject.Spec.Source.URL = ptr.To[string]("https://github.com/shipwright-io/sample-go-fake") Expect(tb.CreateBuild(buildObject)).To(BeNil()) // wait until the Build finish the validation @@ -149,7 +149,7 @@ var _ = Describe("Integration tests Build and referenced Source url", func() { Expect(err).To(BeNil()) buildObject.ObjectMeta.Annotations["build.shipwright.io/verify.repository"] = "true" - buildObject.Spec.Source.URL = pointer.String("foobar") + buildObject.Spec.Source.URL = ptr.To[string]("foobar") Expect(tb.CreateBuild(buildObject)).To(BeNil()) @@ -176,7 +176,7 @@ var _ = Describe("Integration tests Build and referenced Source url", func() { Expect(err).To(BeNil()) buildObject.ObjectMeta.Annotations["build.shipwright.io/verify.repository"] = "false" - buildObject.Spec.Source.URL = pointer.String("foobar") + buildObject.Spec.Source.URL = ptr.To[string]("foobar") Expect(tb.CreateBuild(buildObject)).To(BeNil()) // wait until the Build finish the validation @@ -202,7 +202,7 @@ var _ = Describe("Integration tests Build and referenced Source url", func() { Expect(err).To(BeNil()) buildObject.ObjectMeta.Annotations["build.shipwright.io/verify.repository"] = "true" - buildObject.Spec.Source.URL = pointer.String("https://github.yourco.com/org/build-fake") + buildObject.Spec.Source.URL = ptr.To[string]("https://github.yourco.com/org/build-fake") Expect(tb.CreateBuild(buildObject)).To(BeNil()) @@ -228,7 +228,7 @@ var _ = Describe("Integration tests Build and referenced Source url", func() { Expect(err).To(BeNil()) buildObject.ObjectMeta.Annotations["build.shipwright.io/verify.repository"] = "true" - buildObject.Spec.Source.URL = pointer.String("https://github.yourco.com/org/build-fake") + buildObject.Spec.Source.URL = ptr.To[string]("https://github.yourco.com/org/build-fake") buildObject.Spec.Source.Credentials = &corev1.LocalObjectReference{Name: "foobar"} sampleSecret := tb.Catalog.SecretWithAnnotation(buildObject.Spec.Source.Credentials.Name, buildObject.Namespace) @@ -260,7 +260,7 @@ var _ = Describe("Integration tests Build and referenced Source url", func() { Expect(err).To(BeNil()) buildObject.ObjectMeta.Annotations["build.shipwright.io/verify.repository"] = "true" - buildObject.Spec.Source.URL = pointer.String("git@github.com:shipwright-io/build-fake.git") + buildObject.Spec.Source.URL = ptr.To[string]("git@github.com:shipwright-io/build-fake.git") Expect(tb.CreateBuild(buildObject)).To(BeNil()) @@ -288,7 +288,7 @@ var _ = Describe("Integration tests Build and referenced Source url", func() { Expect(err).To(BeNil()) buildObject.ObjectMeta.Annotations["build.shipwright.io/verify.repository"] = "true" - buildObject.Spec.Source.URL = pointer.String("ssh://github.com/shipwright-io/build-fake.git") + buildObject.Spec.Source.URL = ptr.To[string]("ssh://github.com/shipwright-io/build-fake.git") Expect(tb.CreateBuild(buildObject)).To(BeNil()) diff --git a/test/integration/build_to_secrets_test.go b/test/integration/build_to_secrets_test.go index 2fa6cb5429..dcb476ecaf 100644 --- a/test/integration/build_to_secrets_test.go +++ b/test/integration/build_to_secrets_test.go @@ -10,7 +10,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" corev1 "k8s.io/api/core/v1" ) diff --git a/test/integration/build_to_taskruns_test.go b/test/integration/build_to_taskruns_test.go index a6469fd5d7..6766cfcd3b 100644 --- a/test/integration/build_to_taskruns_test.go +++ b/test/integration/build_to_taskruns_test.go @@ -10,8 +10,8 @@ import ( corev1 "k8s.io/api/core/v1" "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test" - "github.com/shipwright-io/build/test/utils" + utils "github.com/shipwright-io/build/test/utils/v1alpha1" + test "github.com/shipwright-io/build/test/v1alpha1_samples" ) var _ = Describe("Integration tests Build and TaskRun", func() { diff --git a/test/integration/buildrun_cleanup_test.go b/test/integration/buildrun_cleanup_test.go index 51c587ad6d..f5ba42d993 100644 --- a/test/integration/buildrun_cleanup_test.go +++ b/test/integration/buildrun_cleanup_test.go @@ -9,7 +9,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" ) diff --git a/test/integration/buildruns_to_sa_test.go b/test/integration/buildruns_to_sa_test.go index c7d09d9bf1..85e998bb03 100644 --- a/test/integration/buildruns_to_sa_test.go +++ b/test/integration/buildruns_to_sa_test.go @@ -15,7 +15,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" ) var _ = Describe("Integration tests BuildRuns and Service-accounts", func() { diff --git a/test/integration/buildruns_to_taskruns_test.go b/test/integration/buildruns_to_taskruns_test.go index 9e3a32400b..5c80107f8e 100644 --- a/test/integration/buildruns_to_taskruns_test.go +++ b/test/integration/buildruns_to_taskruns_test.go @@ -16,7 +16,7 @@ import ( "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" "github.com/shipwright-io/build/pkg/reconciler/buildrun/resources" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" diff --git a/test/integration/buildstrategy_to_taskruns_test.go b/test/integration/buildstrategy_to_taskruns_test.go index 1da1daf14f..162bf1d4a4 100644 --- a/test/integration/buildstrategy_to_taskruns_test.go +++ b/test/integration/buildstrategy_to_taskruns_test.go @@ -11,8 +11,8 @@ import ( . "github.com/onsi/gomega" "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test" - "github.com/shipwright-io/build/test/utils" + utils "github.com/shipwright-io/build/test/utils/v1alpha1" + test "github.com/shipwright-io/build/test/v1alpha1_samples" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" corev1 "k8s.io/api/core/v1" ) diff --git a/test/integration/clusterbuildstrategy_to_taskruns_test.go b/test/integration/clusterbuildstrategy_to_taskruns_test.go index 1f1d53bda6..1fce846285 100644 --- a/test/integration/clusterbuildstrategy_to_taskruns_test.go +++ b/test/integration/clusterbuildstrategy_to_taskruns_test.go @@ -9,7 +9,7 @@ import ( . "github.com/onsi/gomega" "github.com/shipwright-io/build/pkg/apis/build/v1alpha1" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1alpha1_samples" ) var _ = Describe("Integration tests ClusterBuildStrategies and TaskRuns", func() { @@ -55,13 +55,13 @@ var _ = Describe("Integration tests ClusterBuildStrategies and TaskRuns", func() } }) - Context("when a buildrun is created", func() { + Context("when a buildrun is created", func() { BeforeEach(func() { buildSample = []byte(test.BuildCBSMinimal) buildRunSample = []byte(test.MinimalBuildRun) }) - It("should create a taskrun with the correct annotations", func() { + It("should create a taskrun with the correct annotations", func() { Expect(tb.CreateBuild(buildObject)).To(BeNil()) buildObject, err = tb.GetBuildTillValidation(buildObject.Name) diff --git a/test/integration/integration_suite_test.go b/test/integration/integration_suite_test.go index 5a21bc314f..75ae2bc70f 100644 --- a/test/integration/integration_suite_test.go +++ b/test/integration/integration_suite_test.go @@ -12,7 +12,8 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" - "github.com/shipwright-io/build/test/utils" + // utils "github.com/shipwright-io/build/test/utils" + utils "github.com/shipwright-io/build/test/utils/v1alpha1" ) const ( diff --git a/test/utils/buildruns.go b/test/utils/v1alpha1/buildruns.go similarity index 100% rename from test/utils/buildruns.go rename to test/utils/v1alpha1/buildruns.go diff --git a/test/utils/builds.go b/test/utils/v1alpha1/builds.go similarity index 100% rename from test/utils/builds.go rename to test/utils/v1alpha1/builds.go diff --git a/test/utils/buildstrategies.go b/test/utils/v1alpha1/buildstrategies.go similarity index 100% rename from test/utils/buildstrategies.go rename to test/utils/v1alpha1/buildstrategies.go diff --git a/test/utils/clusterbuildstrategies.go b/test/utils/v1alpha1/clusterbuildstrategies.go similarity index 100% rename from test/utils/clusterbuildstrategies.go rename to test/utils/v1alpha1/clusterbuildstrategies.go diff --git a/test/utils/configmaps.go b/test/utils/v1alpha1/configmaps.go similarity index 100% rename from test/utils/configmaps.go rename to test/utils/v1alpha1/configmaps.go diff --git a/test/utils/controllers.go b/test/utils/v1alpha1/controllers.go similarity index 100% rename from test/utils/controllers.go rename to test/utils/v1alpha1/controllers.go diff --git a/test/utils/v1alpha1/environment.go b/test/utils/v1alpha1/environment.go new file mode 100644 index 0000000000..b614f782f8 --- /dev/null +++ b/test/utils/v1alpha1/environment.go @@ -0,0 +1,128 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "bytes" + "context" + "os" + "path/filepath" + "strconv" + "sync/atomic" + "time" + + "github.com/onsi/ginkgo/v2" + tektonClient "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" + + "k8s.io/client-go/kubernetes" + _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/clientcmd" + "sigs.k8s.io/controller-runtime/pkg/client" + + buildClient "github.com/shipwright-io/build/pkg/client/clientset/versioned" + "github.com/shipwright-io/build/pkg/ctxlog" + test "github.com/shipwright-io/build/test/v1alpha1_samples" + // from https://github.com/kubernetes/client-go/issues/345 +) + +var ( + namespaceCounter int32 +) + +// TestBuild wraps all required clients to run integration +// tests and also the namespace and operator channel used +// per each test case +type TestBuild struct { + // TODO: Adding specific field for polling here, interval and timeout + // but I think we need a small refactoring to make them global for all + // tests under /test dir + Interval time.Duration + TimeOut time.Duration + KubeConfig *rest.Config + Clientset *kubernetes.Clientset + Namespace string + StopBuildControllers context.CancelFunc + BuildClientSet *buildClient.Clientset + PipelineClientSet *tektonClient.Clientset + ControllerRuntimeClient client.Client + Catalog test.Catalog + Context context.Context + BuildControllerLogBuffer *bytes.Buffer +} + +// NewTestBuild returns an initialized instance of TestBuild +func NewTestBuild() (*TestBuild, error) { + namespaceID := ginkgo.GinkgoParallelProcess()*200 + int(atomic.AddInt32(&namespaceCounter, 1)) + testNamespace := "test-build-" + strconv.Itoa(namespaceID) + + logBuffer := &bytes.Buffer{} + l := ctxlog.NewLoggerTo(logBuffer, testNamespace) + + ctx := ctxlog.NewParentContext(l) + + kubeConfig, restConfig, err := KubeConfig() + if err != nil { + return nil, err + } + + // clientSet is required to communicate with our CRDs objects + // see https://www.openshift.com/blog/kubernetes-deep-dive-code-generation-customresources + buildClientSet, err := buildClient.NewForConfig(restConfig) + if err != nil { + return nil, err + } + + pipelineClientSet, err := tektonClient.NewForConfig(restConfig) + if err != nil { + return nil, err + } + + controllerRuntimeClient, err := client.New(restConfig, client.Options{}) + if err != nil { + return nil, err + } + + ctx, cancelFn := context.WithCancel(ctx) + + return &TestBuild{ + // TODO: interval and timeout can be configured via ENV vars + Interval: time.Second * 3, + TimeOut: time.Second * 180, + KubeConfig: restConfig, + Clientset: kubeConfig, + Namespace: testNamespace, + BuildClientSet: buildClientSet, + PipelineClientSet: pipelineClientSet, + ControllerRuntimeClient: controllerRuntimeClient, + Context: ctx, + BuildControllerLogBuffer: logBuffer, + StopBuildControllers: cancelFn, + }, nil +} + +// KubeConfig returns all required clients to speak with +// the k8s API +func KubeConfig() (*kubernetes.Clientset, *rest.Config, error) { + location := os.Getenv("KUBECONFIG") + if location == "" { + location = filepath.Join(os.Getenv("HOME"), ".kube", "config") + } + + config, err := clientcmd.BuildConfigFromFlags("", location) + if err != nil { + config, err = rest.InClusterConfig() + if err != nil { + return nil, nil, err + } + } + + clientset, err := kubernetes.NewForConfig(config) + if err != nil { + return nil, nil, err + } + + return clientset, config, nil +} diff --git a/test/utils/gomega.go b/test/utils/v1alpha1/gomega.go similarity index 100% rename from test/utils/gomega.go rename to test/utils/v1alpha1/gomega.go diff --git a/test/utils/image.go b/test/utils/v1alpha1/image.go similarity index 100% rename from test/utils/image.go rename to test/utils/v1alpha1/image.go diff --git a/test/utils/lookup.go b/test/utils/v1alpha1/lookup.go similarity index 100% rename from test/utils/lookup.go rename to test/utils/v1alpha1/lookup.go diff --git a/test/utils/namespaces.go b/test/utils/v1alpha1/namespaces.go similarity index 100% rename from test/utils/namespaces.go rename to test/utils/v1alpha1/namespaces.go diff --git a/test/utils/secrets.go b/test/utils/v1alpha1/secrets.go similarity index 100% rename from test/utils/secrets.go rename to test/utils/v1alpha1/secrets.go diff --git a/test/utils/service_accounts.go b/test/utils/v1alpha1/service_accounts.go similarity index 100% rename from test/utils/service_accounts.go rename to test/utils/v1alpha1/service_accounts.go diff --git a/test/utils/taskruns.go b/test/utils/v1alpha1/taskruns.go similarity index 100% rename from test/utils/taskruns.go rename to test/utils/v1alpha1/taskruns.go diff --git a/test/utils/v1alpha1/webhook.go b/test/utils/v1alpha1/webhook.go new file mode 100644 index 0000000000..731a7133ed --- /dev/null +++ b/test/utils/v1alpha1/webhook.go @@ -0,0 +1,110 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + "crypto/tls" + "net/http" + "time" + + "github.com/shipwright-io/build/pkg/webhook/conversion" + + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" +) + +func StartBuildWebhook() *http.Server { + mux := http.NewServeMux() + mux.HandleFunc("/convert", conversion.CRDConvertHandler(context.Background())) + mux.HandleFunc("/health", health) + + webhookServer := &http.Server{ + Addr: ":30443", + Handler: mux, + ReadHeaderTimeout: 32 * time.Second, + IdleTimeout: time.Second, + TLSConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + CurvePreferences: []tls.CurveID{tls.CurveP256, tls.CurveP384, tls.X25519}, + CipherSuites: []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + }, + }, + } + + // start server + go func() { + defer ginkgo.GinkgoRecover() + + if err := webhookServer.ListenAndServeTLS("/tmp/server-cert.pem", "/tmp/server-key.pem"); err != nil { + if err != http.ErrServerClosed { + gomega.Expect(err).ToNot(gomega.HaveOccurred()) + } + } + }() + + client := &http.Client{ + Transport: &http.Transport{ + IdleConnTimeout: 5 * time.Second, + ResponseHeaderTimeout: 5 * time.Second, + // #nosec:G402 test code + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + TLSHandshakeTimeout: 5 * time.Second, + }, + } + + gomega.Eventually(func() int { + r, err := client.Get("https://localhost:30443/health") + if err != nil { + return 0 + } + if r != nil { + return r.StatusCode + } + return 0 + }).WithTimeout(10 * time.Second).Should(gomega.Equal(http.StatusNoContent)) + + return webhookServer +} + +func StopBuildWebhook(webhookServer *http.Server) { + err := webhookServer.Close() + gomega.Expect(err).ToNot(gomega.HaveOccurred()) + + client := &http.Client{ + Transport: &http.Transport{ + IdleConnTimeout: 5 * time.Second, + ResponseHeaderTimeout: 5 * time.Second, + // #nosec:G402 test code + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + TLSHandshakeTimeout: 5 * time.Second, + }, + } + + gomega.Eventually(func() int { + r, err := client.Get("https://localhost:30443/health") + if err != nil { + return 0 + } + if r != nil { + return r.StatusCode + } + return 0 + }).WithTimeout(10 * time.Second).Should(gomega.Equal(0)) +} + +func health(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusNoContent) +} diff --git a/test/utils/v1beta1/buildruns.go b/test/utils/v1beta1/buildruns.go new file mode 100644 index 0000000000..2bb4c5d059 --- /dev/null +++ b/test/utils/v1beta1/buildruns.go @@ -0,0 +1,283 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "time" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" + + "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +// This class is intended to host all CRUD calls for testing BuildRun CRDs resources + +// CreateBR generates a BuildRun on the current test namespace +func (t *TestBuild) CreateBR(buildRun *v1beta1.BuildRun) error { + brInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + _, err := brInterface.Create(context.TODO(), buildRun, metav1.CreateOptions{}) + if err != nil { + return err + } + return nil +} + +// UpdateBR updates a BuildRun on the current test namespace +func (t *TestBuild) UpdateBR(buildRun *v1beta1.BuildRun) error { + brInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + _, err := brInterface.Update(context.TODO(), buildRun, metav1.UpdateOptions{}) + if err != nil { + return err + } + return nil +} + +// GetBR retrieves a BuildRun from a desired namespace +// Deprecated: Use LookupBuildRun instead. +func (t *TestBuild) GetBR(name string) (*v1beta1.BuildRun, error) { + brInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + br, err := brInterface.Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return br, nil +} + +// DeleteBR deletes a BuildRun from a desired namespace +func (t *TestBuild) DeleteBR(name string) error { + brInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + if err := brInterface.Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil { + return err + } + + return nil +} + +// GetBRReason ... +func (t *TestBuild) GetBRReason(name string) (string, error) { + br, err := t.GetBR(name) + if err != nil { + return "", err + } + cond := br.Status.GetCondition(v1beta1.Succeeded) + if cond == nil { + return "", errors.New("BuildRun had no Succeeded condition") + } + return cond.Reason, nil +} + +// GetBRTillCompletion returns a BuildRun that have a CompletionTime set. +// If the timeout is reached or it fails when retrieving the BuildRun it will +// stop polling and return +func (t *TestBuild) GetBRTillCompletion(name string) (*v1beta1.BuildRun, error) { + + var ( + pollBRTillCompletion = func() (bool, error) { + + bInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + buildRun, err := bInterface.Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + return false, err + } + if buildRun.Status.CompletionTime != nil { + return true, nil + } + + return false, nil + } + ) + + brInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + err := wait.PollImmediate(t.Interval, t.TimeOut, pollBRTillCompletion) + if err != nil { + return nil, err + } + + return brInterface.Get(context.TODO(), name, metav1.GetOptions{}) +} + +// GetBRTillNotFound waits for the buildrun to get deleted. It returns an error if BuildRun is not found +func (t *TestBuild) GetBRTillNotFound(name string, interval time.Duration, timeout time.Duration) (*v1beta1.BuildRun, error) { + + var ( + GetBRTillNotFound = func() (bool, error) { + + bInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + _, err := bInterface.Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil && apierrors.IsNotFound(err) { + return true, err + } + return false, nil + } + ) + + brInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + err := wait.PollImmediate(interval, timeout, GetBRTillNotFound) + if err != nil { + return nil, err + } + + return brInterface.Get(context.TODO(), name, metav1.GetOptions{}) +} + +// GetBRTillNotOwner returns a BuildRun that has not an owner. +// If the timeout is reached or it fails when retrieving the BuildRun it will +// stop polling and return +func (t *TestBuild) GetBRTillNotOwner(name string, owner string) (*v1beta1.BuildRun, error) { + + brInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + var ( + pollBRTillNotOwner = func() (bool, error) { + + buildRun, err := brInterface.Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + return false, err + } + + for _, ownerReference := range buildRun.OwnerReferences { + if ownerReference.Name == owner { + return false, nil + } + } + + return true, nil + } + ) + + if err := wait.PollImmediate(t.Interval, t.TimeOut, pollBRTillNotOwner); err != nil { + return nil, err + } + + return brInterface.Get(context.TODO(), name, metav1.GetOptions{}) +} + +// GetBRTillOwner returns a BuildRun that has an owner. +// If the timeout is reached or it fails when retrieving the BuildRun it will +// stop polling and return +func (t *TestBuild) GetBRTillOwner(name string, owner string) (*v1beta1.BuildRun, error) { + + brInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + var ( + pollBRTillOwner = func() (bool, error) { + + buildRun, err := brInterface.Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + return false, err + } + + for _, ownerReference := range buildRun.OwnerReferences { + if ownerReference.Name == owner { + return true, nil + } + } + + return false, nil + } + ) + + if err := wait.PollImmediate(t.Interval, t.TimeOut, pollBRTillOwner); err != nil { + return nil, err + } + + return brInterface.Get(context.TODO(), name, metav1.GetOptions{}) +} + +// GetBRTillStartTime returns a BuildRun that have a StartTime set. +// If the timeout is reached or it fails when retrieving the BuildRun it will +// stop polling and return +func (t *TestBuild) GetBRTillStartTime(name string) (*v1beta1.BuildRun, error) { + + var ( + pollBRTillCompletion = func() (bool, error) { + + bInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + buildRun, err := bInterface.Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + return false, err + } + if buildRun.Status.StartTime != nil { + return true, nil + } + + // early exit + if buildRun.Status.CompletionTime != nil { + if buildRunJSON, err := json.Marshal(buildRun); err == nil { + return false, fmt.Errorf("buildrun is completed: %s", buildRunJSON) + } + + return false, fmt.Errorf("buildrun is completed") + } + + return false, nil + } + ) + + brInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + err := wait.PollImmediate(t.Interval, t.TimeOut, pollBRTillCompletion) + if err != nil { + return nil, err + } + + return brInterface.Get(context.TODO(), name, metav1.GetOptions{}) +} + +// GetBRTillDesiredReason polls until a BuildRun gets a particular Reason +// it exit if an error happens or the timeout is reached +func (t *TestBuild) GetBRTillDesiredReason(buildRunname string, reason string) (currentReason string, err error) { + err = wait.PollImmediate(t.Interval, t.TimeOut, func() (bool, error) { + currentReason, err = t.GetBRReason(buildRunname) + if err != nil { + return false, err + } + if currentReason == reason { + return true, nil + } + + return false, nil + }) + + return +} + +// GetBRTillDeletion polls until a BuildRun is not found, it returns +// if a timeout is reached +func (t *TestBuild) GetBRTillDeletion(name string) (bool, error) { + + var ( + pollBRTillCompletion = func() (bool, error) { + + bInterface := t.BuildClientSet.ShipwrightV1beta1().BuildRuns(t.Namespace) + + _, err := bInterface.Get(context.TODO(), name, metav1.GetOptions{}) + if apierrors.IsNotFound(err) { + return true, nil + } + return false, nil + } + ) + + err := wait.PollImmediate(t.Interval, t.TimeOut, pollBRTillCompletion) + if err != nil { + return false, err + } + + return true, nil +} diff --git a/test/utils/v1beta1/builds.go b/test/utils/v1beta1/builds.go new file mode 100644 index 0000000000..e6e5704b4c --- /dev/null +++ b/test/utils/v1beta1/builds.go @@ -0,0 +1,149 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + "strings" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + + "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +// This class is intended to host all CRUD calls for testing Build CRDs resources + +// CreateBuild generates a Build on the current test namespace +func (t *TestBuild) CreateBuild(build *v1beta1.Build) error { + bInterface := t.BuildClientSet.ShipwrightV1beta1().Builds(t.Namespace) + + _, err := bInterface.Create(context.TODO(), build, metav1.CreateOptions{}) + return err +} + +// DeleteBuild deletes a Build on the desired namespace +func (t *TestBuild) DeleteBuild(name string) error { + bInterface := t.BuildClientSet.ShipwrightV1beta1().Builds(t.Namespace) + + err := bInterface.Delete(context.TODO(), name, metav1.DeleteOptions{}) + + return err +} + +// GetBuild returns a Build based on name +// Deprecated: Use LookupBuild instead +func (t *TestBuild) GetBuild(name string) (*v1beta1.Build, error) { + return t.BuildClientSet.ShipwrightV1beta1(). + Builds(t.Namespace).Get(context.TODO(), name, metav1.GetOptions{}) +} + +// ListBuilds returns existing Builds from the desired namespace +func (t *TestBuild) ListBuilds(namespace string) (*v1beta1.BuildList, error) { + return t.BuildClientSet.ShipwrightV1beta1().Builds(namespace).List(t.Context, metav1.ListOptions{}) +} + +// PatchBuild patches an existing Build using the merge patch type +func (t *TestBuild) PatchBuild(buildName string, data []byte) (*v1beta1.Build, error) { + return t.PatchBuildWithPatchType(buildName, data, types.MergePatchType) +} + +// PatchBuildWithPatchType patches an existing Build and allows specifying the patch type +func (t *TestBuild) PatchBuildWithPatchType(buildName string, data []byte, pt types.PatchType) (*v1beta1.Build, error) { + bInterface := t.BuildClientSet.ShipwrightV1beta1().Builds(t.Namespace) + b, err := bInterface.Patch(context.TODO(), buildName, pt, data, metav1.PatchOptions{}) + if err != nil { + return nil, err + } + return b, nil +} + +// GetBuildTillValidation polls until a Build gets a validation and updates +// it´s registered field. If timeout is reached or an error is found, it will +// return with an error +func (t *TestBuild) GetBuildTillValidation(name string) (build *v1beta1.Build, err error) { + err = wait.PollImmediate(t.Interval, t.TimeOut, func() (bool, error) { + build, err = t.LookupBuild(types.NamespacedName{Namespace: t.Namespace, Name: name}) + if err != nil && !apierrors.IsNotFound(err) { + return false, err + } + + // TODO: we might improve the conditional here + if build.Status.Registered != nil && *build.Status.Registered != "" { + return true, nil + } + + return false, nil + }) + + return +} + +// GetBuildTillRegistration polls until a Build gets a desired validation and updates +// it´s registered field. If timeout is reached or an error is found, it will +// return with an error +func (t *TestBuild) GetBuildTillRegistration(name string, condition corev1.ConditionStatus) (*v1beta1.Build, error) { + + var ( + pollBuildTillRegistration = func() (bool, error) { + + bInterface := t.BuildClientSet.ShipwrightV1beta1().Builds(t.Namespace) + + buildRun, err := bInterface.Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + return false, err + } + // TODO: we might improve the conditional here + if buildRun.Status.Registered != nil && *buildRun.Status.Registered == condition { + return true, nil + } + + return false, nil + } + ) + + brInterface := t.BuildClientSet.ShipwrightV1beta1().Builds(t.Namespace) + + if err := wait.PollImmediate(t.Interval, t.TimeOut, pollBuildTillRegistration); err != nil { + return nil, err + } + + return brInterface.Get(context.TODO(), name, metav1.GetOptions{}) +} + +// GetBuildTillMessageContainsSubstring polls until a Build message contains the desired +// substring value and updates it´s registered field. If timeout is reached or an error is found, +// it will return with an error +func (t *TestBuild) GetBuildTillMessageContainsSubstring(name string, partOfMessage string) (*v1beta1.Build, error) { + + var ( + pollBuildTillMessageContainsSubString = func() (bool, error) { + + bInterface := t.BuildClientSet.ShipwrightV1beta1().Builds(t.Namespace) + + buildRun, err := bInterface.Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + return false, err + } + + if strings.Contains(*buildRun.Status.Message, partOfMessage) { + return true, nil + } + + return false, nil + } + ) + + brInterface := t.BuildClientSet.ShipwrightV1beta1().Builds(t.Namespace) + + if err := wait.PollImmediate(t.Interval, t.TimeOut, pollBuildTillMessageContainsSubString); err != nil { + return nil, err + } + + return brInterface.Get(context.TODO(), name, metav1.GetOptions{}) +} diff --git a/test/utils/v1beta1/buildstrategies.go b/test/utils/v1beta1/buildstrategies.go new file mode 100644 index 0000000000..1c480bc97b --- /dev/null +++ b/test/utils/v1beta1/buildstrategies.go @@ -0,0 +1,33 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +// This class is intended to host all CRUD calls for testing BuildStrategy CRDs resources + +// CreateBuildStrategy generates a BuildStrategy on the current test namespace +func (t *TestBuild) CreateBuildStrategy(bs *v1beta1.BuildStrategy) error { + bsInterface := t.BuildClientSet.ShipwrightV1beta1().BuildStrategies(t.Namespace) + + _, err := bsInterface.Create(context.TODO(), bs, metav1.CreateOptions{}) + if err != nil { + return err + } + return nil +} + +// DeleteBuildStrategy deletes a BuildStrategy on the current test namespace +func (t *TestBuild) DeleteBuildStrategy(name string) error { + bsInterface := t.BuildClientSet.ShipwrightV1beta1().BuildStrategies(t.Namespace) + + return bsInterface.Delete(context.TODO(), name, metav1.DeleteOptions{}) +} diff --git a/test/utils/v1beta1/clusterbuildstrategies.go b/test/utils/v1beta1/clusterbuildstrategies.go new file mode 100644 index 0000000000..bf8ffbc293 --- /dev/null +++ b/test/utils/v1beta1/clusterbuildstrategies.go @@ -0,0 +1,37 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +// This class is intended to host all CRUD calls for testing ClusterBuildStrategy CRDs resources + +// CreateClusterBuildStrategy generates a ClusterBuildStrategy on the current test namespace +func (t *TestBuild) CreateClusterBuildStrategy(cbs *v1beta1.ClusterBuildStrategy) error { + cbsInterface := t.BuildClientSet.ShipwrightV1beta1().ClusterBuildStrategies() + + _, err := cbsInterface.Create(context.TODO(), cbs, metav1.CreateOptions{}) + if err != nil { + return err + } + return nil +} + +// DeleteClusterBuildStrategy deletes a ClusterBuildStrategy on the desired namespace +func (t *TestBuild) DeleteClusterBuildStrategy(name string) error { + cbsInterface := t.BuildClientSet.ShipwrightV1beta1().ClusterBuildStrategies() + + err := cbsInterface.Delete(context.TODO(), name, metav1.DeleteOptions{}) + if err != nil { + return err + } + return nil +} diff --git a/test/utils/v1beta1/configmaps.go b/test/utils/v1beta1/configmaps.go new file mode 100644 index 0000000000..748bbd803b --- /dev/null +++ b/test/utils/v1beta1/configmaps.go @@ -0,0 +1,33 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// This class is intended to host all CRUD calls for testing configmap primitive resources + +// CreateConfigMap generates a ConfigMap on the current test namespace +func (t *TestBuild) CreateConfigMap(configMap *corev1.ConfigMap) error { + client := t.Clientset.CoreV1().ConfigMaps(t.Namespace) + _, err := client.Create(context.TODO(), configMap, metav1.CreateOptions{}) + if err != nil { + return err + } + return nil +} + +// DeleteConfigMap removes the desired configMap +func (t *TestBuild) DeleteConfigMap(name string) error { + client := t.Clientset.CoreV1().ConfigMaps(t.Namespace) + if err := client.Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil { + return err + } + return nil +} diff --git a/test/utils/v1beta1/controllers.go b/test/utils/v1beta1/controllers.go new file mode 100644 index 0000000000..539dd58f06 --- /dev/null +++ b/test/utils/v1beta1/controllers.go @@ -0,0 +1,41 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "sigs.k8s.io/controller-runtime/pkg/manager" + + buildconfig "github.com/shipwright-io/build/pkg/config" + "github.com/shipwright-io/build/pkg/controller" +) + +// StartBuildControllers initialize an operator as if being call from main, +// but it disables the prometheus metrics and leader election. This intended +// to for testing. +func (t *TestBuild) StartBuildControllers() error { + c := buildconfig.NewDefaultConfig() + + // read configuration from environment variables, especially the GIT_CONTAINER_IMAGE + c.SetConfigFromEnv() + + mgr, err := controller.NewManager(t.Context, c, t.KubeConfig, manager.Options{ + Namespace: t.Namespace, + LeaderElection: false, + MetricsBindAddress: "0", + }) + if err != nil { + return err + } + + go func() { + // set stopChan with the channel for future closing + err := mgr.Start(t.Context) + if err != nil { + panic(err) + } + }() + + return nil +} diff --git a/test/utils/environment.go b/test/utils/v1beta1/environment.go similarity index 92% rename from test/utils/environment.go rename to test/utils/v1beta1/environment.go index 987aaa8c5b..df541a02f3 100644 --- a/test/utils/environment.go +++ b/test/utils/v1beta1/environment.go @@ -24,7 +24,8 @@ import ( buildClient "github.com/shipwright-io/build/pkg/client/clientset/versioned" "github.com/shipwright-io/build/pkg/ctxlog" - "github.com/shipwright-io/build/test" + test "github.com/shipwright-io/build/test/v1beta1_samples" + // from https://github.com/kubernetes/client-go/issues/345 ) var ( @@ -41,11 +42,11 @@ type TestBuild struct { Interval time.Duration TimeOut time.Duration KubeConfig *rest.Config - Clientset kubernetes.Interface + Clientset *kubernetes.Clientset Namespace string StopBuildControllers context.CancelFunc - BuildClientSet buildClient.Interface - PipelineClientSet tektonClient.Interface + BuildClientSet *buildClient.Clientset + PipelineClientSet *tektonClient.Clientset ControllerRuntimeClient client.Client Catalog test.Catalog Context context.Context diff --git a/test/utils/v1beta1/gomega.go b/test/utils/v1beta1/gomega.go new file mode 100644 index 0000000000..db7bc8bdbc --- /dev/null +++ b/test/utils/v1beta1/gomega.go @@ -0,0 +1,142 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "fmt" + "net/http" + "reflect" + + "github.com/onsi/gomega/format" + "github.com/onsi/gomega/types" +) + +type containNamedElementMatcher struct { + Name string +} + +func (matcher *containNamedElementMatcher) FailureMessage(actual interface{}) (message string) { + return format.Message(actual, "to contain element with name", matcher.Name) +} + +func (matcher *containNamedElementMatcher) NegatedFailureMessage(actual interface{}) (message string) { + return format.Message(actual, "not to contain element with name", matcher.Name) +} + +func (matcher *containNamedElementMatcher) Match(actual interface{}) (success bool, err error) { + if actual == nil { + return false, nil + } + + kind := reflect.TypeOf(actual).Kind() + if kind == reflect.Array || kind == reflect.Slice { + value := reflect.ValueOf(actual) + + for i := 0; i < value.Len(); i++ { + vItem := value.Index(i) + vName := vItem.FieldByName("Name") + if !vName.IsZero() && matcher.Name == vName.String() { + return true, nil + } + } + } + + return false, nil +} + +// ContainNamedElement can be applied for an array or slice of objects which have a Name field, to check if any item has a matching name +func ContainNamedElement(name string) types.GomegaMatcher { + return &containNamedElementMatcher{ + Name: name, + } +} + +type containNamedWithValueElementMatcher struct { + Name string + Value string +} + +func (matcher *containNamedWithValueElementMatcher) FailureMessage(actual interface{}) (message string) { + return format.Message(actual, "to contain element with name and value", fmt.Sprintf("%s=%s", matcher.Name, matcher.Value)) +} + +func (matcher *containNamedWithValueElementMatcher) NegatedFailureMessage(actual interface{}) (message string) { + return format.Message(actual, "not to contain element with name and value", fmt.Sprintf("%s=%s", matcher.Name, matcher.Value)) +} + +func (matcher *containNamedWithValueElementMatcher) Match(actual interface{}) (success bool, err error) { + if actual == nil { + return false, nil + } + + kind := reflect.TypeOf(actual).Kind() + if kind == reflect.Array || kind == reflect.Slice { + value := reflect.ValueOf(actual) + + for i := 0; i < value.Len(); i++ { + vItem := value.Index(i) + vName := vItem.FieldByName("Name") + if !vName.IsZero() && matcher.Name == vName.String() { + vValue := vItem.FieldByName("Value") + if !vValue.IsZero() && matcher.Value == vValue.String() { + return true, nil + } + } + } + } + + return false, nil +} + +// ContainNamedElementWithValue can be applied for an array or slice of objects which have a Name and Value field, to check if any item has a matching name and value +func ContainNamedElementWithValue(name string, value string) types.GomegaMatcher { + return &containNamedWithValueElementMatcher{ + Name: name, + Value: value, + } +} + +type returnMatcher struct { + actualStatusCode int + expectedStatusCode int +} + +func (matcher *returnMatcher) FailureMessage(actual interface{}) (message string) { + return format.Message(matcher.expectedStatusCode, fmt.Sprintf("to be the HTTP response for %s, but received", actual), matcher.actualStatusCode) +} + +func (matcher *returnMatcher) NegatedFailureMessage(actual interface{}) (message string) { + return format.Message(matcher.expectedStatusCode, fmt.Sprintf("to not be the HTTP response for %s, but received", actual), matcher.actualStatusCode) +} + +func (matcher *returnMatcher) Match(actual interface{}) (success bool, err error) { + if actual == nil { + return false, nil + } + + kind := reflect.TypeOf(actual).Kind() + if kind == reflect.String { + url := reflect.ValueOf(actual).String() + + // #nosec:G107 test code + resp, err := http.Get(url) + if err != nil { + return false, err + } + + matcher.actualStatusCode = resp.StatusCode + + return resp.StatusCode == matcher.expectedStatusCode, nil + } + + return false, nil +} + +// Return can be applied for a string, it will call the URL and check the status code +func Return(statusCode int) types.GomegaMatcher { + return &returnMatcher{ + expectedStatusCode: statusCode, + } +} diff --git a/test/utils/v1beta1/image.go b/test/utils/v1beta1/image.go new file mode 100644 index 0000000000..4b900cb727 --- /dev/null +++ b/test/utils/v1beta1/image.go @@ -0,0 +1,115 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "encoding/json" + "fmt" + "log" + "strings" + + "github.com/google/go-containerregistry/pkg/authn" + "github.com/google/go-containerregistry/pkg/name" + containerreg "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote" + buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1" + "k8s.io/apimachinery/pkg/types" + + . "github.com/onsi/gomega" +) + +func getImageURL(buildRun *buildv1beta1.BuildRun) string { + image := "" + if buildRun.Spec.Output.Image != "" { + image = buildRun.Spec.Output.Image + } else { + image = buildRun.Status.BuildSpec.Output.Image + } + + if buildRun.Status.Output != nil && buildRun.Status.Output.Digest != "" { + image = fmt.Sprintf("%s@%s", image, buildRun.Status.Output.Digest) + } + + // In the GitHub action, we are using a registry inside the cluster to + // push the image created by `buildRun`. The registry inside the cluster + // is not directly accessible from the local, so that we have mapped + // the cluster registry port to the local system + // by providing `test/kind/config.yaml` config to the kind + return strings.Replace(image, "registry.registry.svc.cluster.local", "localhost", 1) +} + +// GetImage loads the image manifest for the image produced by a BuildRun +func (t *TestBuild) GetImage(buildRun *buildv1beta1.BuildRun) containerreg.Image { + ref, err := name.ParseReference(getImageURL(buildRun)) + Expect(err).ToNot(HaveOccurred()) + + img, err := remote.Image(ref, remote.WithAuth(t.getRegistryAuthentication(buildRun, ref))) + Expect(err).ToNot(HaveOccurred()) + + return img +} + +func (t *TestBuild) getRegistryAuthentication( + buildRun *buildv1beta1.BuildRun, + ref name.Reference, +) authn.Authenticator { + secretName := "" + if buildRun.Spec.Output != nil && buildRun.Spec.Output.PushSecret != nil { + secretName = *buildRun.Spec.Output.PushSecret + } else if buildRun.Status.BuildSpec.Output.PushSecret != nil { + secretName = *buildRun.Status.BuildSpec.Output.PushSecret + } + + // In case no secret is mounted, use anonymous + if secretName == "" { + log.Println("No access credentials provided, using anonymous mode") + return authn.Anonymous + } + + secret, err := t.LookupSecret( + types.NamespacedName{ + Namespace: buildRun.Namespace, + Name: secretName, + }, + ) + Expect(err).ToNot(HaveOccurred(), "Error retrieving registry secret") + + type auth struct { + Auths map[string]authn.AuthConfig `json:"auths,omitempty"` + } + + var authConfig auth + + Expect(json.Unmarshal(secret.Data[".dockerconfigjson"], &authConfig)).ToNot(HaveOccurred(), "Error parsing secrets docker config") + + // Look-up the respective registry server inside the credentials + registryName := ref.Context().RegistryStr() + if registryName == name.DefaultRegistry { + registryName = authn.DefaultAuthKey + } + + return authn.FromConfig(authConfig.Auths[registryName]) +} + +// ValidateImagePlatformsExist that the image produced by a BuildRun exists for a set of platforms +func (t *TestBuild) ValidateImagePlatformsExist(buildRun *buildv1beta1.BuildRun, expectedPlatforms []containerreg.Platform) { + ref, err := name.ParseReference(getImageURL(buildRun)) + Expect(err).ToNot(HaveOccurred()) + + for _, expectedPlatform := range expectedPlatforms { + _, err := remote.Image(ref, remote.WithAuth(t.getRegistryAuthentication(buildRun, ref)), remote.WithPlatform(expectedPlatform)) + Expect(err).ToNot(HaveOccurred(), fmt.Sprintf("Failed to validate %s/%s", expectedPlatform.OS, expectedPlatform.Architecture)) + } +} + +// ValidateImageDigest ensures that an image digest is set in the BuildRun status and that this digest is pointing to an image +func (t *TestBuild) ValidateImageDigest(buildRun *buildv1beta1.BuildRun) { + // Verify that the status contains a digest + Expect(buildRun.Status.Output).NotTo(BeNil(), ".status.output is nil") + Expect(buildRun.Status.Output.Digest).NotTo(Equal(""), ".status.output.digest is empty") + + // Verify that the digest is valid by retrieving the image manifest + t.GetImage(buildRun) +} diff --git a/test/utils/v1beta1/lookup.go b/test/utils/v1beta1/lookup.go new file mode 100644 index 0000000000..595c9a6e5b --- /dev/null +++ b/test/utils/v1beta1/lookup.go @@ -0,0 +1,151 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "fmt" + "strings" + "time" + + pipelinev1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" + + buildv1beta1 "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +func (t *TestBuild) LookupSecret(entity types.NamespacedName) (*corev1.Secret, error) { + result, err := lookupRuntimeObject(func() (runtime.Object, error) { + return t.Clientset. + CoreV1(). + Secrets(entity.Namespace). + Get(t.Context, entity.Name, metav1.GetOptions{}) + }) + + return result.(*corev1.Secret), err +} + +func (t *TestBuild) LookupPod(entity types.NamespacedName) (*corev1.Pod, error) { + result, err := lookupRuntimeObject(func() (runtime.Object, error) { + return t.Clientset. + CoreV1(). + Pods(entity.Namespace). + Get(t.Context, entity.Name, metav1.GetOptions{}) + }) + + return result.(*corev1.Pod), err +} + +func (t *TestBuild) LookupBuild(entity types.NamespacedName) (*buildv1beta1.Build, error) { + result, err := lookupRuntimeObject(func() (runtime.Object, error) { + return t.BuildClientSet.ShipwrightV1beta1(). + Builds(entity.Namespace).Get(t.Context, entity.Name, metav1.GetOptions{}) + }) + + return result.(*buildv1beta1.Build), err +} + +func (t *TestBuild) LookupBuildRun(entity types.NamespacedName) (*buildv1beta1.BuildRun, error) { + result, err := lookupRuntimeObject(func() (runtime.Object, error) { + return t.BuildClientSet.ShipwrightV1beta1(). + BuildRuns(entity.Namespace).Get(t.Context, entity.Name, metav1.GetOptions{}) + }) + + return result.(*buildv1beta1.BuildRun), err +} + +func (t *TestBuild) LookupTaskRun(entity types.NamespacedName) (*pipelinev1beta1.TaskRun, error) { + result, err := lookupRuntimeObject(func() (runtime.Object, error) { + return t.PipelineClientSet. + TektonV1beta1(). + TaskRuns(entity.Namespace). + Get(t.Context, entity.Name, metav1.GetOptions{}) + }) + + return result.(*pipelinev1beta1.TaskRun), err +} + +func (t *TestBuild) LookupTaskRunUsingBuildRun(buildRun *buildv1beta1.BuildRun) (*pipelinev1beta1.TaskRun, error) { + if buildRun == nil { + return nil, fmt.Errorf("no BuildRun specified to lookup TaskRun") + } + + if buildRun.Status.TaskRunName != nil { + return t.LookupTaskRun(types.NamespacedName{Namespace: buildRun.Namespace, Name: *buildRun.Status.TaskRunName}) + } + + tmp, err := lookupRuntimeObject(func() (runtime.Object, error) { + return t.PipelineClientSet. + TektonV1beta1(). + TaskRuns(buildRun.Namespace). + List(t.Context, metav1.ListOptions{ + LabelSelector: labels.SelectorFromSet( + map[string]string{ + buildv1beta1.LabelBuildRun: buildRun.Name, + }).String(), + }) + }) + + if err != nil { + return nil, err + } + + var taskRunList = tmp.(*pipelinev1beta1.TaskRunList) + switch len(taskRunList.Items) { + case 0: + return nil, fmt.Errorf("no TaskRun found for BuildRun %s/%s", buildRun.Namespace, buildRun.Name) + + case 1: + return &taskRunList.Items[0], nil + + default: + return nil, fmt.Errorf("multiple TaskRuns found for BuildRun %s/%s, which should not have happened", buildRun.Namespace, buildRun.Name) + } +} + +func (t *TestBuild) LookupServiceAccount(entity types.NamespacedName) (*corev1.ServiceAccount, error) { + result, err := lookupRuntimeObject(func() (runtime.Object, error) { + return t.Clientset. + CoreV1(). + ServiceAccounts(entity.Namespace). + Get(t.Context, entity.Name, metav1.GetOptions{}) + }) + + return result.(*corev1.ServiceAccount), err +} + +func lookupRuntimeObject(f func() (runtime.Object, error)) (result runtime.Object, err error) { + err = wait.PollImmediate(4*time.Second, 60*time.Second, func() (bool, error) { + result, err = f() + if err != nil { + // check if we have an error that we want to retry + if isRetryableError(err) { + return false, nil + } + + return true, err + } + + // successful call + return true, nil + }) + + return +} + +func isRetryableError(err error) bool { + return apierrors.IsServerTimeout(err) || + apierrors.IsTimeout(err) || + apierrors.IsTooManyRequests(err) || + apierrors.IsInternalError(err) || + err.Error() == "etcdserver: request timed out" || + err.Error() == "rpc error: code = Unavailable desc = transport is closing" || + strings.Contains(err.Error(), "net/http: request canceled while waiting for connection") +} diff --git a/test/utils/v1beta1/namespaces.go b/test/utils/v1beta1/namespaces.go new file mode 100644 index 0000000000..e5ad5bf002 --- /dev/null +++ b/test/utils/v1beta1/namespaces.go @@ -0,0 +1,73 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + "time" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/wait" +) + +// This class is intended to host all CRUD calls for Namespace primitive resources + +// CreateNamespace generates a Namespace with the current test name +func (t *TestBuild) CreateNamespace() error { + client := t.Clientset.CoreV1().Namespaces() + ns := &corev1.Namespace{ + ObjectMeta: metav1.ObjectMeta{ + Name: t.Namespace, + }, + } + _, err := client.Create(context.TODO(), ns, metav1.CreateOptions{}) + if err != nil { + return err + } + + // wait for the default service account to exist + pollServiceAccount := func() (bool, error) { + + serviceAccountInterface := t.Clientset.CoreV1().ServiceAccounts(t.Namespace) + + _, err := serviceAccountInterface.Get(context.TODO(), "default", metav1.GetOptions{}) + if err != nil { + if !apierrors.IsNotFound(err) { + return false, err + } + return false, nil + } + + return true, nil + } + + return wait.PollImmediate(t.Interval, t.TimeOut, pollServiceAccount) +} + +// DeleteNamespace deletes the namespace with the current test name +func (t *TestBuild) DeleteNamespace() error { + client := t.Clientset.CoreV1().Namespaces() + + if err := client.Delete(context.TODO(), t.Namespace, metav1.DeleteOptions{}); err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + // wait for the namespace to be deleted + pollNamespace := func() (bool, error) { + + if _, err := client.Get(context.TODO(), t.Namespace, metav1.GetOptions{}); err != nil && apierrors.IsNotFound(err) { + return true, nil + } + + return false, nil + } + + return wait.PollImmediate(t.Interval, 5*time.Second, pollNamespace) +} diff --git a/test/utils/v1beta1/secrets.go b/test/utils/v1beta1/secrets.go new file mode 100644 index 0000000000..9bd8016b95 --- /dev/null +++ b/test/utils/v1beta1/secrets.go @@ -0,0 +1,50 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" +) + +// This class is intended to host all CRUD calls for testing secrets primitive resources + +// CreateSecret generates a Secret on the current test namespace +func (t *TestBuild) CreateSecret(secret *corev1.Secret) error { + client := t.Clientset.CoreV1().Secrets(t.Namespace) + _, err := client.Create(context.TODO(), secret, metav1.CreateOptions{}) + if err != nil { + return err + } + return nil +} + +// DeleteSecret removes the desired secret +func (t *TestBuild) DeleteSecret(name string) error { + client := t.Clientset.CoreV1().Secrets(t.Namespace) + if err := client.Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil { + return err + } + return nil +} + +// PatchSecret patches a secret based on name and with the provided data. +// It used the merge type strategy +func (t *TestBuild) PatchSecret(name string, data []byte) (*corev1.Secret, error) { + return t.PatchSecretWithPatchType(name, data, types.MergePatchType) +} + +// PatchSecretWithPatchType patches a secret with a desire data and patch strategy +func (t *TestBuild) PatchSecretWithPatchType(name string, data []byte, pt types.PatchType) (*corev1.Secret, error) { + secInterface := t.Clientset.CoreV1().Secrets(t.Namespace) + b, err := secInterface.Patch(context.TODO(), name, pt, data, metav1.PatchOptions{}) + if err != nil { + return nil, err + } + return b, nil +} diff --git a/test/utils/v1beta1/service_accounts.go b/test/utils/v1beta1/service_accounts.go new file mode 100644 index 0000000000..27de19f5ed --- /dev/null +++ b/test/utils/v1beta1/service_accounts.go @@ -0,0 +1,44 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + + corev1 "k8s.io/api/core/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// This class is intended to host all CRUD calls for testing secrets primitive resources + +// CreateSAFromName creates a simple ServiceAccount with the provided name if it does not exist. +func (t *TestBuild) CreateSAFromName(saName string) error { + client := t.Clientset.CoreV1().ServiceAccounts(t.Namespace) + _, err := client.Get(context.TODO(), saName, metav1.GetOptions{}) + // If the service account already exists, no error is returned + if err == nil { + return nil + } + if !apierrors.IsNotFound(err) { + return err + } + _, err = client.Create(context.TODO(), &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: saName, + }}, metav1.CreateOptions{}) + return err +} + +// GetSA retrieves an existing service-account by name +// Deprecated: Use LookupServiceAccount instead. +func (t *TestBuild) GetSA(saName string) (*corev1.ServiceAccount, error) { + client := t.Clientset.CoreV1().ServiceAccounts(t.Namespace) + sa, err := client.Get(context.TODO(), saName, metav1.GetOptions{}) + if err != nil { + return nil, err + } + return sa, nil +} diff --git a/test/utils/v1beta1/taskruns.go b/test/utils/v1beta1/taskruns.go new file mode 100644 index 0000000000..aef9a53919 --- /dev/null +++ b/test/utils/v1beta1/taskruns.go @@ -0,0 +1,115 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + "errors" + "fmt" + + v1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "knative.dev/pkg/apis" + + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/apimachinery/pkg/util/wait" +) + +// This class is intended to host all CRUD calls for testing TaskRuns CRDs resources + +// GetTaskRunFromBuildRun retrieves an owned TaskRun based on the BuildRunName +func (t *TestBuild) GetTaskRunFromBuildRun(buildRunName string) (*v1beta1.TaskRun, error) { + taskRunLabelSelector := fmt.Sprintf("buildrun.shipwright.io/name=%s", buildRunName) + + trInterface := t.PipelineClientSet.TektonV1beta1().TaskRuns(t.Namespace) + + trList, err := trInterface.List(context.TODO(), metav1.ListOptions{ + LabelSelector: taskRunLabelSelector, + }) + if err != nil { + return nil, err + } + + if len(trList.Items) != 1 { + return nil, fmt.Errorf("failed to find an owned TaskRun based on a Buildrun %s/%s name", t.Namespace, buildRunName) + } + + return &trList.Items[0], nil +} + +// UpdateTaskRun applies changes to a TaskRun object +func (t *TestBuild) UpdateTaskRun(name string, apply func(tr *v1beta1.TaskRun)) (*v1beta1.TaskRun, error) { + var tr *v1beta1.TaskRun + var err error + for i := 0; i < 5; i++ { + tr, err = t.LookupTaskRun(types.NamespacedName{ + Namespace: t.Namespace, + Name: name, + }) + if err != nil { + return nil, err + } + + apply(tr) + + tr, err = t.PipelineClientSet.TektonV1beta1().TaskRuns(t.Namespace).Update(context.TODO(), tr, metav1.UpdateOptions{}) + if err == nil { + return tr, nil + } + // retry the famous ""Operation cannot be fulfilled on taskruns.tekton.dev \"buildrun-test-build-225-xkw6k\": the object has been modified; please apply your changes to the latest version and try again" error + if !apierrors.IsConflict(err) { + return nil, err + } + } + + return nil, err +} + +// GetTRReason returns the Reason of the Succeeded condition +// of an existing TaskRun based on a BuildRun name +func (t *TestBuild) GetTRReason(buildRunName string) (string, error) { + tr, err := t.GetTaskRunFromBuildRun(buildRunName) + if err != nil { + return "", err + } + + trCondition := tr.Status.GetCondition(apis.ConditionSucceeded) + if trCondition != nil { + return trCondition.Reason, nil + } + + return "", errors.New("foo") +} + +// GetTRTillDesiredReason polls until a TaskRun matches a desired Reason +// or it exits if an error happen or a timeout is reach. +func (t *TestBuild) GetTRTillDesiredReason(buildRunName string, reason string) (trReason string, err error) { + err = wait.PollImmediate(t.Interval, t.TimeOut, func() (bool, error) { + trReason, err = t.GetTRReason(buildRunName) + if err != nil { + return false, err + } + + if trReason == reason { + return true, nil + } + + return false, nil + }) + + return +} + +// DeleteTR deletes a TaskRun from a desired namespace +func (t *TestBuild) DeleteTR(name string) error { + trInterface := t.PipelineClientSet.TektonV1beta1().TaskRuns(t.Namespace) + + if err := trInterface.Delete(context.TODO(), name, metav1.DeleteOptions{}); err != nil { + return err + } + + return nil +} diff --git a/test/utils/v1beta1/webhook.go b/test/utils/v1beta1/webhook.go new file mode 100644 index 0000000000..731a7133ed --- /dev/null +++ b/test/utils/v1beta1/webhook.go @@ -0,0 +1,110 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package utils + +import ( + "context" + "crypto/tls" + "net/http" + "time" + + "github.com/shipwright-io/build/pkg/webhook/conversion" + + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" +) + +func StartBuildWebhook() *http.Server { + mux := http.NewServeMux() + mux.HandleFunc("/convert", conversion.CRDConvertHandler(context.Background())) + mux.HandleFunc("/health", health) + + webhookServer := &http.Server{ + Addr: ":30443", + Handler: mux, + ReadHeaderTimeout: 32 * time.Second, + IdleTimeout: time.Second, + TLSConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + CurvePreferences: []tls.CurveID{tls.CurveP256, tls.CurveP384, tls.X25519}, + CipherSuites: []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + }, + }, + } + + // start server + go func() { + defer ginkgo.GinkgoRecover() + + if err := webhookServer.ListenAndServeTLS("/tmp/server-cert.pem", "/tmp/server-key.pem"); err != nil { + if err != http.ErrServerClosed { + gomega.Expect(err).ToNot(gomega.HaveOccurred()) + } + } + }() + + client := &http.Client{ + Transport: &http.Transport{ + IdleConnTimeout: 5 * time.Second, + ResponseHeaderTimeout: 5 * time.Second, + // #nosec:G402 test code + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + TLSHandshakeTimeout: 5 * time.Second, + }, + } + + gomega.Eventually(func() int { + r, err := client.Get("https://localhost:30443/health") + if err != nil { + return 0 + } + if r != nil { + return r.StatusCode + } + return 0 + }).WithTimeout(10 * time.Second).Should(gomega.Equal(http.StatusNoContent)) + + return webhookServer +} + +func StopBuildWebhook(webhookServer *http.Server) { + err := webhookServer.Close() + gomega.Expect(err).ToNot(gomega.HaveOccurred()) + + client := &http.Client{ + Transport: &http.Transport{ + IdleConnTimeout: 5 * time.Second, + ResponseHeaderTimeout: 5 * time.Second, + // #nosec:G402 test code + TLSClientConfig: &tls.Config{ + InsecureSkipVerify: true, + }, + TLSHandshakeTimeout: 5 * time.Second, + }, + } + + gomega.Eventually(func() int { + r, err := client.Get("https://localhost:30443/health") + if err != nil { + return 0 + } + if r != nil { + return r.StatusCode + } + return 0 + }).WithTimeout(10 * time.Second).Should(gomega.Equal(0)) +} + +func health(resp http.ResponseWriter, _ *http.Request) { + resp.WriteHeader(http.StatusNoContent) +} diff --git a/test/build_samples.go b/test/v1alpha1_samples/build_samples.go similarity index 99% rename from test/build_samples.go rename to test/v1alpha1_samples/build_samples.go index 9351f4adba..48e6b1fabc 100644 --- a/test/build_samples.go +++ b/test/v1alpha1_samples/build_samples.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package test +package testalpha // MinimalBuildahBuildWithEnvVars defines a simple // Build with a source, strategy, and env vars diff --git a/test/buildrun_samples.go b/test/v1alpha1_samples/buildrun_samples.go similarity index 99% rename from test/buildrun_samples.go rename to test/v1alpha1_samples/buildrun_samples.go index 84a0964e12..02e505104d 100644 --- a/test/buildrun_samples.go +++ b/test/v1alpha1_samples/buildrun_samples.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package test +package testalpha // MinimalBuildahBuildRunWithEnvVars defines a simple // BuildRun with a referenced Build and env vars diff --git a/test/buildstrategy_samples.go b/test/v1alpha1_samples/buildstrategy_samples.go similarity index 99% rename from test/buildstrategy_samples.go rename to test/v1alpha1_samples/buildstrategy_samples.go index e7b7b55c19..4f99f84457 100644 --- a/test/buildstrategy_samples.go +++ b/test/v1alpha1_samples/buildstrategy_samples.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package test +package testalpha // MinimalBuildahBuildStrategy defines a // BuildStrategy for Buildah with two steps diff --git a/test/catalog.go b/test/v1alpha1_samples/catalog.go similarity index 98% rename from test/catalog.go rename to test/v1alpha1_samples/catalog.go index 501b742829..f8f700df31 100644 --- a/test/catalog.go +++ b/test/v1alpha1_samples/catalog.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package test +package testalpha import ( "context" @@ -21,7 +21,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/types" - "k8s.io/utils/pointer" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/yaml" @@ -99,7 +99,7 @@ func (c *Catalog) BuildWithClusterBuildStrategyAndFalseSourceAnnotation(name str }, Spec: build.BuildSpec{ Source: build.Source{ - URL: pointer.String("foobar"), + URL: ptr.To[string]("foobar"), }, Strategy: build.Strategy{ Name: strategyName, @@ -122,7 +122,7 @@ func (c *Catalog) BuildWithClusterBuildStrategy(name string, ns string, strategy }, Spec: build.BuildSpec{ Source: build.Source{ - URL: pointer.String("https://github.com/shipwright-io/sample-go"), + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go"), }, Strategy: build.Strategy{ Name: strategyName, @@ -148,7 +148,7 @@ func (c *Catalog) BuildWithClusterBuildStrategyAndSourceSecret(name string, ns s }, Spec: build.BuildSpec{ Source: build.Source{ - URL: pointer.String("https://github.com/shipwright-io/sample-go"), + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go"), Credentials: &corev1.LocalObjectReference{ Name: "foobar", }, @@ -174,7 +174,7 @@ func (c *Catalog) BuildWithBuildStrategy(name string, ns string, strategyName st }, Spec: build.BuildSpec{ Source: build.Source{ - URL: pointer.String("https://github.com/shipwright-io/sample-go"), + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go"), }, Strategy: build.Strategy{ Name: strategyName, @@ -193,7 +193,7 @@ func (c *Catalog) BuildWithNilBuildStrategyKind(name string, ns string, strategy }, Spec: build.BuildSpec{ Source: build.Source{ - URL: pointer.String("https://github.com/shipwright-io/sample-go"), + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go"), }, Strategy: build.Strategy{ Name: strategyName, @@ -211,7 +211,7 @@ func (c *Catalog) BuildWithOutputSecret(name string, ns string, secretName strin }, Spec: build.BuildSpec{ Source: build.Source{ - URL: pointer.String("https://github.com/shipwright-io/sample-go"), + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go"), }, Output: build.Image{ Credentials: &corev1.LocalObjectReference{ @@ -953,7 +953,7 @@ func (c *Catalog) BuildRunWithSA(buildRunName string, buildName string, saName s }, ServiceAccount: &build.ServiceAccount{ Name: &saName, - Generate: pointer.Bool(false), + Generate: ptr.To[bool](false), }, }, Status: build.BuildRunStatus{}, @@ -971,7 +971,7 @@ func (c *Catalog) BuildRunWithoutSA(buildRunName string, buildName string) *buil Name: buildName, }, ServiceAccount: &build.ServiceAccount{ - Generate: pointer.Bool(false), + Generate: ptr.To[bool](false), }, }, } @@ -989,7 +989,7 @@ func (c *Catalog) BuildRunWithSAGenerate(buildRunName string, buildName string) Name: buildName, }, ServiceAccount: &build.ServiceAccount{ - Generate: pointer.Bool(true), + Generate: ptr.To[bool](true), }, }, } diff --git a/test/clusterbuildstrategy_samples.go b/test/v1alpha1_samples/clusterbuildstrategy_samples.go similarity index 99% rename from test/clusterbuildstrategy_samples.go rename to test/v1alpha1_samples/clusterbuildstrategy_samples.go index 1dc2739d73..26072420b3 100644 --- a/test/clusterbuildstrategy_samples.go +++ b/test/v1alpha1_samples/clusterbuildstrategy_samples.go @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package test +package testalpha // MinimalBuildahClusterBuildStrategy defines a // BuildStrategy for Buildah with two steps diff --git a/test/v1beta1_samples/build_samples.go b/test/v1beta1_samples/build_samples.go new file mode 100644 index 0000000000..20427ec0ce --- /dev/null +++ b/test/v1beta1_samples/build_samples.go @@ -0,0 +1,631 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package testbeta + +// MinimalBuildahBuildWithEnvVars defines a simple +// Build with a source, strategy, and env vars +const MinimalBuildahBuildWithEnvVars = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + name: buildah + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + env: + - name: MY_VAR_1 + value: "my-var-1-build-value" + - name: MY_VAR_2 + valueFrom: + fieldRef: + fieldPath: "my-fieldpath" +` + +// MinimalBuildahBuild defines a simple +// Build with a source and a strategy +const MinimalBuildahBuild = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + name: buildah + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile +` + +// BuildahBuildWithOutput defines a simple +// Build with a source, strategy and output +const BuildahBuildWithOutput = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah + namespace: build-test +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + name: buildah + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildahBuildWithAnnotationAndLabel defines a simple +// Build with a source, strategy, output, +// annotations and labels +const BuildahBuildWithAnnotationAndLabel = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + name: buildah + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + labels: + "maintainer": "team@my-company.com" + annotations: + "org.opencontainers.image.url": https://my-company.com/images +` + +// BuildahBuildWithMultipleAnnotationAndLabel defines a +// Build with a source, strategy, output, +// multiple annotations and labels +const BuildahBuildWithMultipleAnnotationAndLabel = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + name: buildah + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + labels: + "maintainer": "team@my-company.com" + "description": "This is my cool image" + annotations: + "org.opencontainers.image.url": https://my-company.com/images + "org.opencontainers.image.source": "https://github.com/org/repo" +` + +// BuildpacksBuildWithBuilderAndTimeOut defines a Build with +// source, strategy, builder, output and +// timeout +const BuildpacksBuildWithBuilderAndTimeOut = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildpacks-v3 + namespace: build-test +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + contextDir: docker-build + strategy: + name: buildpacks-v3 + kind: ClusterBuildStrategy + paramValues: + - name: dockerfile + value: Dockerfile + - name: builder-image + value: heroku/buildpacks:18 + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + timeout: 30s +` + +// BuildahBuildWithTimeOut defines a Build for +// Buildah with source, strategy, output and +// timeout +const BuildahBuildWithTimeOut = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: buildah + namespace: build-test +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + name: buildah + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + timeout: 30s +` + +// BuildBSMinimal defines a Build with a BuildStrategy +const BuildBSMinimal = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildBSMinimalNoSource defines a Build with a BuildStrategy without sources +const BuildBSMinimalNoSource = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: {} + strategy: + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildCBSMinimal defines a Build with a +// ClusterBuildStrategy +const BuildCBSMinimal = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + contextDir: docker-build + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildCBSMinimalWithFakeSecret defines a Build with a +// ClusterBuildStrategy and an not existing secret +const BuildCBSMinimalWithFakeSecret = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + pushSecret: fake-secret +` + +// BuildWithOutputRefSecret defines a Build with a +// referenced secret under spec.output +const BuildWithOutputRefSecret = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + pushSecret: output-secret + timeout: 5s +` + +// BuildWithSourceRefSecret defines a Build with a +// referenced secret under spec.source +const BuildWithSourceRefSecret = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + cloneSecret: source-secret + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + timeout: 5s +` + +// BuildWithBuilderRefSecret defines a Build with a +// referenced secret under spec.builder +const BuildWithBuilderRefSecret = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + paramValues: + - name: builder-image + value: heroku/buildpacks:18 + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + timeout: 5s +` + +// BuildWithMultipleRefSecrets defines a Build with +// multiple referenced secrets under spec +const BuildWithMultipleRefSecrets = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + cloneSecret: source-secret + paramValues: + - name: builder-image + value: heroku/buildpacks:18 + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + timeout: 5s +` + +// BuildCBSWithShortTimeOut defines a Build with a +// ClusterBuildStrategy and a short timeout +const BuildCBSWithShortTimeOut = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + timeout: 5s +` + +// BuildCBSWithShortTimeOutAndRefOutputSecret defines a Build with a +// ClusterBuildStrategy, a short timeout and an output secret +const BuildCBSWithShortTimeOutAndRefOutputSecret = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + pushSecret: foobarsecret + timeout: 5s +` + +// BuildCBSWithWrongURL defines a Build with a +// ClusterBuildStrategy and a non-existing url +const BuildCBSWithWrongURL = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + annotations: + build.shipwright.io/verify.repository: "true" +spec: + source: + git: + url: "https://github.foobar.com/sbose78/taxi" + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildCBSWithVerifyRepositoryAnnotation defines a Build +// with the verify repository annotation key +const BuildCBSWithVerifyRepositoryAnnotation = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + annotations: + build.shipwright.io/verify.repository: "" +spec: + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildCBSWithoutVerifyRepositoryAnnotation defines a minimal +// Build without source url and annotation +const BuildCBSWithoutVerifyRepositoryAnnotation = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildCBSWithBuildRunDeletion defines a Build with a +// ClusterBuildStrategy and the annotation for automatic BuildRun +// deletion +const BuildCBSWithBuildRunDeletion = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + strategy: + kind: ClusterBuildStrategy + retention: + atBuildDeletion: true + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildWithSleepTimeParam defines a Build with a parameter +const BuildWithSleepTimeParam = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + paramValues: + - name: sleep-time + value: "30" + strategy: + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildWithArrayParam defines a Build with an array parameter +const BuildWithArrayParam = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + paramValues: + - name: array-param + values: + - value: "3" + - value: "-1" + strategy: + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildWithConfigMapSecretParams defines a Build with parameter values referencing a ConfigMap and Secret +const BuildWithConfigMapSecretParams = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + paramValues: + - name: array-param + values: + - value: "3" + - configMapValue: + name: a-configmap + key: a-cm-key + - value: "-1" + - name: sleep-time + secretValue: + name: a-secret + key: a-secret-key + strategy: + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildWithRestrictedParam defines a Build using params that are reserved only +// for shipwright +const BuildWithRestrictedParam = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + paramValues: + - name: shp-something + value: "30" + - name: DOCKERFILE + value: "30" + strategy: + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildWithUndefinedParameter defines a param that was not declared under the +// strategy parameters +const BuildWithUndefinedParam = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + paramValues: + - name: sleep-not + value: "30" + strategy: + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildWithEmptyStringParam defines a param that with an empty string value +const BuildWithEmptyStringParam = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + paramValues: + - name: sleep-time + value: "" + strategy: + kind: BuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildWithUndefinedParamAndCBS defines a param that was not declared under the +// strategy parameters of a ClusterBuildStrategy +const BuildWithUndefinedParamAndCBS = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + paramValues: + - name: sleep-not + value: "30" + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// BuildWithSleepTimeParamAndCBS defines a Build with a parameter +const BuildWithSleepTimeParamAndCBS = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + paramValues: + - name: sleep-time + value: "30" + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// MinimalBuildWithRetentionTTLFive defines a simple +// Build with a source, a strategy and ttl +const MinimalBuildWithRetentionTTLFive = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: build-retention-ttl +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + contextDir: docker-build + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + retention: + ttlAfterFailed: 5s + ttlAfterSucceeded: 5s +` + +// MinimalBuildWithRetentionLimitOne defines a simple +// Build with a source, a strategy and limits set as 1 +const MinimalBuildWithRetentionLimitOne = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: build-retention-limit +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + contextDir: docker-build + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + retention: + failedLimit: 1 + succeededLimit: 1 +` + +// MinimalBuildWithRetentionLimitDiff defines a simple Build with a source, +// a strategy and different failed and succeeded limits +const MinimalBuildWithRetentionLimitDiff = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: build-retention-limit +spec: + source: + url: "https://github.com/shipwright-io/sample-go" + contextDir: docker-build + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + retention: + failedLimit: 1 + succeededLimit: 2 +` + +// MinimalBuildWithRetentionTTL defines a simple +// Build with a source, a strategy ttl +const MinimalBuildWithRetentionTTLOneMin = ` +apiVersion: shipwright.io/v1beta1 +kind: Build +metadata: + name: build-retention-ttl +spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + contextDir: docker-build + strategy: + kind: ClusterBuildStrategy + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app + retention: + ttlAfterFailed: 1m + ttlAfterSucceeded: 1m +` diff --git a/test/v1beta1_samples/buildrun_samples.go b/test/v1beta1_samples/buildrun_samples.go new file mode 100644 index 0000000000..0d8676400c --- /dev/null +++ b/test/v1beta1_samples/buildrun_samples.go @@ -0,0 +1,253 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package testbeta + +// MinimalBuildahBuildRunWithEnvVars defines a simple +// BuildRun with a referenced Build and env vars +const MinimalBuildahBuildRunWithEnvVars = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildah-run +spec: + build: + name: buildah + env: + - name: MY_VAR_2 + value: "my-var-2-buildrun-value" + - name: MY_VAR_3 + valueFrom: + fieldRef: + fieldPath: "my-fieldpath" +` + +// BuildahBuildRunWithOutputImageLabelsAndAnnotations defines a BuildRun +// with a output image labels and annotation +const BuildahBuildRunWithOutputImageLabelsAndAnnotations = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildah-run + namespace: build-test +spec: + build: + name: buildah + serviceAccount: buildpacks-v3-serviceaccount + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app-v2 + labels: + "maintainer": "new-team@my-company.com" + "foo": "bar" + annotations: + "org.opencontainers.owner": "my-company" +` + +// MinimalBuildahBuildRun defines a simple +// BuildRun with a referenced Build +const MinimalBuildahBuildRun = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildah-run +spec: + build: + name: buildah +` + +// BuildahBuildRunWithSA defines a BuildRun +// with a service-account +const BuildahBuildRunWithSA = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildah-run + namespace: build-test +spec: + build: + name: buildah + serviceAccount: buildpacks-v3-serviceaccount +` + +// BuildahBuildRunWithSAAndOutput defines a BuildRun +// with a service-account and output overrides +const BuildahBuildRunWithSAAndOutput = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildah-run + namespace: build-test +spec: + build: + name: buildah + serviceAccount: buildpacks-v3-serviceaccount + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app-v2 +` + +// BuildpacksBuildRunWithSA defines a BuildRun +// with a service-account +const BuildpacksBuildRunWithSA = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildpacks-v3-run + namespace: build-test +spec: + build: + name: buildpacks-v3 + serviceAccount: buildpacks-v3-serviceaccount +` + +// BuildahBuildRunWithTimeOutAndSA defines a BuildRun +// with a service-account and timeout +const BuildahBuildRunWithTimeOutAndSA = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildah-run + namespace: build-test +spec: + build: + name: buildah + serviceAccount: buildpacks-v3-serviceaccount + timeout: 1m +` + +// MinimalBuildRun defines a minimal BuildRun +// with a reference to a not existing Build +const MinimalBuildRun = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +spec: + build: + name: foobar +` + +const MinimalOneOffBuildRun = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: standalone-buildrun +spec: + build: + spec: + source: + git: + url: "https://github.com/shipwright-io/sample-go" + contextDir: docker-build + strategy: + kind: ClusterBuildStrategy + name: buildah + output: + image: image-registry.openshift-image-registry.svc:5000/example/buildpacks-app +` + +// MinimalBuildRunWithParams defines a param override +const MinimalBuildRunWithParams = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +spec: + paramValues: + - name: sleep-time + value: "15" + build: + name: foobar +` + +const MinimalBuildRunWithReservedParams = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +spec: + paramValues: + - name: shp-sleep-time + value: "15" + build: + name: foobar +` + +// MinimalBuildRunWithSpecifiedServiceAccount defines a minimal BuildRun +// with a reference to a not existing serviceAccount +const MinimalBuildRunWithSpecifiedServiceAccount = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +spec: + build: + name: buildah + serviceAccount: foobar +` + +// MinimalBuildRunWithSAGeneration defines a minimal BuildRun +// with a reference to a not existing Build +const MinimalBuildRunWithSAGeneration = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +spec: + serviceAccount: ".generate" + build: + name: foobar +` + +// MinimalBuildRunWithTimeOut defines a BuildRun with +// an override for the Build Timeout +const MinimalBuildRunWithTimeOut = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +spec: + timeout: 1s + build: + name: foobar +` + +// MinimalBuildRunWithOutput defines a BuildRun with +// an override for the Build Output +const MinimalBuildRunWithOutput = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +spec: + output: + image: foobar.registry.com + build: + name: foobar +` + +// MinimalBuildRunRetention defines a minimal BuildRun +// with a reference used to test retention fields +const MinimalBuildRunRetention = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buidrun-retention-ttl +spec: + build: + name: build-retention-ttl +` + +// MinimalBuildRunRetention defines a minimal BuildRun +// with a reference used to test retention fields +const MinimalBuildRunRetentionTTLFive = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buidrun-retention-ttl +spec: + build: + name: build-retention-ttl + retention: + ttlAfterFailed: 5s + ttlAfterSucceeded: 5s +` + +const MinimalBuildahBuildRunWithExitCode = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildRun +metadata: + name: buildah-run +spec: + paramValues: + - name: exit-command + value: "true" + build: + name: buildah +` diff --git a/test/v1beta1_samples/buildstrategy_samples.go b/test/v1beta1_samples/buildstrategy_samples.go new file mode 100644 index 0000000000..fcf19c81f9 --- /dev/null +++ b/test/v1beta1_samples/buildstrategy_samples.go @@ -0,0 +1,369 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package testbeta + +// MinimalBuildahBuildStrategy defines a +// BuildStrategy for Buildah with two steps +// each of them with different container resources +const MinimalBuildahBuildStrategy = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildStrategy +metadata: + name: buildah +spec: + volumes: + - name: buildah-images + emptyDir: {} + steps: + - name: buildah-bud + image: quay.io/containers/buildah:v1.31.0 + workingDir: $(params.shp-source-root) + securityContext: + privileged: true + command: + - /usr/bin/buildah + args: + - bud + - --tag=$(params.shp-output-image) + - --file=$(build.dockerfile) + - $(params.shp-source-context) + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 500m + memory: 1Gi + volumeMounts: + - name: buildah-images + mountPath: /var/lib/containers/storage + - name: buildah-push + image: quay.io/containers/buildah:v1.31.0 + securityContext: + privileged: true + command: + - /usr/bin/buildah + args: + - push + - --tls-verify=false + - docker://$(params.shp-output-image) + resources: + limits: + cpu: 100m + memory: 65Mi + requests: + cpu: 100m + memory: 65Mi + volumeMounts: + - name: buildah-images + mountPath: /var/lib/containers/storage +` + +// MinimalBuildahBuildStrategyWithEnvs defines a +// BuildStrategy for Buildah with two steps +// each of them with different container resources +// and env vars +const MinimalBuildahBuildStrategyWithEnvs = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildStrategy +metadata: + name: buildah +spec: + volumes: + - name: buildah-images + emptyDir: {} + steps: + - name: buildah-bud + image: quay.io/containers/buildah:v1.31.0 + workingDir: $(params.shp-source-root) + securityContext: + privileged: true + command: + - /usr/bin/buildah + args: + - bud + - --tag=$(params.shp-output-image) + - --file=$(build.dockerfile) + - $(params.shp-source-context) + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 500m + memory: 1Gi + volumeMounts: + - name: buildah-images + mountPath: /var/lib/containers/storage + env: + - name: MY_VAR_1 + value: "my-var-1-buildstrategy-value" + - name: MY_VAR_2 + valueFrom: + fieldRef: + fieldPath: "my-fieldpath" + - name: buildah-push + image: quay.io/containers/buildah:v1.31.0 + securityContext: + privileged: true + command: + - /usr/bin/buildah + args: + - push + - --tls-verify=false + - docker://$(params.shp-output-image) + resources: + limits: + cpu: 100m + memory: 65Mi + requests: + cpu: 100m + memory: 65Mi + volumeMounts: + - name: buildah-images + mountPath: /var/lib/containers/storage +` + +// BuildahBuildStrategySingleStep defines a +// BuildStrategy for Buildah with a single step +// and container resources +const BuildahBuildStrategySingleStep = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildStrategy +metadata: + annotations: + kubernetes.io/ingress-bandwidth: 1M + clusterbuildstrategy.shipwright.io/dummy: aValue + kubectl.kubernetes.io/last-applied-configuration: anotherValue + kubernetes.io/egress-bandwidth: 1M + name: buildah +spec: + volumes: + - name: varlibcontainers + emptyDir: {} + steps: + - name: build + image: "$(build.builder.image)" + workingDir: $(params.shp-source-root) + command: + - buildah + - bud + - --tls-verify=false + - --layers + - -f + - $(build.dockerfile) + - -t + - $(params.shp-output-image) + - $(params.shp-source-context) + resources: + limits: + cpu: 500m + memory: 2Gi + requests: + cpu: 500m + memory: 2Gi + volumeMounts: + - name: varlibcontainers + mountPath: /var/lib/containers +` + +// BuildpacksBuildStrategySingleStep defines a +// BuildStrategy for Buildpacks with a single step +// and container resources +const BuildpacksBuildStrategySingleStep = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildStrategy +metadata: + name: buildpacks-v3 +spec: + volumes: + - name: varlibcontainers + emptyDir: {} + steps: + - name: build + image: "$(build.builder.image)" + workingDir: $(params.shp-source-root) + command: + - /cnb/lifecycle/builder + - -app + - $(params.shp-source-context) + - -layers + - /layers + - -group + - /layers/group.toml + - plan + - /layers/plan.toml + resources: + limits: + cpu: 500m + memory: 2Gi + requests: + cpu: 500m + memory: 2Gi + volumeMounts: + - name: varlibcontainers + mountPath: /var/lib/containers +` + +// BuildStrategyWithParameters is a strategy that uses a +// sleep command with a value for its spec.parameters +const BuildStrategyWithParameters = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildStrategy +metadata: + name: strategy-with-param +spec: + parameters: + - name: sleep-time + description: "time in seconds for sleeping" + default: "1" + - name: array-param + description: "An arbitrary array" + type: array + defaults: [] + steps: + - name: sleep30 + image: alpine:latest + command: + - sleep + args: + - $(params.sleep-time) + - name: echo-array-sum + image: alpine:latest + command: + - /bin/bash + args: + - -c + - | + set -euo pipefail + + sum=0 + + for var in "$@" + do + sum=$((sum+var)) + done + + echo "Sum: ${sum}" + - -- + - $(params.array-param[*]) +` + +// BuildStrategyWithoutDefaultInParameter is a strategy that uses a +// sleep command with a value from its spec.parameters, where the parameter +// have no default +const BuildStrategyWithoutDefaultInParameter = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildStrategy +metadata: + name: strategy-with-param-and-no-default +spec: + parameters: + - name: sleep-time + description: "time in seconds for sleeping" + steps: + - name: sleep30 + image: alpine:latest + command: + - sleep + args: + - $(params.sleep-time) +` + +// BuildStrategyWithErrorResult is a strategy that always fails +// and surfaces and error reason and message to the user +const BuildStrategyWithErrorResult = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildStrategy +metadata: + name: strategy-with-error-results +spec: + steps: + - name: fail-with-error-result + image: alpine:latest + command: + - sh + args: + - -c + - | + printf "integration test error reason" > $(results.shp-error-reason.path); + printf "integration test error message" > $(results.shp-error-message.path); + return 1 +` + +// BuildStrategyWithParameterVerification is a strategy that verifies that parameters can be used at all expected places +const BuildStrategyWithParameterVerification = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildStrategy +metadata: + name: strategy-with-parameter-verification +spec: + parameters: + - name: env1 + description: "This parameter will be used in the env of the build step" + type: string + - name: env2 + description: "This parameter will be used in the env of the build step" + type: string + - name: env3 + description: "This parameter will be used in the env of the build step" + type: string + - name: image + description: "This parameter will be used as the image of the build step" + type: string + - name: commands + description: "This parameter will be used as the command of the build step" + type: array + - name: args + description: "This parameter will be used as the args of the build step" + type: array + steps: + - name: calculate-sum + image: $(params.image) + env: + - name: ENV_FROM_PARAMETER1 + value: $(params.env1) + - name: ENV_FROM_PARAMETER2 + value: $(params.env2) + - name: ENV_FROM_PARAMETER3 + value: $(params.env3) + command: + - $(params.commands[*]) + args: + - | + set -euo pipefail + + sum=$((ENV_FROM_PARAMETER1 + ENV_FROM_PARAMETER2 + ENV_FROM_PARAMETER3)) + + for var in "$@" + do + sum=$((sum+var)) + done + + echo "Sum: ${sum}" + # Once we have strategy-defined results, then those would be better suitable + # Until then, just store it as image size :-) + echo -n "${sum}" > '$(results.shp-image-size.path)' + - -- + - $(params.args[*]) +` + +// BuildStrategyWithoutPush is a strategy that writes an image tarball and pushes nothing +const BuildStrategyWithoutPush = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildStrategy +metadata: + name: strategy-without-push +spec: + steps: + - name: store-tarball + image: gcr.io/go-containerregistry/crane:v0.16.1 + command: + - crane + args: + - export + - busybox + - $(params.shp-output-directory)/image.tar +` diff --git a/test/v1beta1_samples/catalog.go b/test/v1beta1_samples/catalog.go new file mode 100644 index 0000000000..675ec595f6 --- /dev/null +++ b/test/v1beta1_samples/catalog.go @@ -0,0 +1,1092 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package testbeta + +import ( + "context" + "fmt" + "strconv" + "time" + + . "github.com/onsi/gomega" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "knative.dev/pkg/apis" + knativev1 "knative.dev/pkg/apis/duck/v1" + + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/resource" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" + "k8s.io/utils/ptr" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/yaml" + + build "github.com/shipwright-io/build/pkg/apis/build/v1beta1" +) + +// Catalog allows you to access helper functions +type Catalog struct{} + +// SecretWithAnnotation gives you a secret with build annotation +func (c *Catalog) SecretWithAnnotation(name string, ns string) *corev1.Secret { + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + Annotations: map[string]string{build.AnnotationBuildRefSecret: "true"}, + }, + } +} + +// SecretWithoutAnnotation gives you a secret without build annotation +func (c *Catalog) SecretWithoutAnnotation(name string, ns string) *corev1.Secret { + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + } +} + +// SecretWithStringData creates a Secret with stringData (not base64 encoded) +func (c *Catalog) SecretWithStringData(name string, ns string, stringData map[string]string) *corev1.Secret { + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + StringData: stringData, + } +} + +// SecretWithDockerConfigJson creates a secret of type dockerconfigjson +func (c *Catalog) SecretWithDockerConfigJson(name string, ns string, host string, username string, password string) *corev1.Secret { + return &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + Type: corev1.SecretTypeDockerConfigJson, + StringData: map[string]string{ + ".dockerconfigjson": fmt.Sprintf("{\"auths\":{%q:{\"username\":%q,\"password\":%q}}}", host, username, password), + }, + } +} + +// ConfigMapWithData creates a ConfigMap with data +func (c *Catalog) ConfigMapWithData(name string, ns string, data map[string]string) *corev1.ConfigMap { + return &corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + Data: data, + } +} + +// BuildWithClusterBuildStrategyAndFalseSourceAnnotation gives you an specific Build CRD +func (c *Catalog) BuildWithClusterBuildStrategyAndFalseSourceAnnotation(name string, ns string, strategyName string) *build.Build { + buildStrategy := build.ClusterBuildStrategyKind + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + Annotations: map[string]string{build.AnnotationBuildVerifyRepository: "false"}, + }, + Spec: build.BuildSpec{ + Source: build.Source{ + GitSource: &build.Git{ + URL: ptr.To[string]("foobar"), + }, + }, + Strategy: build.Strategy{ + Name: strategyName, + Kind: &buildStrategy, + }, + Output: build.Image{ + Image: "foobar", + }, + }, + } +} + +// BuildWithClusterBuildStrategy gives you an specific Build CRD +func (c *Catalog) BuildWithClusterBuildStrategy(name string, ns string, strategyName string, secretName string) *build.Build { + buildStrategy := build.ClusterBuildStrategyKind + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + Spec: build.BuildSpec{ + Source: build.Source{ + GitSource: &build.Git{ + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go"), + }, + }, + Strategy: build.Strategy{ + Name: strategyName, + Kind: &buildStrategy, + }, + Output: build.Image{ + Image: "foobar", + PushSecret: &secretName, + }, + }, + } +} + +// BuildWithClusterBuildStrategyAndSourceSecret gives you an specific Build CRD +func (c *Catalog) BuildWithClusterBuildStrategyAndSourceSecret(name string, ns string, strategyName string) *build.Build { + buildStrategy := build.ClusterBuildStrategyKind + secret := "foobar" + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + Spec: build.BuildSpec{ + Source: build.Source{ + GitSource: &build.Git{ + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go"), + CloneSecret: &secret, + }, + }, + Strategy: build.Strategy{ + Name: strategyName, + Kind: &buildStrategy, + }, + Output: build.Image{ + Image: "foobar", + }, + }, + } +} + +// BuildWithBuildStrategy gives you an specific Build CRD +func (c *Catalog) BuildWithBuildStrategy(name string, ns string, strategyName string) *build.Build { + buildStrategy := build.NamespacedBuildStrategyKind + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + Spec: build.BuildSpec{ + Source: build.Source{ + GitSource: &build.Git{ + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go"), + }, + }, + Strategy: build.Strategy{ + Name: strategyName, + Kind: &buildStrategy, + }, + }, + } +} + +// BuildWithNilBuildStrategyKind gives you an Build CRD with nil build strategy kind +func (c *Catalog) BuildWithNilBuildStrategyKind(name string, ns string, strategyName string) *build.Build { + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Namespace: ns, + }, + Spec: build.BuildSpec{ + Source: build.Source{ + GitSource: &build.Git{ + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go"), + }, + }, + Strategy: build.Strategy{ + Name: strategyName, + }, + }, + } +} + +// 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.Source{ + GitSource: &build.Git{ + URL: ptr.To[string]("https://github.com/shipwright-io/sample-go"), + }, + }, + Output: build.Image{ + PushSecret: &secretName, + }, + }, + } +} + +// ClusterBuildStrategy to support tests +func (c *Catalog) ClusterBuildStrategy(name string) *build.ClusterBuildStrategy { + return &build.ClusterBuildStrategy{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + } +} + +// FakeClusterBuildStrategyNotFound returns a not found error +func (c *Catalog) FakeClusterBuildStrategyNotFound(name string) error { + return errors.NewNotFound(schema.GroupResource{}, name) +} + +// StubFunc is used to simulate the status of the Build +// after a .Status().Update() call in the controller. This +// receives a parameter to return an specific status state +func (c *Catalog) StubFunc(status corev1.ConditionStatus, reason build.BuildReason, message string) func(context context.Context, object client.Object, _ ...client.UpdateOption) error { + return func(context context.Context, object client.Object, _ ...client.UpdateOption) error { + switch object := object.(type) { + case *build.Build: + Expect(*object.Status.Registered).To(Equal(status)) + Expect(*object.Status.Reason).To(Equal(reason)) + Expect(*object.Status.Message).To(Equal(message)) + } + return nil + } +} + +// StubBuildUpdateOwnerReferences simulates and assert an updated +// BuildRun object ownerreferences +func (c *Catalog) StubBuildUpdateOwnerReferences(ownerKind string, ownerName string, isOwnerController *bool, blockOwnerDeletion *bool) func(context context.Context, object client.Object, _ ...client.UpdateOption) error { + return func(context context.Context, object client.Object, _ ...client.UpdateOption) error { + switch object := object.(type) { + case *build.BuildRun: + Expect(object.OwnerReferences[0].Kind).To(Equal(ownerKind)) + Expect(object.OwnerReferences[0].Name).To(Equal(ownerName)) + Expect(object.OwnerReferences[0].Controller).To(Equal(isOwnerController)) + Expect(object.OwnerReferences[0].BlockOwnerDeletion).To(Equal(blockOwnerDeletion)) + Expect(len(object.OwnerReferences)).ToNot(Equal(0)) + } + return nil + } +} + +// StubBuildRun is used to simulate the existence of a BuildRun +// only when there is a client GET on this object type +func (c *Catalog) StubBuildRun( + b *build.BuildRun, +) func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + return func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + switch object := object.(type) { + case *build.BuildRun: + b.DeepCopyInto(object) + return nil + } + return errors.NewNotFound(schema.GroupResource{}, nn.Name) + } +} + +// StubBuildRunAndTaskRun is used to simulate the existence of a BuildRun +// and a TaskRun when there is a client GET on this two objects +func (c *Catalog) StubBuildRunAndTaskRun( + b *build.BuildRun, + tr *v1beta1.TaskRun, +) func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + return func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + switch object := object.(type) { + case *build.BuildRun: + b.DeepCopyInto(object) + return nil + case *v1beta1.TaskRun: + tr.DeepCopyInto(object) + return nil + } + return errors.NewNotFound(schema.GroupResource{}, nn.Name) + } +} + +// StubBuildAndTaskRun is used to simulate the existence of a Build +// and a TaskRun when there is a client GET on this two objects +func (c *Catalog) StubBuildAndTaskRun( + b *build.Build, + tr *v1beta1.TaskRun, +) func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + return func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + switch object := object.(type) { + case *build.Build: + b.DeepCopyInto(object) + return nil + case *v1beta1.TaskRun: + tr.DeepCopyInto(object) + return nil + } + return errors.NewNotFound(schema.GroupResource{}, nn.Name) + } +} + +// StubBuildStatusReason asserts Status fields on a Build resource +func (c *Catalog) StubBuildStatusReason(reason build.BuildReason, message string) func(context context.Context, object client.Object, _ ...client.UpdateOption) error { + return func(context context.Context, object client.Object, _ ...client.UpdateOption) error { + switch object := object.(type) { + case *build.Build: + if object.Status.Message != nil && *object.Status.Message != "" { + Expect(*object.Status.Message).To(Equal(message)) + } + if object.Status.Reason != nil && *object.Status.Reason != "" { + Expect(*object.Status.Reason).To(Equal(reason)) + } + } + return nil + } +} + +// StubBuildRunStatus asserts Status fields on a BuildRun resource +func (c *Catalog) StubBuildRunStatus(reason string, name *string, condition build.Condition, status corev1.ConditionStatus, buildSpec build.BuildSpec, tolerateEmptyStatus bool) func(context context.Context, object client.Object, _ ...client.UpdateOption) error { + return func(context context.Context, object client.Object, _ ...client.UpdateOption) error { + switch object := object.(type) { + case *build.BuildRun: + if !tolerateEmptyStatus { + Expect(object.Status.GetCondition(build.Succeeded).Status).To(Equal(condition.Status)) + Expect(object.Status.GetCondition(build.Succeeded).Reason).To(Equal(condition.Reason)) + Expect(object.Status.TaskRunName).To(Equal(name)) + } + if object.Status.BuildSpec != nil { + Expect(*object.Status.BuildSpec).To(Equal(buildSpec)) + } + } + return nil + } +} + +// StubBuildRunLabel asserts Label fields on a BuildRun resource +func (c *Catalog) StubBuildRunLabel(buildSample *build.Build) func(context context.Context, object client.Object, _ ...client.UpdateOption) error { + return func(context context.Context, object client.Object, _ ...client.UpdateOption) error { + switch object := object.(type) { + case *build.BuildRun: + Expect(object.Labels[build.LabelBuild]).To(Equal(buildSample.Name)) + Expect(object.Labels[build.LabelBuildGeneration]).To(Equal(strconv.FormatInt(buildSample.Generation, 10))) + } + return nil + } +} + +// StubBuildRunGetWithoutSA simulates the output of client GET calls +// for the BuildRun unit tests +func (c *Catalog) StubBuildRunGetWithoutSA( + b *build.Build, + br *build.BuildRun, +) func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + return func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + switch object := object.(type) { + case *build.Build: + b.DeepCopyInto(object) + return nil + case *build.BuildRun: + br.DeepCopyInto(object) + return nil + } + return errors.NewNotFound(schema.GroupResource{}, nn.Name) + } +} + +// StubBuildRunGetWithTaskRunAndSA returns fake object for different +// client calls +func (c *Catalog) StubBuildRunGetWithTaskRunAndSA( + b *build.Build, + br *build.BuildRun, + tr *v1beta1.TaskRun, + sa *corev1.ServiceAccount, +) func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + return func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + switch object := object.(type) { + case *build.Build: + b.DeepCopyInto(object) + return nil + case *build.BuildRun: + br.DeepCopyInto(object) + return nil + case *v1beta1.TaskRun: + tr.DeepCopyInto(object) + return nil + case *corev1.ServiceAccount: + sa.DeepCopyInto(object) + return nil + } + return errors.NewNotFound(schema.GroupResource{}, nn.Name) + } +} + +// StubBuildRunGetWithSA returns fake object for different +// client calls +func (c *Catalog) StubBuildRunGetWithSA( + b *build.Build, + br *build.BuildRun, + sa *corev1.ServiceAccount, +) func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + return func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + switch object := object.(type) { + case *build.Build: + b.DeepCopyInto(object) + return nil + case *build.BuildRun: + br.DeepCopyInto(object) + return nil + case *corev1.ServiceAccount: + sa.DeepCopyInto(object) + return nil + } + return errors.NewNotFound(schema.GroupResource{}, nn.Name) + } +} + +// StubBuildRunGetWithSAandStrategies simulates the output of client GET +// calls for the BuildRun unit tests +func (c *Catalog) StubBuildRunGetWithSAandStrategies( + b *build.Build, + br *build.BuildRun, + sa *corev1.ServiceAccount, + cb *build.ClusterBuildStrategy, + bs *build.BuildStrategy, +) func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + return func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + switch object := object.(type) { + case *build.Build: + if b != nil { + b.DeepCopyInto(object) + return nil + } + case *build.BuildRun: + if br != nil { + br.DeepCopyInto(object) + return nil + } + case *corev1.ServiceAccount: + if sa != nil { + sa.DeepCopyInto(object) + return nil + } + case *build.ClusterBuildStrategy: + if cb != nil { + cb.DeepCopyInto(object) + return nil + } + case *build.BuildStrategy: + if bs != nil { + bs.DeepCopyInto(object) + return nil + } + } + return errors.NewNotFound(schema.GroupResource{}, nn.Name) + } +} + +func (c *Catalog) StubBuildCRDs( + b *build.Build, + br *build.BuildRun, + sa *corev1.ServiceAccount, + cb *build.ClusterBuildStrategy, + bs *build.BuildStrategy, +) func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + return func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + switch object := object.(type) { + case *build.Build: + b.DeepCopyInto(object) + return nil + case *build.BuildRun: + br.DeepCopyInto(object) + return nil + case *corev1.ServiceAccount: + sa.DeepCopyInto(object) + return nil + case *build.ClusterBuildStrategy: + cb.DeepCopyInto(object) + return nil + case *build.BuildStrategy: + bs.DeepCopyInto(object) + return nil + } + return errors.NewNotFound(schema.GroupResource{}, nn.Name) + } +} + +// StubBuildCRDsPodAndTaskRun stubs different objects in case a client +// GET call is executed against them +func (c *Catalog) StubBuildCRDsPodAndTaskRun( + b *build.Build, + br *build.BuildRun, + sa *corev1.ServiceAccount, + cb *build.ClusterBuildStrategy, + bs *build.BuildStrategy, + tr *v1beta1.TaskRun, + pod *corev1.Pod, +) func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + return func(context context.Context, nn types.NamespacedName, object client.Object, getOptions ...client.GetOption) error { + switch object := object.(type) { + case *build.Build: + b.DeepCopyInto(object) + return nil + case *build.BuildRun: + br.DeepCopyInto(object) + return nil + case *corev1.ServiceAccount: + sa.DeepCopyInto(object) + return nil + case *build.ClusterBuildStrategy: + cb.DeepCopyInto(object) + return nil + case *build.BuildStrategy: + bs.DeepCopyInto(object) + return nil + case *v1beta1.TaskRun: + tr.DeepCopyInto(object) + return nil + case *corev1.Pod: + pod.DeepCopyInto(object) + return nil + } + return errors.NewNotFound(schema.GroupResource{}, nn.Name) + } +} + +// 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: knativev1.Status{ + Conditions: knativev1.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{ + ObjectMeta: metav1.ObjectMeta{ + Name: trName, + Namespace: ns, + Labels: map[string]string{"buildrun.shipwright.io/name": buildRunName}, + }, + Spec: v1beta1.TaskRunSpec{}, + Status: v1beta1.TaskRunStatus{ + Status: knativev1.Status{ + Conditions: knativev1.Conditions{ + { + Type: apis.ConditionSucceeded, + Reason: reason, + Status: status, + }, + }, + }, + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + StartTime: &metav1.Time{ + Time: time.Now(), + }, + }, + }, + } +} + +// TaskRunWithCompletionAndStartTime provides a TaskRun object with a +// Completion and StartTime +func (c *Catalog) TaskRunWithCompletionAndStartTime(trName string, buildRunName string, ns string) *v1beta1.TaskRun { + return &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: trName, + Namespace: ns, + Labels: map[string]string{"buildrun.shipwright.io/name": buildRunName}, + }, + Spec: v1beta1.TaskRunSpec{}, + Status: v1beta1.TaskRunStatus{ + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + CompletionTime: &metav1.Time{ + Time: time.Now(), + }, + StartTime: &metav1.Time{ + Time: time.Now(), + }, + PodName: "foobar", + }, + Status: knativev1.Status{ + Conditions: knativev1.Conditions{ + { + Type: apis.ConditionSucceeded, + Reason: "something bad happened", + Status: corev1.ConditionFalse, + Message: "some message", + }, + }, + }, + }, + } +} + +// DefaultTaskRunWithFalseStatus returns a minimal tektont TaskRun with a FALSE status +func (c *Catalog) DefaultTaskRunWithFalseStatus(trName string, buildRunName string, ns string) *v1beta1.TaskRun { + return &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: trName, + Namespace: ns, + Labels: map[string]string{"buildrun.shipwright.io/name": buildRunName}, + }, + Spec: v1beta1.TaskRunSpec{}, + Status: v1beta1.TaskRunStatus{ + Status: knativev1.Status{ + Conditions: knativev1.Conditions{ + { + Type: apis.ConditionSucceeded, + Reason: "something bad happened", + Status: corev1.ConditionFalse, + Message: "some message", + }, + }, + }, + TaskRunStatusFields: v1beta1.TaskRunStatusFields{ + StartTime: &metav1.Time{ + Time: time.Now(), + }, + }, + }, + } +} + +// DefaultBuild returns a minimal Build object +func (c *Catalog) DefaultBuild(buildName string, strategyName string, strategyKind build.BuildStrategyKind) *build.Build { + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildName, + }, + Spec: build.BuildSpec{ + Strategy: build.Strategy{ + Name: strategyName, + Kind: &strategyKind, + }, + }, + Status: build.BuildStatus{ + Registered: build.ConditionStatusPtr(corev1.ConditionTrue), + }, + } +} + +// BuildWithoutStrategyKind returns a minimal Build object without an strategy kind definition +func (c *Catalog) BuildWithoutStrategyKind(buildName string, strategyName string) *build.Build { + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildName, + }, + Spec: build.BuildSpec{ + Strategy: build.Strategy{ + Name: strategyName, + }, + }, + Status: build.BuildStatus{ + Registered: build.ConditionStatusPtr(corev1.ConditionTrue), + }, + } +} + +// BuildWithBuildRunDeletions returns a minimal Build object with the +// build.shipwright.io/build-run-deletion annotation set to true +func (c *Catalog) BuildWithBuildRunDeletions(buildName string, strategyName string, strategyKind build.BuildStrategyKind) *build.Build { + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildName, + }, + Spec: build.BuildSpec{ + Strategy: build.Strategy{ + Name: strategyName, + Kind: &strategyKind, + }, + Retention: &build.BuildRetention{ + AtBuildDeletion: ptr.To[bool](true), + }, + }, + Status: build.BuildStatus{ + Registered: build.ConditionStatusPtr(corev1.ConditionTrue), + }, + } +} + +// BuildWithBuildRunDeletionsAndFakeNS returns a minimal Build object with the +// build.shipwright.io/build-run-deletion annotation set to true in a fake namespace +func (c *Catalog) BuildWithBuildRunDeletionsAndFakeNS(buildName string, strategyName string, strategyKind build.BuildStrategyKind) *build.Build { + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildName, + Namespace: "fakens", + }, + Spec: build.BuildSpec{ + Strategy: build.Strategy{ + Name: strategyName, + Kind: &strategyKind, + }, + Retention: &build.BuildRetention{ + AtBuildDeletion: ptr.To[bool](true), + }, + }, + Status: build.BuildStatus{ + Registered: build.ConditionStatusPtr(corev1.ConditionTrue), + }, + } +} + +// DefaultBuildWithFalseRegistered returns a minimal Build object with a FALSE Registered +func (c *Catalog) DefaultBuildWithFalseRegistered(buildName string, strategyName string, strategyKind build.BuildStrategyKind) *build.Build { + return &build.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildName, + }, + Spec: build.BuildSpec{ + Strategy: build.Strategy{ + Name: strategyName, + Kind: &strategyKind, + }, + }, + Status: build.BuildStatus{ + Registered: build.ConditionStatusPtr(corev1.ConditionFalse), + Reason: build.BuildReasonPtr("something bad happened"), + }, + } +} + +// DefaultBuildRun returns a minimal BuildRun object +func (c *Catalog) DefaultBuildRun(buildRunName string, buildName string) *build.BuildRun { + var defaultBuild = c.DefaultBuild(buildName, "foobar-strategy", build.ClusterBuildStrategyKind) + return &build.BuildRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildRunName, + }, + Spec: build.BuildRunSpec{ + Build: &build.ReferencedBuild{ + Name: buildName, + }, + }, + Status: build.BuildRunStatus{ + BuildSpec: &defaultBuild.Spec, + }, + } +} + +// PodWithInitContainerStatus returns a pod with a single +// entry under the Status field for InitContainer Status +func (c *Catalog) PodWithInitContainerStatus(podName string, initContainerName string) *corev1.Pod { + return &corev1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: podName, + }, + Status: corev1.PodStatus{ + InitContainerStatuses: []corev1.ContainerStatus{ + { + Name: initContainerName, + }, + }, + }, + } +} + +// BuildRunWithBuildSnapshot returns BuildRun Object with a populated +// BuildSpec in the Status field +func (c *Catalog) BuildRunWithBuildSnapshot(buildRunName string, buildName string) *build.BuildRun { + return &build.BuildRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildRunName, + CreationTimestamp: metav1.Time{ + Time: time.Now(), + }, + }, + Status: build.BuildRunStatus{ + BuildSpec: &build.BuildSpec{ + Strategy: build.Strategy{ + Name: "foobar", + }, + }, + }, + Spec: build.BuildRunSpec{ + Build: &build.ReferencedBuild{ + Name: buildName, + }, + }, + } +} + +// BuildRunWithExistingOwnerReferences returns a BuildRun object that is +// already owned by some fake object +func (c *Catalog) BuildRunWithExistingOwnerReferences(buildRunName string, buildName string, ownerName string) *build.BuildRun { + + managingController := true + + fakeOwnerRef := metav1.OwnerReference{ + APIVersion: ownerName, + Kind: ownerName, + Controller: &managingController, + } + + return &build.BuildRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildRunName, + OwnerReferences: []metav1.OwnerReference{fakeOwnerRef}, + }, + Spec: build.BuildRunSpec{ + Build: &build.ReferencedBuild{ + Name: buildName, + }, + }, + } +} + +// BuildRunWithFakeNamespace returns a BuildRun object with +// a namespace that does not exist +func (c *Catalog) BuildRunWithFakeNamespace(buildRunName string, buildName string) *build.BuildRun { + return &build.BuildRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildRunName, + Namespace: "foobarns", + }, + Spec: build.BuildRunSpec{ + Build: &build.ReferencedBuild{ + Name: buildName, + }, + }, + } +} + +// DefaultTaskRun returns a minimal TaskRun object +func (c *Catalog) DefaultTaskRun(taskRunName string, ns string) *v1beta1.TaskRun { + return &v1beta1.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: taskRunName, + Namespace: ns, + }, + } +} + +// DefaultServiceAccount returns a minimal SA object +func (c *Catalog) DefaultServiceAccount(name string) *corev1.ServiceAccount { + return &corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + }, + } +} + +// 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 { + return &build.ClusterBuildStrategy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foobar", + }, + } +} + +// DefaultNamespacedBuildStrategy returns a minimal BuildStrategy +// object with a inmutable name +func (c *Catalog) DefaultNamespacedBuildStrategy() *build.BuildStrategy { + return &build.BuildStrategy{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foobar", + }, + } +} + +// BuildRunWithSucceededCondition returns a BuildRun with a single condition +// of the type Succeeded +func (c *Catalog) BuildRunWithSucceededCondition() *build.BuildRun { + return &build.BuildRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foobar", + }, + Status: build.BuildRunStatus{ + Conditions: build.Conditions{ + build.Condition{ + Type: build.Succeeded, + Reason: "foobar", + Message: "foo is not bar", + Status: corev1.ConditionUnknown, + }, + }, + }, + } +} + +// BuildRunWithSA returns a customized BuildRun object that defines a +// service account +func (c *Catalog) BuildRunWithSA(buildRunName string, buildName string, saName string) *build.BuildRun { + return &build.BuildRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildRunName, + }, + Spec: build.BuildRunSpec{ + Build: &build.ReferencedBuild{ + Name: buildName, + }, + ServiceAccount: &saName, + }, + Status: build.BuildRunStatus{}, + } +} + +// BuildRunWithoutSA returns a buildrun without serviceAccountName and generate serviceAccount is false +func (c *Catalog) BuildRunWithoutSA(buildRunName string, buildName string) *build.BuildRun { + return &build.BuildRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildRunName, + }, + Spec: build.BuildRunSpec{ + Build: &build.ReferencedBuild{ + Name: buildName, + }, + ServiceAccount: nil, + }, + } +} + +// BuildRunWithSAGenerate returns a customized BuildRun object that defines a +// service account +func (c *Catalog) BuildRunWithSAGenerate(buildRunName string, buildName string) *build.BuildRun { + return &build.BuildRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildRunName, + }, + Spec: build.BuildRunSpec{ + Build: &build.ReferencedBuild{ + Name: buildName, + }, + ServiceAccount: ptr.To[string](".generate"), + }, + } +} + +// LoadCustomResources returns a container set of resources based on cpu and memory +func (c *Catalog) LoadCustomResources(cpu string, mem string) corev1.ResourceRequirements { + return corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse(cpu), + corev1.ResourceMemory: resource.MustParse(mem), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse(cpu), + corev1.ResourceMemory: resource.MustParse(mem), + }, + } +} + +// LoadBuildYAML parses YAML bytes into JSON and from JSON +// into a Build struct +func (c *Catalog) LoadBuildYAML(d []byte) (*build.Build, error) { + b := &build.Build{} + err := yaml.Unmarshal(d, b) + if err != nil { + return nil, err + } + return b, nil +} + +// LoadBuildWithNameAndStrategy returns a populated Build with name and a referenced strategy +func (c *Catalog) LoadBuildWithNameAndStrategy(name string, strategy string, d []byte) (*build.Build, error) { + b := &build.Build{} + err := yaml.Unmarshal(d, b) + if err != nil { + return nil, err + } + b.Name = name + b.Spec.Strategy.Name = strategy + return b, nil +} + +// LoadBuildRunFromBytes returns a populated BuildRun +func (c *Catalog) LoadBuildRunFromBytes(d []byte) (*build.BuildRun, error) { + b := &build.BuildRun{} + err := yaml.Unmarshal(d, b) + if err != nil { + return nil, err + } + return b, nil +} + +// LoadBRWithNameAndRef returns a populated BuildRun with a name and a referenced Build +func (c *Catalog) LoadBRWithNameAndRef(name string, buildName string, d []byte) (*build.BuildRun, error) { + b := &build.BuildRun{} + err := yaml.Unmarshal(d, b) + if err != nil { + return nil, err + } + b.Name = name + b.Spec.Build.Name = buildName + return b, nil +} + +func (c *Catalog) LoadStandAloneBuildRunWithNameAndStrategy(name string, strategy *build.ClusterBuildStrategy, d []byte) (*build.BuildRun, error) { + b := &build.BuildRun{} + err := yaml.Unmarshal(d, b) + if err != nil { + return nil, err + } + b.Name = name + b.Spec.Build.Build.Strategy = build.Strategy{Kind: (*build.BuildStrategyKind)(&strategy.Kind), Name: strategy.Name} + + return b, nil +} + +// LoadBuildStrategyFromBytes returns a populated BuildStrategy +func (c *Catalog) LoadBuildStrategyFromBytes(d []byte) (*build.BuildStrategy, error) { + b := &build.BuildStrategy{} + err := yaml.Unmarshal(d, b) + if err != nil { + return nil, err + } + return b, nil +} + +// LoadCBSWithName returns a populated ClusterBuildStrategy with a name +func (c *Catalog) LoadCBSWithName(name string, d []byte) (*build.ClusterBuildStrategy, error) { + b := &build.ClusterBuildStrategy{} + err := yaml.Unmarshal(d, b) + if err != nil { + return nil, err + } + b.Name = name + return b, nil +} diff --git a/test/v1beta1_samples/clusterbuildstrategy_samples.go b/test/v1beta1_samples/clusterbuildstrategy_samples.go new file mode 100644 index 0000000000..2f9a6a22f5 --- /dev/null +++ b/test/v1beta1_samples/clusterbuildstrategy_samples.go @@ -0,0 +1,358 @@ +// Copyright The Shipwright Contributors +// +// SPDX-License-Identifier: Apache-2.0 + +package testbeta + +// MinimalBuildahClusterBuildStrategy defines a +// BuildStrategy for Buildah with two steps +// each of them with different container resources +const MinimalBuildahClusterBuildStrategy = ` +apiVersion: shipwright.io/v1beta1 +kind: BuildStrategy +metadata: + name: buildah +spec: + volumes: + - name: buildah-images + volumeSource: + emptyDir: {} + buildSteps: + - name: buildah-bud + image: quay.io/containers/buildah:v1.31.0 + workingDir: $(params.shp-source-root) + securityContext: + privileged: true + command: + - /usr/bin/buildah + args: + - bud + - --tag=$(params.shp-output-image) + - --file=$(build.dockerfile) + - $(params.shp-source-context) + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 500m + memory: 1Gi + volumeMounts: + - name: buildah-images + mountPath: /var/lib/containers/storage + - name: buildah-push + image: quay.io/containers/buildah:v1.31.0 + securityContext: + privileged: true + command: + - /usr/bin/buildah + args: + - push + - --tls-verify=false + - docker://$(params.shp-output-image) + resources: + limits: + cpu: 100m + memory: 65Mi + requests: + cpu: 100m + memory: 65Mi + volumeMounts: + - name: buildah-images + mountPath: /var/lib/containers/storage +` + +// ClusterBuildStrategySingleStep defines a +// BuildStrategy for Buildah with a single step +// and container resources +const ClusterBuildStrategySingleStep = ` +apiVersion: shipwright.io/v1beta1 +kind: ClusterBuildStrategy +metadata: + name: buildah +spec: + volumes: + - name: buildah-images + volumeSource: + emptyDir: {} + buildSteps: + - name: buildah-bud + image: quay.io/containers/buildah:v1.31.0 + workingDir: $(params.shp-source-root) + securityContext: + privileged: true + command: + - /usr/bin/buildah + args: + - bud + - --tag=$(params.shp-output-image) + - --file=$(build.dockerfile) + - $(params.shp-source-context) + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + volumeMounts: + - name: buildah-images + mountPath: /var/lib/containers/storage + - name: buildah-push + image: quay.io/containers/buildah:v1.31.0 + securityContext: + privileged: true + command: + - /usr/bin/buildah + args: + - push + - --tls-verify=false + - docker://$(params.shp-output-image) + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi + volumeMounts: + - name: buildah-images + mountPath: /var/lib/containers/storage +` + +// ClusterBuildStrategySingleStepKaniko is a cluster build strategy based on +// Kaniko, which is very close to the actual Kaniko build strategy example in +// the project +const ClusterBuildStrategySingleStepKaniko = ` +apiVersion: shipwright.io/v1beta1 +kind: ClusterBuildStrategy +metadata: + name: kaniko +spec: + buildSteps: + - name: step-build-and-push + image: gcr.io/kaniko-project/executor:v1.15.0 + workingDir: $(params.shp-source-root) + securityContext: + runAsUser: 0 + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --skip-tls-verify=true + - --dockerfile=$(build.dockerfile) + - --context=$(params.shp-source-context) + - --destination=$(params.shp-output-image) + - --snapshot-mode=redo + - --push-retry=3 + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi +` + +// ClusterBuildStrategySingleStepKanikoError is a Kaniko based cluster build +// strategy that has a configuration error (misspelled command flag) so that +// it will fail in Tekton +const ClusterBuildStrategySingleStepKanikoError = ` +apiVersion: shipwright.io/v1beta1 +kind: ClusterBuildStrategy +metadata: + name: kaniko +spec: + buildSteps: + - name: step-build-and-push + image: gcr.io/kaniko-project/executor:v1.15.0 + workingDir: $(params.shp-source-root) + securityContext: + runAsUser: 0 + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --skips-tlss-verifys=true + - --dockerfile=$(build.dockerfile) + - --context=$(params.shp-source-context) + - --destination=$(params.shp-output-image) + - --snapshot-mode=redo + - --push-retry=3 + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi +` + +// ClusterBuildStrategyNoOp is a strategy that does nothing and has no dependencies +const ClusterBuildStrategyNoOp = ` +apiVersion: shipwright.io/v1beta1 +kind: ClusterBuildStrategy +metadata: + name: noop +spec: + parameters: + - name: exit-command + description: "Exit command for the pod" + default: "true" + buildSteps: + - name: step-no-and-op + image: alpine:latest + workingDir: $(params.shp-source-root) + securityContext: + runAsUser: 0 + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - $(params.exit-command) + resources: + limits: + cpu: 250m + memory: 128Mi + requests: + cpu: 250m + memory: 128Mi +` + +// ClusterBuildStrategySleep30s is a strategy that does only sleep 30 seconds +const ClusterBuildStrategySleep30s = ` +apiVersion: build.dev/v1beta1 +kind: ClusterBuildStrategy +metadata: + name: noop +spec: + buildSteps: + - name: sleep30 + image: alpine:latest + command: + - sleep + args: + - "30s" + resources: + limits: + cpu: 250m + memory: 128Mi + requests: + cpu: 250m + memory: 128Mi +` + +// ClusterBuildStrategyWithAnnotations is a cluster build strategy that contains annotations +const ClusterBuildStrategyWithAnnotations = ` +apiVersion: shipwright.io/v1beta1 +kind: ClusterBuildStrategy +metadata: + annotations: + kubernetes.io/ingress-bandwidth: 1M + clusterbuildstrategy.shipwright.io/dummy: aValue + kubectl.kubernetes.io/last-applied-configuration: anotherValue + name: kaniko +spec: + buildSteps: + - name: step-build-and-push + image: gcr.io/kaniko-project/executor:v1.15.0 + workingDir: $(params.shp-source-root) + securityContext: + runAsUser: 0 + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + - SETFCAP + - KILL + env: + - name: DOCKER_CONFIG + value: /tekton/home/.docker + - name: AWS_ACCESS_KEY_ID + value: NOT_SET + - name: AWS_SECRET_KEY + value: NOT_SET + command: + - /kaniko/executor + args: + - --skip-tls-verify=true + - --dockerfile=$(build.dockerfile) + - --context=$(params.shp-source-root) + - --destination=$(params.shp-output-image) + - --snapshot-mode=redo + - --push-retry=3 + resources: + limits: + cpu: 500m + memory: 1Gi + requests: + cpu: 250m + memory: 65Mi +` + +// ClusterBuildStrategyWithParameters is a strategy that uses a +// sleep command with a value for its spec.parameters +const ClusterBuildStrategyWithParameters = ` +apiVersion: build.dev/v1beta1 +kind: ClusterBuildStrategy +metadata: + name: strategy-with-param +spec: + parameters: + - name: sleep-time + description: "time in seconds for sleeping" + default: "1" + buildSteps: + - name: sleep30 + image: alpine:latest + command: + - sleep + args: + - $(params.sleep-time) +` diff --git a/vendor/k8s.io/utils/pointer/pointer.go b/vendor/k8s.io/utils/pointer/pointer.go index b8103223ad..b673a64257 100644 --- a/vendor/k8s.io/utils/pointer/pointer.go +++ b/vendor/k8s.io/utils/pointer/pointer.go @@ -14,12 +14,15 @@ See the License for the specific language governing permissions and limitations under the License. */ +// Deprecated: Use functions in k8s.io/utils/ptr instead: ptr.To to obtain +// a pointer, ptr.Deref to dereference a pointer, ptr.Equal to compare +// dereferenced pointers. package pointer import ( - "fmt" - "reflect" "time" + + "k8s.io/utils/ptr" ) // AllPtrFieldsNil tests whether all pointer fields in a struct are nil. This is useful when, @@ -28,383 +31,219 @@ import ( // // This function is only valid for structs and pointers to structs. Any other // type will cause a panic. Passing a typed nil pointer will return true. -func AllPtrFieldsNil(obj interface{}) bool { - v := reflect.ValueOf(obj) - if !v.IsValid() { - panic(fmt.Sprintf("reflect.ValueOf() produced a non-valid Value for %#v", obj)) - } - if v.Kind() == reflect.Ptr { - if v.IsNil() { - return true - } - v = v.Elem() - } - for i := 0; i < v.NumField(); i++ { - if v.Field(i).Kind() == reflect.Ptr && !v.Field(i).IsNil() { - return false - } - } - return true -} - -// Int returns a pointer to an int -func Int(i int) *int { - return &i -} +// +// Deprecated: Use ptr.AllPtrFieldsNil instead. +var AllPtrFieldsNil = ptr.AllPtrFieldsNil + +// Int returns a pointer to an int. +var Int = ptr.To[int] // IntPtr is a function variable referring to Int. // -// Deprecated: Use Int instead. +// Deprecated: Use ptr.To instead. var IntPtr = Int // for back-compat // IntDeref dereferences the int ptr and returns it if not nil, or else // returns def. -func IntDeref(ptr *int, def int) int { - if ptr != nil { - return *ptr - } - return def -} +var IntDeref = ptr.Deref[int] // IntPtrDerefOr is a function variable referring to IntDeref. // -// Deprecated: Use IntDeref instead. +// Deprecated: Use ptr.Deref instead. var IntPtrDerefOr = IntDeref // for back-compat // Int32 returns a pointer to an int32. -func Int32(i int32) *int32 { - return &i -} +var Int32 = ptr.To[int32] // Int32Ptr is a function variable referring to Int32. // -// Deprecated: Use Int32 instead. +// Deprecated: Use ptr.To instead. var Int32Ptr = Int32 // for back-compat // Int32Deref dereferences the int32 ptr and returns it if not nil, or else // returns def. -func Int32Deref(ptr *int32, def int32) int32 { - if ptr != nil { - return *ptr - } - return def -} +var Int32Deref = ptr.Deref[int32] // Int32PtrDerefOr is a function variable referring to Int32Deref. // -// Deprecated: Use Int32Deref instead. +// Deprecated: Use ptr.Deref instead. var Int32PtrDerefOr = Int32Deref // for back-compat // Int32Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Int32Equal(a, b *int32) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Int32Equal = ptr.Equal[int32] // Uint returns a pointer to an uint -func Uint(i uint) *uint { - return &i -} +var Uint = ptr.To[uint] // UintPtr is a function variable referring to Uint. // -// Deprecated: Use Uint instead. +// Deprecated: Use ptr.To instead. var UintPtr = Uint // for back-compat // UintDeref dereferences the uint ptr and returns it if not nil, or else // returns def. -func UintDeref(ptr *uint, def uint) uint { - if ptr != nil { - return *ptr - } - return def -} +var UintDeref = ptr.Deref[uint] // UintPtrDerefOr is a function variable referring to UintDeref. // -// Deprecated: Use UintDeref instead. +// Deprecated: Use ptr.Deref instead. var UintPtrDerefOr = UintDeref // for back-compat // Uint32 returns a pointer to an uint32. -func Uint32(i uint32) *uint32 { - return &i -} +var Uint32 = ptr.To[uint32] // Uint32Ptr is a function variable referring to Uint32. // -// Deprecated: Use Uint32 instead. +// Deprecated: Use ptr.To instead. var Uint32Ptr = Uint32 // for back-compat // Uint32Deref dereferences the uint32 ptr and returns it if not nil, or else // returns def. -func Uint32Deref(ptr *uint32, def uint32) uint32 { - if ptr != nil { - return *ptr - } - return def -} +var Uint32Deref = ptr.Deref[uint32] // Uint32PtrDerefOr is a function variable referring to Uint32Deref. // -// Deprecated: Use Uint32Deref instead. +// Deprecated: Use ptr.Deref instead. var Uint32PtrDerefOr = Uint32Deref // for back-compat // Uint32Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Uint32Equal(a, b *uint32) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Uint32Equal = ptr.Equal[uint32] // Int64 returns a pointer to an int64. -func Int64(i int64) *int64 { - return &i -} +var Int64 = ptr.To[int64] // Int64Ptr is a function variable referring to Int64. // -// Deprecated: Use Int64 instead. +// Deprecated: Use ptr.To instead. var Int64Ptr = Int64 // for back-compat // Int64Deref dereferences the int64 ptr and returns it if not nil, or else // returns def. -func Int64Deref(ptr *int64, def int64) int64 { - if ptr != nil { - return *ptr - } - return def -} +var Int64Deref = ptr.Deref[int64] // Int64PtrDerefOr is a function variable referring to Int64Deref. // -// Deprecated: Use Int64Deref instead. +// Deprecated: Use ptr.Deref instead. var Int64PtrDerefOr = Int64Deref // for back-compat // Int64Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Int64Equal(a, b *int64) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Int64Equal = ptr.Equal[int64] // Uint64 returns a pointer to an uint64. -func Uint64(i uint64) *uint64 { - return &i -} +var Uint64 = ptr.To[uint64] // Uint64Ptr is a function variable referring to Uint64. // -// Deprecated: Use Uint64 instead. +// Deprecated: Use ptr.To instead. var Uint64Ptr = Uint64 // for back-compat // Uint64Deref dereferences the uint64 ptr and returns it if not nil, or else // returns def. -func Uint64Deref(ptr *uint64, def uint64) uint64 { - if ptr != nil { - return *ptr - } - return def -} +var Uint64Deref = ptr.Deref[uint64] // Uint64PtrDerefOr is a function variable referring to Uint64Deref. // -// Deprecated: Use Uint64Deref instead. +// Deprecated: Use ptr.Deref instead. var Uint64PtrDerefOr = Uint64Deref // for back-compat // Uint64Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Uint64Equal(a, b *uint64) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Uint64Equal = ptr.Equal[uint64] // Bool returns a pointer to a bool. -func Bool(b bool) *bool { - return &b -} +var Bool = ptr.To[bool] // BoolPtr is a function variable referring to Bool. // -// Deprecated: Use Bool instead. +// Deprecated: Use ptr.To instead. var BoolPtr = Bool // for back-compat // BoolDeref dereferences the bool ptr and returns it if not nil, or else // returns def. -func BoolDeref(ptr *bool, def bool) bool { - if ptr != nil { - return *ptr - } - return def -} +var BoolDeref = ptr.Deref[bool] // BoolPtrDerefOr is a function variable referring to BoolDeref. // -// Deprecated: Use BoolDeref instead. +// Deprecated: Use ptr.Deref instead. var BoolPtrDerefOr = BoolDeref // for back-compat // BoolEqual returns true if both arguments are nil or both arguments // dereference to the same value. -func BoolEqual(a, b *bool) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var BoolEqual = ptr.Equal[bool] // String returns a pointer to a string. -func String(s string) *string { - return &s -} +var String = ptr.To[string] // StringPtr is a function variable referring to String. // -// Deprecated: Use String instead. +// Deprecated: Use ptr.To instead. var StringPtr = String // for back-compat // StringDeref dereferences the string ptr and returns it if not nil, or else // returns def. -func StringDeref(ptr *string, def string) string { - if ptr != nil { - return *ptr - } - return def -} +var StringDeref = ptr.Deref[string] // StringPtrDerefOr is a function variable referring to StringDeref. // -// Deprecated: Use StringDeref instead. +// Deprecated: Use ptr.Deref instead. var StringPtrDerefOr = StringDeref // for back-compat // StringEqual returns true if both arguments are nil or both arguments // dereference to the same value. -func StringEqual(a, b *string) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var StringEqual = ptr.Equal[string] // Float32 returns a pointer to a float32. -func Float32(i float32) *float32 { - return &i -} +var Float32 = ptr.To[float32] // Float32Ptr is a function variable referring to Float32. // -// Deprecated: Use Float32 instead. +// Deprecated: Use ptr.To instead. var Float32Ptr = Float32 // Float32Deref dereferences the float32 ptr and returns it if not nil, or else // returns def. -func Float32Deref(ptr *float32, def float32) float32 { - if ptr != nil { - return *ptr - } - return def -} +var Float32Deref = ptr.Deref[float32] // Float32PtrDerefOr is a function variable referring to Float32Deref. // -// Deprecated: Use Float32Deref instead. +// Deprecated: Use ptr.Deref instead. var Float32PtrDerefOr = Float32Deref // for back-compat // Float32Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Float32Equal(a, b *float32) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Float32Equal = ptr.Equal[float32] // Float64 returns a pointer to a float64. -func Float64(i float64) *float64 { - return &i -} +var Float64 = ptr.To[float64] // Float64Ptr is a function variable referring to Float64. // -// Deprecated: Use Float64 instead. +// Deprecated: Use ptr.To instead. var Float64Ptr = Float64 // Float64Deref dereferences the float64 ptr and returns it if not nil, or else // returns def. -func Float64Deref(ptr *float64, def float64) float64 { - if ptr != nil { - return *ptr - } - return def -} +var Float64Deref = ptr.Deref[float64] // Float64PtrDerefOr is a function variable referring to Float64Deref. // -// Deprecated: Use Float64Deref instead. +// Deprecated: Use ptr.Deref instead. var Float64PtrDerefOr = Float64Deref // for back-compat // Float64Equal returns true if both arguments are nil or both arguments // dereference to the same value. -func Float64Equal(a, b *float64) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var Float64Equal = ptr.Equal[float64] // Duration returns a pointer to a time.Duration. -func Duration(d time.Duration) *time.Duration { - return &d -} +var Duration = ptr.To[time.Duration] // DurationDeref dereferences the time.Duration ptr and returns it if not nil, or else // returns def. -func DurationDeref(ptr *time.Duration, def time.Duration) time.Duration { - if ptr != nil { - return *ptr - } - return def -} +var DurationDeref = ptr.Deref[time.Duration] // DurationEqual returns true if both arguments are nil or both arguments // dereference to the same value. -func DurationEqual(a, b *time.Duration) bool { - if (a == nil) != (b == nil) { - return false - } - if a == nil { - return true - } - return *a == *b -} +var DurationEqual = ptr.Equal[time.Duration] diff --git a/vendor/k8s.io/utils/ptr/OWNERS b/vendor/k8s.io/utils/ptr/OWNERS new file mode 100644 index 0000000000..0d6392752a --- /dev/null +++ b/vendor/k8s.io/utils/ptr/OWNERS @@ -0,0 +1,10 @@ +# See the OWNERS docs at https://go.k8s.io/owners + +approvers: +- apelisse +- stewart-yu +- thockin +reviewers: +- apelisse +- stewart-yu +- thockin diff --git a/vendor/k8s.io/utils/ptr/README.md b/vendor/k8s.io/utils/ptr/README.md new file mode 100644 index 0000000000..2ca8073dc7 --- /dev/null +++ b/vendor/k8s.io/utils/ptr/README.md @@ -0,0 +1,3 @@ +# Pointer + +This package provides some functions for pointer-based operations. diff --git a/vendor/k8s.io/utils/ptr/ptr.go b/vendor/k8s.io/utils/ptr/ptr.go new file mode 100644 index 0000000000..659ed3b9e2 --- /dev/null +++ b/vendor/k8s.io/utils/ptr/ptr.go @@ -0,0 +1,73 @@ +/* +Copyright 2023 The Kubernetes Authors. + +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 ptr + +import ( + "fmt" + "reflect" +) + +// AllPtrFieldsNil tests whether all pointer fields in a struct are nil. This is useful when, +// for example, an API struct is handled by plugins which need to distinguish +// "no plugin accepted this spec" from "this spec is empty". +// +// This function is only valid for structs and pointers to structs. Any other +// type will cause a panic. Passing a typed nil pointer will return true. +func AllPtrFieldsNil(obj interface{}) bool { + v := reflect.ValueOf(obj) + if !v.IsValid() { + panic(fmt.Sprintf("reflect.ValueOf() produced a non-valid Value for %#v", obj)) + } + if v.Kind() == reflect.Ptr { + if v.IsNil() { + return true + } + v = v.Elem() + } + for i := 0; i < v.NumField(); i++ { + if v.Field(i).Kind() == reflect.Ptr && !v.Field(i).IsNil() { + return false + } + } + return true +} + +// To returns a pointer to the given value. +func To[T any](v T) *T { + return &v +} + +// Deref dereferences ptr and returns the value it points to if no nil, or else +// returns def. +func Deref[T any](ptr *T, def T) T { + if ptr != nil { + return *ptr + } + return def +} + +// Equal returns true if both arguments are nil or both arguments +// dereference to the same value. +func Equal[T comparable](a, b *T) bool { + if (a == nil) != (b == nil) { + return false + } + if a == nil { + return true + } + return *a == *b +} diff --git a/vendor/k8s.io/utils/trace/trace.go b/vendor/k8s.io/utils/trace/trace.go index a0b07a6d78..187eb5d8c5 100644 --- a/vendor/k8s.io/utils/trace/trace.go +++ b/vendor/k8s.io/utils/trace/trace.go @@ -65,6 +65,11 @@ func durationToMilliseconds(timeDuration time.Duration) int64 { } type traceItem interface { + // rLock must be called before invoking time or writeItem. + rLock() + // rUnlock must be called after processing the item is complete. + rUnlock() + // time returns when the trace was recorded as completed. time() time.Time // writeItem outputs the traceItem to the buffer. If stepThreshold is non-nil, only output the @@ -79,6 +84,10 @@ type traceStep struct { fields []Field } +// rLock doesn't need to do anything because traceStep instances are immutable. +func (s traceStep) rLock() {} +func (s traceStep) rUnlock() {} + func (s traceStep) time() time.Time { return s.stepTime } @@ -106,6 +115,14 @@ type Trace struct { traceItems []traceItem } +func (t *Trace) rLock() { + t.lock.RLock() +} + +func (t *Trace) rUnlock() { + t.lock.RUnlock() +} + func (t *Trace) time() time.Time { if t.endTime != nil { return *t.endTime @@ -231,8 +248,10 @@ func (t *Trace) logTrace() { func (t *Trace) writeTraceSteps(b *bytes.Buffer, formatter string, stepThreshold *time.Duration) { lastStepTime := t.startTime for _, stepOrTrace := range t.traceItems { + stepOrTrace.rLock() stepOrTrace.writeItem(b, formatter, lastStepTime, stepThreshold) lastStepTime = stepOrTrace.time() + stepOrTrace.rUnlock() } } diff --git a/vendor/modules.txt b/vendor/modules.txt index 51a4da31d3..57814a08df 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -1049,7 +1049,7 @@ k8s.io/kube-openapi/pkg/validation/spec # k8s.io/kubectl v0.26.9 ## explicit; go 1.19 k8s.io/kubectl/pkg/scheme -# k8s.io/utils v0.0.0-20230209194617-a36077c30491 +# k8s.io/utils v0.0.0-20230726121419-3b25d923346b ## explicit; go 1.18 k8s.io/utils/buffer k8s.io/utils/clock @@ -1058,6 +1058,7 @@ k8s.io/utils/integer k8s.io/utils/internal/third_party/forked/golang/net k8s.io/utils/net k8s.io/utils/pointer +k8s.io/utils/ptr k8s.io/utils/strings/slices k8s.io/utils/trace # knative.dev/pkg v0.0.0-20230221145627-8efb3485adcf