diff --git a/cmd/controller/main.go b/cmd/controller/main.go index f1ed25948..867c17a11 100644 --- a/cmd/controller/main.go +++ b/cmd/controller/main.go @@ -9,13 +9,9 @@ import ( "os" "time" - "github.com/pivotal/kpack/pkg/secret" - + "github.com/Masterminds/semver/v3" "github.com/sigstore/cosign/v2/cmd/cosign/cli/sign" ociremote "github.com/sigstore/cosign/v2/pkg/oci/remote" - - "github.com/pivotal/kpack/pkg/cosign" - "go.uber.org/zap" "golang.org/x/sync/errgroup" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -46,6 +42,7 @@ import ( "github.com/pivotal/kpack/pkg/client/informers/externalversions" "github.com/pivotal/kpack/pkg/cnb" "github.com/pivotal/kpack/pkg/config" + "github.com/pivotal/kpack/pkg/cosign" "github.com/pivotal/kpack/pkg/dockercreds/k8sdockercreds" "github.com/pivotal/kpack/pkg/duckbuilder" "github.com/pivotal/kpack/pkg/flaghelpers" @@ -64,6 +61,7 @@ import ( "github.com/pivotal/kpack/pkg/reconciler/lifecycle" "github.com/pivotal/kpack/pkg/reconciler/sourceresolver" "github.com/pivotal/kpack/pkg/registry" + "github.com/pivotal/kpack/pkg/secret" ) const ( diff --git a/go.mod b/go.mod index b5c8f4c17..e5439f45e 100644 --- a/go.mod +++ b/go.mod @@ -324,5 +324,3 @@ require ( sigs.k8s.io/structured-merge-diff/v4 v4.2.3 // indirect sigs.k8s.io/yaml v1.3.0 // indirect ) - -replace github.com/AdamKorcz/go-fuzz-headers-1 => github.com/AdamKorcz/go-fuzz-headers-1 v0.0.0-20230919221257-8b5d3ce2d11d diff --git a/pkg/apis/build/v1alpha2/build.go b/pkg/apis/build/v1alpha2/build.go index 0714cc7e4..845685cf8 100644 --- a/pkg/apis/build/v1alpha2/build.go +++ b/pkg/apis/build/v1alpha2/build.go @@ -200,16 +200,6 @@ func (b *Build) builtWithStack(runImage string) bool { return lastBuildRunImageRef.Identifier() == builderRunImageRef.Identifier() } -func (b *Build) builtWithBuildpacks(buildpacks corev1alpha1.BuildpackMetadataList) bool { - for _, bp := range b.Status.BuildMetadata { - if !buildpacks.Include(bp) { - return false - } - } - - return true -} - func (b *Build) additionalBuildNeeded() bool { _, ok := b.Annotations[BuildNeededAnnotation] return ok diff --git a/pkg/apis/build/v1alpha2/build_conversion.go b/pkg/apis/build/v1alpha2/build_conversion.go index 00dd29cb3..2ae70fdd1 100644 --- a/pkg/apis/build/v1alpha2/build_conversion.go +++ b/pkg/apis/build/v1alpha2/build_conversion.go @@ -80,7 +80,7 @@ func (bs *BuildSpec) convertFrom(from *v1alpha1.BuildSpec) { func (bs *BuildStatus) convertFrom(from *v1alpha1.BuildStatus) { bs.Status = from.Status - bs.BuildMetadata = from.BuildMetadata + bs.BuildMetadataBuildpacks = from.BuildMetadata bs.Stack = from.Stack bs.LatestImage = from.LatestImage bs.PodName = from.PodName @@ -90,7 +90,7 @@ func (bs *BuildStatus) convertFrom(from *v1alpha1.BuildStatus) { func (bs *BuildStatus) convertTo(to *v1alpha1.BuildStatus) { to.Status = bs.Status - to.BuildMetadata = bs.BuildMetadata + to.BuildMetadata = bs.BuildMetadataBuildpacks to.Stack = bs.Stack to.LatestImage = bs.LatestImage to.PodName = bs.PodName diff --git a/pkg/apis/build/v1alpha2/build_conversion_test.go b/pkg/apis/build/v1alpha2/build_conversion_test.go index 2a719b112..479c06c56 100644 --- a/pkg/apis/build/v1alpha2/build_conversion_test.go +++ b/pkg/apis/build/v1alpha2/build_conversion_test.go @@ -68,7 +68,7 @@ func testBuildConversion(t *testing.T, when spec.G, it spec.S) { ObservedGeneration: 0, Conditions: nil, }, - BuildMetadata: corev1alpha1.BuildpackMetadataList{}, + BuildMetadataBuildpacks: corev1alpha1.BuildpackMetadataList{}, Stack: corev1alpha1.BuildStack{ RunImage: "some-run", ID: "some-id", diff --git a/pkg/apis/build/v1alpha2/build_pod.go b/pkg/apis/build/v1alpha2/build_pod.go index eabf5243c..617b4592f 100644 --- a/pkg/apis/build/v1alpha2/build_pod.go +++ b/pkg/apis/build/v1alpha2/build_pod.go @@ -72,11 +72,11 @@ const ( var ( PrepareCommand = "/cnb/process/build-init" - AnalyzeCommand = "/cnb/lifecycle/analyzer" - DetectCommand = "/cnb/lifecycle/detector" - RestoreCommand = "/cnb/lifecycle/restorer" - BuildCommand = "/cnb/lifecycle/builder" - ExportCommand = "/cnb/lifecycle/exporter" + AnalyzeCommand = "/cnb/lifecycle/analyzer" + DetectCommand = "/cnb/lifecycle/detector" + RestoreCommand = "/cnb/lifecycle/restorer" + BuildCommand = "/cnb/lifecycle/builder" + ExportCommand = "/cnb/lifecycle/exporter" CompletionCommand = "/cnb/process/completion" RebaseCommand = "/cnb/process/rebase" ) @@ -760,7 +760,7 @@ func (b *Build) useImageExtensions(pod *corev1.Pod) { container.SecurityContext.RunAsUser = intPointer(0) container.SecurityContext.RunAsGroup = intPointer(0) container.SecurityContext.RunAsNonRoot = boolPointer(false) - container.SecurityContext.Capabilities = &corev1.Capabilities{Add: []corev1.Capability{"SETGID", "SETUID"}} // TODO: check if this is needed if not using kind + container.SecurityContext.Capabilities = &corev1.Capabilities{Add: []corev1.Capability{"SETGID", "SETUID"}} } pod.Spec.InitContainers[idx] = container } diff --git a/pkg/apis/build/v1alpha2/build_types.go b/pkg/apis/build/v1alpha2/build_types.go index 83b54e4cc..e4c30324e 100644 --- a/pkg/apis/build/v1alpha2/build_types.go +++ b/pkg/apis/build/v1alpha2/build_types.go @@ -129,12 +129,13 @@ type BuildStack struct { // +k8s:openapi-gen=true type BuildStatus struct { - corev1alpha1.Status `json:",inline"` - BuildMetadata corev1alpha1.BuildpackMetadataList `json:"buildMetadata,omitempty"` - Stack corev1alpha1.BuildStack `json:"stack,omitempty"` - LatestImage string `json:"latestImage,omitempty"` - LatestCacheImage string `json:"latestCacheImage,omitempty"` - PodName string `json:"podName,omitempty"` + corev1alpha1.Status `json:",inline"` + BuildMetadataBuildpacks corev1alpha1.BuildpackMetadataList `json:"buildMetadata,omitempty"` + BuildMetadataExtensions corev1alpha1.BuildpackMetadataList `json:"buildMetadataExtensions,omitempty"` + Stack corev1alpha1.BuildStack `json:"stack,omitempty"` + LatestImage string `json:"latestImage,omitempty"` + LatestCacheImage string `json:"latestCacheImage,omitempty"` + PodName string `json:"podName,omitempty"` // +listType StepStates []corev1.ContainerState `json:"stepStates,omitempty"` // +listType diff --git a/pkg/apis/build/v1alpha2/builder_resource.go b/pkg/apis/build/v1alpha2/builder_resource.go index ea280d683..f340417ef 100644 --- a/pkg/apis/build/v1alpha2/builder_resource.go +++ b/pkg/apis/build/v1alpha2/builder_resource.go @@ -8,6 +8,7 @@ type BuilderResource interface { BuildBuilderSpec() corev1alpha1.BuildBuilderSpec Ready() bool BuildpackMetadata() corev1alpha1.BuildpackMetadataList + ExtensionMetadata() corev1alpha1.BuildpackMetadataList RunImage() string GetKind() string ConditionReadyMessage() string diff --git a/pkg/apis/build/v1alpha2/image_builds.go b/pkg/apis/build/v1alpha2/image_builds.go index 786bf06f6..7b5a0eb4e 100644 --- a/pkg/apis/build/v1alpha2/image_builds.go +++ b/pkg/apis/build/v1alpha2/image_builds.go @@ -28,6 +28,7 @@ const ( BuildReasonConfig = "CONFIG" BuildReasonCommit = "COMMIT" BuildReasonBuildpack = "BUILDPACK" + BuildReasonExtension = "EXTENSION" BuildReasonStack = "STACK" BuildReasonTrigger = "TRIGGER" ) diff --git a/pkg/apis/build/v1alpha2/image_builds_test.go b/pkg/apis/build/v1alpha2/image_builds_test.go index c33233df2..f8c63ee4b 100644 --- a/pkg/apis/build/v1alpha2/image_builds_test.go +++ b/pkg/apis/build/v1alpha2/image_builds_test.go @@ -60,7 +60,7 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) { LatestImage: "some/builder@sha256:builder-digest", Kind: BuilderKind, BuilderReady: true, - BuilderMetadata: []corev1alpha1.BuildpackMetadata{ + BuilderMetadataBuildpacks: []corev1alpha1.BuildpackMetadata{ {Id: "buildpack.matches", Version: "1"}, }, LatestRunImage: "some.registry.io/run-image@sha256:67e3de2af270bf09c02e9a644aeb7e87e6b3c049abe6766bf6b6c3728a83e7fb", @@ -84,7 +84,7 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) { }, }, }, - BuildMetadata: []corev1alpha1.BuildpackMetadata{ + BuildMetadataBuildpacks: []corev1alpha1.BuildpackMetadata{ {Id: "buildpack.matches", Version: "1"}, }, Stack: corev1alpha1.BuildStack{ @@ -371,14 +371,15 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) { } type TestBuilderResource struct { - BuilderReady bool - BuilderMetadata []corev1alpha1.BuildpackMetadata - ImagePullSecrets []corev1.LocalObjectReference - Kind string - LatestImage string - LatestRunImage string - Name string - Namespace string + BuilderReady bool + BuilderMetadataBuildpacks []corev1alpha1.BuildpackMetadata + BuilderMetadataExtensions []corev1alpha1.BuildpackMetadata + ImagePullSecrets []corev1.LocalObjectReference + Kind string + LatestImage string + LatestRunImage string + Name string + Namespace string } func (t TestBuilderResource) ConditionReadyMessage() string { @@ -397,7 +398,11 @@ func (t TestBuilderResource) Ready() bool { } func (t TestBuilderResource) BuildpackMetadata() corev1alpha1.BuildpackMetadataList { - return t.BuilderMetadata + return t.BuilderMetadataBuildpacks +} + +func (t TestBuilderResource) ExtensionMetadata() corev1alpha1.BuildpackMetadataList { + return t.BuilderMetadataExtensions } func (t TestBuilderResource) RunImage() string { diff --git a/pkg/apis/build/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/build/v1alpha2/zz_generated.deepcopy.go index 52001390b..9843afddc 100644 --- a/pkg/apis/build/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/build/v1alpha2/zz_generated.deepcopy.go @@ -313,8 +313,8 @@ func (in *BuildStack) DeepCopy() *BuildStack { func (in *BuildStatus) DeepCopyInto(out *BuildStatus) { *out = *in in.Status.DeepCopyInto(&out.Status) - if in.BuildMetadata != nil { - in, out := &in.BuildMetadata, &out.BuildMetadata + if in.BuildMetadataBuildpacks != nil { + in, out := &in.BuildMetadataBuildpacks, &out.BuildMetadataBuildpacks *out = make(v1alpha1.BuildpackMetadataList, len(*in)) copy(*out, *in) } diff --git a/pkg/buildchange/buildpack_change.go b/pkg/buildchange/buildpack_change.go index c72fc9fb5..339b6080b 100644 --- a/pkg/buildchange/buildpack_change.go +++ b/pkg/buildchange/buildpack_change.go @@ -9,10 +9,10 @@ import ( corev1alpha1 "github.com/pivotal/kpack/pkg/apis/core/v1alpha1" ) -func NewBuildpackChange(oldBuildpacks, newBuildpacks []corev1alpha1.BuildpackInfo) Change { +func NewBuildpackChange(oldInfos, newInfos []corev1alpha1.BuildpackInfo) Change { return buildpackChange{ - old: oldBuildpacks, - new: newBuildpacks, + old: oldInfos, + new: newInfos, } } diff --git a/pkg/buildchange/extension_change.go b/pkg/buildchange/extension_change.go new file mode 100644 index 000000000..5ed8197ef --- /dev/null +++ b/pkg/buildchange/extension_change.go @@ -0,0 +1,40 @@ +package buildchange + +import ( + "sort" + + "github.com/google/go-cmp/cmp" + + buildapi "github.com/pivotal/kpack/pkg/apis/build/v1alpha2" + corev1alpha1 "github.com/pivotal/kpack/pkg/apis/core/v1alpha1" +) + +func NewExtensionChange(oldInfos, newInfos []corev1alpha1.BuildpackInfo) Change { + return extensionChange{ + old: oldInfos, + new: newInfos, + } +} + +type extensionChange struct { + old []corev1alpha1.BuildpackInfo + new []corev1alpha1.BuildpackInfo +} + +func (b extensionChange) Reason() buildapi.BuildReason { return buildapi.BuildReasonExtension } + +func (b extensionChange) IsBuildRequired() (bool, error) { + sort.Slice(b.old, func(i, j int) bool { + return b.old[i].Id < b.old[j].Id + }) + sort.Slice(b.new, func(i, j int) bool { + return b.new[i].Id < b.new[j].Id + }) + return !cmp.Equal(b.old, b.new), nil +} + +func (b extensionChange) Old() interface{} { return b.old } + +func (b extensionChange) New() interface{} { return b.new } + +func (b extensionChange) Priority() buildapi.BuildPriority { return buildapi.BuildPriorityLow } diff --git a/pkg/cnb/build_metadata.go b/pkg/cnb/build_metadata.go index 44cd4d2c3..a71138208 100644 --- a/pkg/cnb/build_metadata.go +++ b/pkg/cnb/build_metadata.go @@ -21,6 +21,7 @@ import ( type BuildMetadata struct { BuildpackMetadata corev1alpha1.BuildpackMetadataList `json:"buildpackMetadata"` + ExtensionMetadata corev1alpha1.BuildpackMetadataList `json:"extensionMetadata"` LatestCacheImage string `json:"latestCacheImage"` LatestImage string `json:"latestImage"` StackID string `json:"stackID"` @@ -43,7 +44,8 @@ func (r *RemoteMetadataRetriever) GetBuildMetadata(builtImageRef, cacheTag strin cacheImageRef, _ := r.getCacheImage(cacheTag, keychain) // if getting cache fails, use empty cache return &BuildMetadata{ - BuildpackMetadata: buildMetadataFromBuiltImage(buildImg), + BuildpackMetadata: buildpackMetadataFromBuiltImage(buildImg), + ExtensionMetadata: extensionMetadataFromBuiltImage(buildImg), LatestImage: buildImg.identifier, LatestCacheImage: cacheImageRef, StackRunImage: buildImg.stack.RunImage, @@ -103,6 +105,7 @@ func readBuiltImage(appImage ggcrv1.Image, appImageId string) (builtImage, error return builtImage{ identifier: appImageId, buildpackMetadata: buildMetadata.Buildpacks, + extensionMetadata: buildMetadata.Extensions, stack: builtImageStack{ RunImage: baseImageRef.Context().String() + "@" + runImageRef.Identifier(), ID: stackId, @@ -113,6 +116,7 @@ func readBuiltImage(appImage ggcrv1.Image, appImageId string) (builtImage, error type builtImage struct { identifier string buildpackMetadata []lifecyclebuildpack.GroupElement + extensionMetadata []lifecyclebuildpack.GroupElement stack builtImageStack } @@ -126,16 +130,28 @@ type RunImageAppMetadata struct { Reference string `json:"reference" toml:"reference"` } -func buildMetadataFromBuiltImage(image builtImage) corev1alpha1.BuildpackMetadataList { - bpMetadata := make([]corev1alpha1.BuildpackMetadata, 0, len(image.buildpackMetadata)) - for _, metadata := range image.buildpackMetadata { - bpMetadata = append(bpMetadata, corev1alpha1.BuildpackMetadata{ - Id: metadata.ID, - Version: metadata.Version, - Homepage: metadata.Homepage, +func buildpackMetadataFromBuiltImage(image builtImage) corev1alpha1.BuildpackMetadataList { + ret := make([]corev1alpha1.BuildpackMetadata, 0, len(image.buildpackMetadata)) + for _, m := range image.buildpackMetadata { + ret = append(ret, corev1alpha1.BuildpackMetadata{ + Id: m.ID, + Version: m.Version, + Homepage: m.Homepage, }) } - return bpMetadata + return ret +} + +func extensionMetadataFromBuiltImage(image builtImage) corev1alpha1.BuildpackMetadataList { + ret := make([]corev1alpha1.BuildpackMetadata, 0, len(image.buildpackMetadata)) + for _, m := range image.buildpackMetadata { + ret = append(ret, corev1alpha1.BuildpackMetadata{ + Id: m.ID, + Version: m.Version, + Homepage: m.Homepage, + }) + } + return ret } func CompressBuildMetadata(metadata *BuildMetadata) ([]byte, error) { diff --git a/pkg/duckbuilder/duck_builder.go b/pkg/duckbuilder/duck_builder.go index 3a7942ee4..00c48b420 100644 --- a/pkg/duckbuilder/duck_builder.go +++ b/pkg/duckbuilder/duck_builder.go @@ -44,11 +44,14 @@ func (b *DuckBuilder) BuildBuilderSpec() corev1alpha1.BuildBuilderSpec { } } -// TODO: add for extensions? func (b *DuckBuilder) BuildpackMetadata() corev1alpha1.BuildpackMetadataList { return b.Status.BuilderMetadataBuildpacks } +func (b *DuckBuilder) ExtensionMetadata() corev1alpha1.BuildpackMetadataList { + return b.Status.BuilderMetadataExtensions +} + func (b *DuckBuilder) RunImage() string { return b.Status.Stack.RunImage } diff --git a/pkg/reconciler/build/build.go b/pkg/reconciler/build/build.go index b02cfc0c5..beb6fbeee 100644 --- a/pkg/reconciler/build/build.go +++ b/pkg/reconciler/build/build.go @@ -3,17 +3,8 @@ package build import ( "context" "encoding/json" + "github.com/google/go-containerregistry/pkg/authn" - buildapi "github.com/pivotal/kpack/pkg/apis/build/v1alpha2" - corev1alpha1 "github.com/pivotal/kpack/pkg/apis/core/v1alpha1" - "github.com/pivotal/kpack/pkg/buildchange" - "github.com/pivotal/kpack/pkg/buildpod" - "github.com/pivotal/kpack/pkg/client/clientset/versioned" - buildinformers "github.com/pivotal/kpack/pkg/client/informers/externalversions/build/v1alpha2" - buildlisters "github.com/pivotal/kpack/pkg/client/listers/build/v1alpha2" - "github.com/pivotal/kpack/pkg/cnb" - "github.com/pivotal/kpack/pkg/reconciler" - "github.com/pivotal/kpack/pkg/registry" "github.com/pkg/errors" "go.uber.org/zap" corev1 "k8s.io/api/core/v1" @@ -27,6 +18,17 @@ import ( "k8s.io/client-go/tools/cache" "knative.dev/pkg/controller" "knative.dev/pkg/logging/logkey" + + buildapi "github.com/pivotal/kpack/pkg/apis/build/v1alpha2" + corev1alpha1 "github.com/pivotal/kpack/pkg/apis/core/v1alpha1" + "github.com/pivotal/kpack/pkg/buildchange" + "github.com/pivotal/kpack/pkg/buildpod" + "github.com/pivotal/kpack/pkg/client/clientset/versioned" + buildinformers "github.com/pivotal/kpack/pkg/client/informers/externalversions/build/v1alpha2" + buildlisters "github.com/pivotal/kpack/pkg/client/listers/build/v1alpha2" + "github.com/pivotal/kpack/pkg/cnb" + "github.com/pivotal/kpack/pkg/reconciler" + "github.com/pivotal/kpack/pkg/registry" ) const ( @@ -167,7 +169,8 @@ func (c *Reconciler) reconcile(ctx context.Context, build *buildapi.Build) error return errors.Wrap(err, "failed to get build metadata from build pod") } } - build.Status.BuildMetadata = buildMetadata.BuildpackMetadata + build.Status.BuildMetadataBuildpacks = buildMetadata.BuildpackMetadata + build.Status.BuildMetadataExtensions = buildMetadata.ExtensionMetadata build.Status.LatestImage = buildMetadata.LatestImage build.Status.LatestCacheImage = buildMetadata.LatestCacheImage build.Status.Stack.RunImage = buildMetadata.StackRunImage diff --git a/pkg/reconciler/build/build_test.go b/pkg/reconciler/build/build_test.go index 47657cec9..0b2809b73 100644 --- a/pkg/reconciler/build/build_test.go +++ b/pkg/reconciler/build/build_test.go @@ -5,6 +5,11 @@ import ( "encoding/json" "errors" "fmt" + "os" + "path/filepath" + "testing" + "time" + "github.com/sclevine/spec" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -21,10 +26,6 @@ import ( "k8s.io/client-go/tools/record" "knative.dev/pkg/controller" rtesting "knative.dev/pkg/reconciler/testing" - "os" - "path/filepath" - "testing" - "time" buildapi "github.com/pivotal/kpack/pkg/apis/build/v1alpha2" corev1alpha1 "github.com/pivotal/kpack/pkg/apis/core/v1alpha1" @@ -578,7 +579,7 @@ func testBuildReconciler(t *testing.T, when spec.G, it spec.S) { }, }, PodName: "build-name-build-pod", - BuildMetadata: corev1alpha1.BuildpackMetadataList{ + BuildMetadataBuildpacks: corev1alpha1.BuildpackMetadataList{ { Id: "some-id", Version: "some-version", @@ -647,7 +648,7 @@ func testBuildReconciler(t *testing.T, when spec.G, it spec.S) { }, }, }, - BuildMetadata: corev1alpha1.BuildpackMetadataList{{ + BuildMetadataBuildpacks: corev1alpha1.BuildpackMetadataList{{ Id: "io.buildpack.previouslyfetched", Version: "1.1", }}, @@ -759,7 +760,7 @@ func testBuildReconciler(t *testing.T, when spec.G, it spec.S) { }, }, PodName: "build-name-build-pod", - BuildMetadata: corev1alpha1.BuildpackMetadataList{{ + BuildMetadataBuildpacks: corev1alpha1.BuildpackMetadataList{{ Id: "io.buildpack.executed", Version: "1.1", Homepage: "mysupercoolsite.com", @@ -818,7 +819,7 @@ func testBuildReconciler(t *testing.T, when spec.G, it spec.S) { }, }, }, - BuildMetadata: corev1alpha1.BuildpackMetadataList{{ + BuildMetadataBuildpacks: corev1alpha1.BuildpackMetadataList{{ Id: "io.buildpack.previouslyfetched", Version: "1.1", }}, @@ -1317,7 +1318,7 @@ func testBuildReconciler(t *testing.T, when spec.G, it spec.S) { }, }, PodName: "build-name-build-pod", - BuildMetadata: corev1alpha1.BuildpackMetadataList{ + BuildMetadataBuildpacks: corev1alpha1.BuildpackMetadataList{ { Id: "some-id", Version: "some-version", diff --git a/pkg/reconciler/image/build_required.go b/pkg/reconciler/image/build_required.go index a01841164..73761db35 100644 --- a/pkg/reconciler/image/build_required.go +++ b/pkg/reconciler/image/build_required.go @@ -45,6 +45,7 @@ func isBuildRequired(img *buildapi.Image, Process(commitChange(lastBuild, srcResolver)). Process(configChange(img, lastBuild, srcResolver)). Process(buildpackChange(lastBuild, builder)). + Process(extensionChange(lastBuild, builder)). Process(stackChange(lastBuild, builder)). Summarize() if err != nil { @@ -109,17 +110,35 @@ func buildpackChange(lastBuild *buildapi.Build, builder buildapi.BuilderResource return nil } - var old []corev1alpha1.BuildpackInfo - var new []corev1alpha1.BuildpackInfo + var oldInfo []corev1alpha1.BuildpackInfo + var newInfo []corev1alpha1.BuildpackInfo - builderBuildpacks := builder.BuildpackMetadata() - for _, lastBuildBp := range lastBuild.Status.BuildMetadata { - if !builderBuildpacks.Include(lastBuildBp) { - old = append(old, corev1alpha1.BuildpackInfo{Id: lastBuildBp.Id, Version: lastBuildBp.Version}) + fromBuilder := builder.BuildpackMetadata() + for _, fromLastBuild := range lastBuild.Status.BuildMetadataBuildpacks { + if !fromBuilder.Include(fromLastBuild) { + oldInfo = append(oldInfo, corev1alpha1.BuildpackInfo{Id: fromLastBuild.Id, Version: fromLastBuild.Version}) } } - return buildchange.NewBuildpackChange(old, new) + return buildchange.NewBuildpackChange(oldInfo, newInfo) +} + +func extensionChange(lastBuild *buildapi.Build, builder buildapi.BuilderResource) buildchange.Change { + if lastBuild == nil || !lastBuild.IsSuccess() { + return nil + } + + var oldInfo []corev1alpha1.BuildpackInfo + var newInfo []corev1alpha1.BuildpackInfo + + fromBuilder := builder.ExtensionMetadata() + for _, fromLastBuild := range lastBuild.Status.BuildMetadataExtensions { + if !fromBuilder.Include(fromLastBuild) { + oldInfo = append(oldInfo, corev1alpha1.BuildpackInfo{Id: fromLastBuild.Id, Version: fromLastBuild.Version}) + } + } + + return buildchange.NewExtensionChange(oldInfo, newInfo) } func stackChange(lastBuild *buildapi.Build, builder buildapi.BuilderResource) buildchange.Change { @@ -127,6 +146,10 @@ func stackChange(lastBuild *buildapi.Build, builder buildapi.BuilderResource) bu return nil } + if len(builder.ExtensionMetadata()) > 0 { + return nil + } + oldRunImageRefStr := lastBuild.Status.Stack.RunImage newRunImageRefStr := builder.RunImage() return buildchange.NewStackChange(oldRunImageRefStr, newRunImageRefStr) diff --git a/pkg/reconciler/image/build_required_test.go b/pkg/reconciler/image/build_required_test.go index 617c44eed..c7bafbf5e 100644 --- a/pkg/reconciler/image/build_required_test.go +++ b/pkg/reconciler/image/build_required_test.go @@ -60,7 +60,7 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) { Namespace: "test-ns", LatestImage: "some/builder@sha256:builder-digest", BuilderReady: true, - BuilderMetadata: []corev1alpha1.BuildpackMetadata{ + BuilderMetadataBuildpacks: []corev1alpha1.BuildpackMetadata{ {Id: "buildpack.matches", Version: "1"}, }, LatestRunImage: "some.registry.io/run-image@sha256:67e3de2af270bf09c02e9a644aeb7e87e6b3c049abe6766bf6b6c3728a83e7fb", @@ -85,7 +85,7 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) { }, }, }, - BuildMetadata: []corev1alpha1.BuildpackMetadata{ + BuildMetadataBuildpacks: []corev1alpha1.BuildpackMetadata{ {Id: "buildpack.matches", Version: "1"}, }, Stack: corev1alpha1.BuildStack{ @@ -308,27 +308,56 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) { }) when("Builder Metadata changes", func() { - it("false if builder has additional unused buildpacks", func() { - builder.BuilderMetadata = []corev1alpha1.BuildpackMetadata{ - {Id: "buildpack.matches", Version: "1"}, - {Id: "buildpack.unused", Version: "unused"}, - } - - result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) - assert.NoError(t, err) - assert.Equal(t, corev1.ConditionFalse, result.ConditionStatus) - assert.Equal(t, "", result.PriorityClass) - assert.Equal(t, "", result.ReasonsStr) - assert.Equal(t, "", result.ChangesStr) - }) - - it("true if builder metadata has different buildpack version from used buildpack version", func() { - builder.BuilderMetadata = []corev1alpha1.BuildpackMetadata{ - {Id: "buildpack.matches", Version: "NEW_VERSION"}, - {Id: "buildpack.different", Version: "different"}, - } + when("buildpacks", func() { + it("false if builder has additional unused buildpacks", func() { + builder.BuilderMetadataBuildpacks = []corev1alpha1.BuildpackMetadata{ + {Id: "buildpack.matches", Version: "1"}, + {Id: "buildpack.unused", Version: "unused"}, + } + + result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) + assert.NoError(t, err) + assert.Equal(t, corev1.ConditionFalse, result.ConditionStatus) + assert.Equal(t, "", result.PriorityClass) + assert.Equal(t, "", result.ReasonsStr) + assert.Equal(t, "", result.ChangesStr) + }) + + it("true if builder metadata has different buildpack version from used buildpack version", func() { + builder.BuilderMetadataBuildpacks = []corev1alpha1.BuildpackMetadata{ + {Id: "buildpack.matches", Version: "NEW_VERSION"}, + {Id: "buildpack.different", Version: "different"}, + } + + expectedChanges := testhelpers.CompactJSON(` +[ + { + "reason": "BUILDPACK", + "old": [ + { + "id": "buildpack.matches", + "version": "1" + } + ], + "new": null + } +]`) - expectedChanges := testhelpers.CompactJSON(` + result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) + assert.NoError(t, err) + assert.Equal(t, corev1.ConditionTrue, result.ConditionStatus) + assert.Equal(t, buildapi.BuildReasonBuildpack, result.ReasonsStr) + assert.Equal(t, buildapi.BuildPriorityClassLow, result.PriorityClass) + assert.Equal(t, expectedChanges, result.ChangesStr) + }) + + it("true if builder does not have all most recent used buildpacks", func() { + builder.BuilderMetadataBuildpacks = []corev1alpha1.BuildpackMetadata{ + {Id: "buildpack.only.new.buildpacks", Version: "1"}, + {Id: "buildpack.only.new.or.unused.buildpacks", Version: "1"}, + } + + expectedChanges := testhelpers.CompactJSON(` [ { "reason": "BUILDPACK", @@ -342,27 +371,77 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) { } ]`) - result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) - assert.NoError(t, err) - assert.Equal(t, corev1.ConditionTrue, result.ConditionStatus) - assert.Equal(t, buildapi.BuildReasonBuildpack, result.ReasonsStr) - assert.Equal(t, buildapi.BuildPriorityClassLow, result.PriorityClass) - assert.Equal(t, expectedChanges, result.ChangesStr) + result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) + assert.NoError(t, err) + assert.Equal(t, corev1.ConditionTrue, result.ConditionStatus) + assert.Equal(t, buildapi.BuildReasonBuildpack, result.ReasonsStr) + assert.Equal(t, buildapi.BuildPriorityClassLow, result.PriorityClass) + assert.Equal(t, expectedChanges, result.ChangesStr) + }) }) - it("true if builder does not have all most recent used buildpacks", func() { - builder.BuilderMetadata = []corev1alpha1.BuildpackMetadata{ - {Id: "buildpack.only.new.buildpacks", Version: "1"}, - {Id: "buildpack.only.new.or.unused.buildpacks", Version: "1"}, - } + when("extensions", func() { + it.Before(func() { + latestBuild.Status.BuildMetadataExtensions = []corev1alpha1.BuildpackMetadata{ + {Id: "extension.matches", Version: "1"}, + } + }) + + it("false if builder has additional unused extensions", func() { + builder.BuilderMetadataExtensions = []corev1alpha1.BuildpackMetadata{ + {Id: "extension.matches", Version: "1"}, + {Id: "extension.unused", Version: "unused"}, + } + + result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) + assert.NoError(t, err) + assert.Equal(t, corev1.ConditionFalse, result.ConditionStatus) + assert.Equal(t, "", result.PriorityClass) + assert.Equal(t, "", result.ReasonsStr) + assert.Equal(t, "", result.ChangesStr) + }) + + it("true if builder metadata has different extension version from used extension version", func() { + builder.BuilderMetadataExtensions = []corev1alpha1.BuildpackMetadata{ + {Id: "extension.matches", Version: "NEW_VERSION"}, + {Id: "extension.different", Version: "different"}, + } + + expectedChanges := testhelpers.CompactJSON(` +[ + { + "reason": "EXTENSION", + "old": [ + { + "id": "extension.matches", + "version": "1" + } + ], + "new": null + } +]`) - expectedChanges := testhelpers.CompactJSON(` + result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) + assert.NoError(t, err) + assert.Equal(t, corev1.ConditionTrue, result.ConditionStatus) + assert.Equal(t, buildapi.BuildReasonExtension, result.ReasonsStr) + assert.Equal(t, buildapi.BuildPriorityClassLow, result.PriorityClass) + assert.Equal(t, expectedChanges, result.ChangesStr) + }) + + it("true if builder does not have all most recent used extensions", func() { + builder.BuilderMetadataExtensions = []corev1alpha1.BuildpackMetadata{ + {Id: "extension.only.new.extensions", Version: "1"}, + {Id: "extension.only.new.or.unused.extensions", Version: "1"}, + } + + expectedChanges := testhelpers.CompactJSON(` [ { - "reason": "BUILDPACK", + "reason": "EXTENSION", "old": [ { - "id": "buildpack.matches", + "id": "extension.matches", "version": "1" } ], @@ -370,18 +449,22 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) { } ]`) - result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) - assert.NoError(t, err) - assert.Equal(t, corev1.ConditionTrue, result.ConditionStatus) - assert.Equal(t, buildapi.BuildReasonBuildpack, result.ReasonsStr) - assert.Equal(t, buildapi.BuildPriorityClassLow, result.PriorityClass) - assert.Equal(t, expectedChanges, result.ChangesStr) + result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) + assert.NoError(t, err) + assert.Equal(t, corev1.ConditionTrue, result.ConditionStatus) + assert.Equal(t, buildapi.BuildReasonExtension, result.ReasonsStr) + assert.Equal(t, buildapi.BuildPriorityClassLow, result.PriorityClass) + assert.Equal(t, expectedChanges, result.ChangesStr) + }) }) - it("true if builder has a different run image", func() { - builder.LatestRunImage = "some.registry.io/run-image@sha256:a1aa3da2a80a775df55e880b094a1a8de19b919435ad0c71c29a0983d64e65db" + when("builder has a different run image", func() { + it.Before(func() { + builder.LatestRunImage = "some.registry.io/run-image@sha256:a1aa3da2a80a775df55e880b094a1a8de19b919435ad0c71c29a0983d64e65db" + }) - expectedChanges := testhelpers.CompactJSON(` + it("true", func() { + expectedChanges := testhelpers.CompactJSON(` [ { "reason": "STACK", @@ -390,12 +473,28 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) { } ]`) - result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) - assert.NoError(t, err) - assert.Equal(t, corev1.ConditionTrue, result.ConditionStatus) - assert.Equal(t, buildapi.BuildReasonStack, result.ReasonsStr) - assert.Equal(t, buildapi.BuildPriorityClassLow, result.PriorityClass) - assert.Equal(t, expectedChanges, result.ChangesStr) + result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) + assert.NoError(t, err) + assert.Equal(t, corev1.ConditionTrue, result.ConditionStatus) + assert.Equal(t, buildapi.BuildReasonStack, result.ReasonsStr) + assert.Equal(t, buildapi.BuildPriorityClassLow, result.PriorityClass) + assert.Equal(t, expectedChanges, result.ChangesStr) + }) + + when("there are extensions", func() { + it.Before(func() { + builder.BuilderMetadataExtensions = []corev1alpha1.BuildpackMetadata{ + {Id: "some-extension-id", Version: "some-extension-version"}, + } + }) + it("false", func() { + expectedChanges := testhelpers.CompactJSON(``) + + result, err := isBuildRequired(image, latestBuild, sourceResolver, builder) + assert.NoError(t, err) + assert.Equal(t, expectedChanges, result.ChangesStr) + }) + }) }) }) @@ -799,14 +898,15 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) { } type TestBuilderResource struct { - BuilderReady bool - BuilderMetadata []corev1alpha1.BuildpackMetadata - ImagePullSecrets []corev1.LocalObjectReference - LatestImage string - LatestRunImage string - Name string - Namespace string - Kind string + BuilderReady bool + BuilderMetadataBuildpacks []corev1alpha1.BuildpackMetadata + BuilderMetadataExtensions []corev1alpha1.BuildpackMetadata + ImagePullSecrets []corev1.LocalObjectReference + LatestImage string + LatestRunImage string + Name string + Namespace string + Kind string } func (t TestBuilderResource) BuildBuilderSpec() corev1alpha1.BuildBuilderSpec { @@ -821,7 +921,11 @@ func (t TestBuilderResource) Ready() bool { } func (t TestBuilderResource) BuildpackMetadata() corev1alpha1.BuildpackMetadataList { - return t.BuilderMetadata + return t.BuilderMetadataBuildpacks +} + +func (t TestBuilderResource) ExtensionMetadata() corev1alpha1.BuildpackMetadataList { + return t.BuilderMetadataExtensions } func (t TestBuilderResource) RunImage() string { diff --git a/pkg/reconciler/image/image_test.go b/pkg/reconciler/image/image_test.go index 679642d56..384cd6f9e 100644 --- a/pkg/reconciler/image/image_test.go +++ b/pkg/reconciler/image/image_test.go @@ -1642,7 +1642,7 @@ func testImageReconciler(t *testing.T, when spec.G, it spec.S) { RunImage: "some/run@sha256:67e3de2af270bf09c02e9a644aeb7e87e6b3c049abe6766bf6b6c3728a83e7fb", ID: "io.buildpacks.stacks.bionic", }, - BuildMetadata: corev1alpha1.BuildpackMetadataList{ + BuildMetadataBuildpacks: corev1alpha1.BuildpackMetadataList{ { Id: "io.buildpack", Version: "old-version", @@ -1812,7 +1812,7 @@ func testImageReconciler(t *testing.T, when spec.G, it spec.S) { RunImage: "gcr.io/test-project/install/run@sha256:42841631725942db48b7ba8b788b97374a2ada34c84ee02ca5e02ef3d4b0dfca", ID: "io.buildpacks.stacks.bionic", }, - BuildMetadata: corev1alpha1.BuildpackMetadataList{ + BuildMetadataBuildpacks: corev1alpha1.BuildpackMetadataList{ { Id: "io.buildpack", Version: "version", diff --git a/test/execute_build_test.go b/test/execute_build_test.go index d00617f38..fd82b15ac 100644 --- a/test/execute_build_test.go +++ b/test/execute_build_test.go @@ -105,7 +105,7 @@ func testCreateImage(t *testing.T, _ spec.G, it spec.S) { imageName := fmt.Sprintf("%s-%s", name, builderType) builder := builderConfigs[builderType] var builderHasExtensions bool - if strings.Contains(builder.Name, "extensions") { // TODO: this is a bit hacky, maybe we can improve it + if strings.Contains(builder.Name, "extensions") { // FIXME: this is a bit hacky, maybe we can improve it builderHasExtensions = true } @@ -146,15 +146,17 @@ func testCreateImage(t *testing.T, _ spec.G, it spec.S) { var lifecycleMD files.LayersMetadata require.NoError(t, json.Unmarshal([]byte(lifecycleMDLabel), &lifecycleMD)) runImageReference := lifecycleMD.RunImage.Reference - require.Contains(t, runImageReference, "gcr.io/paketo-buildpacks/run-jammy-tiny") + require.Contains(t, runImageReference, "paketobuildpacks/run-jammy-tiny") } expectLogs = func(t *testing.T, logs string) { - require.Contains(t, logs, "Setting up curl") + require.Contains(t, logs, "curl --version") } } builtImages[validateImageCreate(t, clients, image, expectedResources, expectImage, expectLogs)] = struct{}{} - validateRebase(t, ctx, clients, image.Name, testNamespace) + if !builderHasExtensions { + validateRebase(t, ctx, clients, image.Name, testNamespace) + } }) } } @@ -531,7 +533,7 @@ func testCreateImage(t *testing.T, _ spec.G, it spec.S) { { BuildpackRef: corev1alpha1.BuildpackRef{ BuildpackInfo: corev1alpha1.BuildpackInfo{ - Id: "samples/curl", // FIXME + Id: "samples/curl", }, }, }, @@ -729,7 +731,7 @@ func testCreateImage(t *testing.T, _ spec.G, it spec.S) { { BuildpackRef: corev1alpha1.BuildpackRef{ BuildpackInfo: corev1alpha1.BuildpackInfo{ - Id: "samples/curl", // FIXME + Id: "samples/curl", }, }, }, @@ -748,7 +750,7 @@ func testCreateImage(t *testing.T, _ spec.G, it spec.S) { waitUntilReady(t, ctx, clients, builder, clusterBuilder, builderWithExtensions, clusterBuilderWithExtensions) }) - it.Focus("builds and rebases git, blob, and registry images from unauthenticated sources", func() { + it("builds and rebases git, blob, and registry images from unauthenticated sources", func() { imageSources := map[string]corev1alpha1.SourceConfig{ "git-image": { Git: &corev1alpha1.Git{ @@ -946,7 +948,7 @@ func waitUntilReady(t *testing.T, ctx context.Context, clients *clients, objects require.NoError(t, err) return kResource.Status.GetCondition(apis.ConditionReady).IsTrue() - }, 1*time.Second, 8*time.Minute) + }, 1*time.Second, 16*time.Minute) } } @@ -966,7 +968,7 @@ func waitUntilFailed(t *testing.T, ctx context.Context, clients *clients, expect condition := kResource.Status.GetCondition(apis.ConditionReady) return condition.IsFalse() && "" != condition.Message && strings.Contains(condition.Message, expectedMessage) - }, 1*time.Second, 8*time.Minute) + }, 1*time.Second, 16*time.Minute) } } @@ -1039,7 +1041,7 @@ func validateRebase(t *testing.T, ctx context.Context, clients *clients, imageNa build, err := clients.client.KpackV1alpha2().Builds(testNamespace).Get(ctx, rebaseBuildName, metav1.GetOptions{}) require.NoError(t, err) - //rebase and completion + // rebase and completion require.LessOrEqual(t, len(build.Status.StepsCompleted), 2) return build.Status.GetCondition(corev1alpha1.ConditionSucceeded).IsTrue()