Repository: shipwright-io/build
Pull request #1379 (2023-09-11 18:05:09)

Add conversion code for buildrun deletion capability
# Changes

Adding conversion logic for the automatic "BuildRun deletion when Build is deleted" capability which is an annotation in alpha and a first class attribute in beta.

# Submitter Checklist

- [x] Includes tests if functionality changed/was added
- [ ] Includes docs if changes are user-facing
- [x] [Set a kind label on this PR](https://prow.k8s.io/command-help#kind)
- [x] Release notes block has been filled in, or marked NONE

See [the contributor guide](https://github.com/shipwright-io/build/blob/main/CONTRIBUTING.md)
for details on coding conventions, github and prow interactions, and the code review process.

# Release Notes

```release-note
NONE
```


Patch:
diff --git a/pkg/apis/build/v1beta1/build_conversion.go b/pkg/apis/build/v1beta1/build_conversion.go
index acc75622..25e155f1 100644
--- a/pkg/apis/build/v1beta1/build_conversion.go
+++ b/pkg/apis/build/v1beta1/build_conversion.go
@@ -6,6 +6,7 @@ package v1beta1
 
 import (
 	"context"
+	"strconv"
 
 	"github.com/shipwright-io/build/pkg/apis/build/v1alpha1"
 	"github.com/shipwright-io/build/pkg/ctxlog"
@@ -13,6 +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"
 )
 
 const (
@@ -33,6 +35,15 @@ func (src *Build) ConvertTo(ctx context.Context, obj *unstructured.Unstructured)
 	alphaBuild.ObjectMeta = src.ObjectMeta
 
 	src.Spec.ConvertTo(&alphaBuild.Spec)
+
+	// convert annotation-controlled features
+	if src.Spec.Retention != nil && src.Spec.Retention.AtBuildDeletion != nil {
+		if alphaBuild.ObjectMeta.Annotations == nil {
+			alphaBuild.ObjectMeta.Annotations = make(map[string]string, 1)
+		}
+		alphaBuild.ObjectMeta.Annotations[v1alpha1.AnnotationBuildRunDeletion] = strconv.FormatBool(*src.Spec.Retention.AtBuildDeletion)
+	}
+
 	mapito, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&alphaBuild)
 	if err != nil {
 		ctxlog.Error(ctx, err, "failed structuring the newObject")
@@ -59,6 +70,15 @@ func (src *Build) ConvertFrom(ctx context.Context, obj *unstructured.Unstructure
 
 	src.Spec.ConvertFrom(&alphaBuild.Spec)
 
+	// convert annotation-controlled features
+	if value, set := alphaBuild.Annotations[v1alpha1.AnnotationBuildRunDeletion]; set {
+		if src.Spec.Retention == nil {
+			src.Spec.Retention = &BuildRetention{}
+		}
+		src.Spec.Retention.AtBuildDeletion = pointer.Bool(value == "true")
+		delete(src.ObjectMeta.Annotations, v1alpha1.AnnotationBuildRunDeletion)
+	}
+
 	src.Status = BuildStatus{
 		Registered: alphaBuild.Status.Registered,
 		Reason:     (*BuildReason)(alphaBuild.Status.Reason),
@@ -222,7 +242,11 @@ func (dest *BuildSpec) ConvertTo(bs *v1alpha1.BuildSpec) error {
 	bs.Env = dest.Env
 
 	// Handle BuildSpec Retention
-	if dest.Retention != nil {
+	if dest.Retention != nil &&
+		(dest.Retention.FailedLimit != nil ||
+			dest.Retention.SucceededLimit != nil ||
+			dest.Retention.TTLAfterFailed != nil ||
+			dest.Retention.TTLAfterSucceeded != nil) {
 		bs.Retention = &v1alpha1.BuildRetention{
 			FailedLimit:       dest.Retention.FailedLimit,
 			SucceededLimit:    dest.Retention.SucceededLimit,
diff --git a/pkg/apis/build/v1beta1/build_types.go b/pkg/apis/build/v1beta1/build_types.go
index 8fbe4c41..738fa05e 100644
--- a/pkg/apis/build/v1beta1/build_types.go
+++ b/pkg/apis/build/v1beta1/build_types.go
@@ -268,7 +268,7 @@ type BuildRetention struct {
 	// AtBuildDeletion defines if related BuildRuns should be deleted when deleting the Build.
 	//
 	// +optional
-	AtBuildDeletion bool `json:"atBuildDeletion,omitempty"`
+	AtBuildDeletion *bool `json:"atBuildDeletion,omitempty"`
 }
 
 func init() {
diff --git a/pkg/apis/build/v1beta1/zz_generated.deepcopy.go b/pkg/apis/build/v1beta1/zz_generated.deepcopy.go
index fda4d61d..45d8944a 100644
--- a/pkg/apis/build/v1beta1/zz_generated.deepcopy.go
+++ b/pkg/apis/build/v1beta1/zz_generated.deepcopy.go
@@ -99,6 +99,11 @@ func (in *BuildRetention) DeepCopyInto(out *BuildRetention) {
 		*out = new(v1.Duration)
 		**out = **in
 	}
+	if in.AtBuildDeletion != nil {
+		in, out := &in.AtBuildDeletion, &out.AtBuildDeletion
+		*out = new(bool)
+		**out = **in
+	}
 	return
 }
 


Test patch:
diff --git a/pkg/webhook/conversion/converter_test.go b/pkg/webhook/conversion/converter_test.go
index 8fbb4baf..6c1e2502 100644
--- a/pkg/webhook/conversion/converter_test.go
+++ b/pkg/webhook/conversion/converter_test.go
@@ -22,6 +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"
 )
 
 func getConversionReview(o string) (apiextensionsv1.ConversionReview, error) {
@@ -204,6 +205,8 @@ request:
         output:
           image: %s
           pushSecret: %s
+        retention:
+          atBuildDeletion: true
 `
 			o := fmt.Sprintf(buildTemplate, apiVersion,
 				desiredAPIVersion, ctxDir,
@@ -234,6 +237,9 @@ request:
 				},
 				ObjectMeta: v1.ObjectMeta{
 					Name: "buildkit-build",
+					Annotations: map[string]string{
+						v1alpha1.AnnotationBuildRunDeletion: "true",
+					},
 				},
 				Spec: v1alpha1.BuildSpec{
 					Source: v1alpha1.Source{
@@ -270,7 +276,7 @@ request:
 							// todo: figure out why we need to set this one
 							SingleValue: &v1alpha1.SingleValue{},
 							Values: []v1alpha1.SingleValue{
-								v1alpha1.SingleValue{
+								{
 									SecretValue: &v1alpha1.ObjectKeyRef{
 										Name:   "npm-registry-access",
 										Key:    "npm-auth-token",
@@ -416,6 +422,8 @@ request:
       kind: Build
       metadata:
         name: buildkit-build
+        annotations:
+          build.shipwright.io/build-run-deletion: "true"
       spec:
         source:
           contextDir: %s
@@ -494,6 +502,9 @@ request:
 							},
 						},
 					},
+					Retention: &v1beta1.BuildRetention{
+						AtBuildDeletion: pointer.Bool(true),
+					},
 					Trigger: &v1beta1.Trigger{
 						When: []v1beta1.TriggerWhen{
 							{
@@ -612,7 +623,7 @@ request:
 							// todo: figure out why we need to set this one
 							SingleValue: &v1beta1.SingleValue{},
 							Values: []v1beta1.SingleValue{
-								v1beta1.SingleValue{
+								{
 									SecretValue: &v1beta1.ObjectKeyRef{
 										Name:   "npm-registry-access",
 										Key:    "npm-auth-token",