diff --git a/docs/buildrun.md b/docs/buildrun.md index eba428e9c4..a92625cfe4 100644 --- a/docs/buildrun.md +++ b/docs/buildrun.md @@ -50,7 +50,7 @@ The `BuildRun` definition supports the following fields: - `spec.resources` - Refers to the compute [resources](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/) used on the container where the image is built. - `spec.serviceAccount` - Refers to the SA to use when building the image. (_defaults to the `default` SA_) - `spec.timeout` - Defines a custom timeout. The value needs to be parsable by [ParseDuration](https://golang.org/pkg/time/#ParseDuration), for example `5m`. The value overwrites the value that is defined in the `Build`. - + - `spec.output.image` - Refers to a custom location where the generated image would be pushed. The value will overwrite the `output.image` value which is defined in `Build`. ### Defining the BuildRef A `BuildRun` resource can reference a `Build` resource, that indicates what image to build. For example: diff --git a/pkg/apis/build/v1alpha1/buildrun_types.go b/pkg/apis/build/v1alpha1/buildrun_types.go index 0e04bedd22..b0a342ca96 100644 --- a/pkg/apis/build/v1alpha1/buildrun_types.go +++ b/pkg/apis/build/v1alpha1/buildrun_types.go @@ -31,6 +31,11 @@ type BuildRunSpec struct { // Timeout defines the maximum run time of this build run. // +optional Timeout *metav1.Duration `json:"timeout,omitempty"` + + // Output refers to the location where the generated + // image would be pushed to. It will overwrite the output image in build spec + // +optional + Output *Image `json:"output,omitempty"` } // BuildRunStatus defines the observed state of BuildRun diff --git a/pkg/controller/buildrun/generate_taskrun.go b/pkg/controller/buildrun/generate_taskrun.go index a1054bc962..890a12c9b8 100644 --- a/pkg/controller/buildrun/generate_taskrun.go +++ b/pkg/controller/buildrun/generate_taskrun.go @@ -170,6 +170,14 @@ func GenerateTaskRun(build *buildv1alpha1.Build, buildRun *buildv1alpha1.BuildRu revision = *build.Spec.Source.Revision } + // retrieve expected imageURL form build or buildRun + var ImageURL string + if buildRun.Spec.Output != nil { + ImageURL = buildRun.Spec.Output.ImageURL + } else { + ImageURL = build.Spec.Output.ImageURL + } + taskSpec, err := GenerateTaskSpec(build, buildRun, buildSteps) if err != nil { return nil, err @@ -219,7 +227,7 @@ func GenerateTaskRun(build *buildv1alpha1.Build, buildRun *buildv1alpha1.BuildRu Params: []taskv1.ResourceParam{ { Name: outputImageResourceURL, - Value: build.Spec.Output.ImageURL, + Value: ImageURL, }, }, }, diff --git a/pkg/controller/buildrun/generate_taskrun_test.go b/pkg/controller/buildrun/generate_taskrun_test.go index 809088b756..9d90306d91 100644 --- a/pkg/controller/buildrun/generate_taskrun_test.go +++ b/pkg/controller/buildrun/generate_taskrun_test.go @@ -179,7 +179,7 @@ var _ = Describe("GenerateTaskrun", func() { var ( k8sDuration30s *metav1.Duration k8sDuration1m *metav1.Duration - namespace, contextDir, revision, outputPath, serviceAccountName string + namespace, contextDir, revision, outputPath, outputPathBuildRun, serviceAccountName string got *v1beta1.TaskRun err error ) @@ -202,6 +202,7 @@ var _ = Describe("GenerateTaskrun", func() { ImageURL: "heroku/buildpacks:18", } outputPath = "image-registry.openshift-image-registry.svc:5000/example/buildpacks-app" + outputPathBuildRun = "image-registry.openshift-image-registry.svc:5000/example/buildpacks-app-v2" serviceAccountName = buildpacks + "-serviceaccount" }) @@ -538,5 +539,95 @@ var _ = Describe("GenerateTaskrun", func() { Expect(got.Spec.Timeout).To(Equal(k8sDuration1m)) }) }) + + Context("when the build and buildrun both contain an output imageURL", func() { + BeforeEach(func() { + build = &buildv1alpha1.Build{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildah, + Namespace: namespace, + }, + Spec: buildv1alpha1.BuildSpec{ + Source: buildv1alpha1.GitSource{ + URL: url, + }, + StrategyRef: &buildv1alpha1.StrategyRef{ + Name: buildah, + }, + Output: buildv1alpha1.Image{ + ImageURL: outputPath, + }, + }, + } + buildRun = &buildv1alpha1.BuildRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: buildah + "-run", + Namespace: namespace, + }, + Spec: buildv1alpha1.BuildRunSpec{ + BuildRef: &buildv1alpha1.BuildRef{ + Name: buildah, + }, + Resources: &corev1.ResourceRequirements{ + Limits: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("2Gi"), + }, + Requests: corev1.ResourceList{ + corev1.ResourceCPU: resource.MustParse("500m"), + corev1.ResourceMemory: resource.MustParse("2Gi"), + }, + }, + ServiceAccount: &buildv1alpha1.ServiceAccount{ + Name: &serviceAccountName, + }, + Output: &buildv1alpha1.Image{ + ImageURL: outputPathBuildRun, + }, + }, + } + buildStrategy = &buildv1alpha1.BuildStrategy{ + ObjectMeta: metav1.ObjectMeta{Name: buildah}, + Spec: buildv1alpha1.BuildStrategySpec{ + BuildSteps: []buildv1alpha1.BuildStep{ + { + Container: corev1.Container{ + Name: "build", + Image: "$(build.builder.image)", + WorkingDir: "/workspace/source", + Command: []string{ + "buildah", "bud", "--tls-verify=false", "--layers", "-f", "$(build.dockerfile)", "-t", "$(build.output.image)", "$(build.pathContext)", + }, + VolumeMounts: []corev1.VolumeMount{ + { + Name: "varlibcontainers", + MountPath: "/var/lib/containers", + }, + }, + }, + }, + }, + }, + } + }) + + JustBeforeEach(func() { + got, err = buildrunCtl.GenerateTaskRun(build, buildRun, serviceAccountName, buildStrategy.Spec.BuildSteps) + Expect(err).To(BeNil()) + }) + + It("should use the imageURL from the BuildRun", func() { + outputResources := got.Spec.Resources.Outputs + for _, outputResource := range outputResources { + Expect(outputResource.ResourceSpec.Type).To(Equal(v1beta1.PipelineResourceTypeImage)) + params := outputResource.ResourceSpec.Params + for _, param := range params { + if param.Name == "url" { + Expect(param.Value).To(Equal(outputPathBuildRun)) + } + } + } + }) + }) }) })