Skip to content

Commit

Permalink
Trigger a new build when the lifecycle changes
Browse files Browse the repository at this point in the history
Signed-off-by: Natalie Arellano <[email protected]>
  • Loading branch information
natalieparellano committed May 29, 2024
1 parent b54d5c5 commit 94736b7
Show file tree
Hide file tree
Showing 8 changed files with 338 additions and 40 deletions.
2 changes: 1 addition & 1 deletion pkg/apis/build/v1alpha2/builder_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type BuilderResource interface {
UpToDate() bool
BuildpackMetadata() corev1alpha1.BuildpackMetadataList
RunImage() string
// TODO: confirm, should we add LifecycleVersion here?
LifecycleImage() string
GetKind() string
ConditionReadyMessage() string
}
1 change: 0 additions & 1 deletion pkg/apis/build/v1alpha2/image_builds.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ const (
BuildReasonCommit = "COMMIT"
BuildReasonBuildpack = "BUILDPACK"
BuildReasonStack = "STACK"
// TODO: use this somewhere
BuildReasonLifecycle = "LIFECYCLE"
BuildReasonTrigger = "TRIGGER"
)
Expand Down
23 changes: 14 additions & 9 deletions pkg/apis/build/v1alpha2/image_builds_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -371,15 +371,16 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) {
}

type TestBuilderResource struct {
BuilderReady bool
BuilderUpToDate bool
BuilderMetadata []corev1alpha1.BuildpackMetadata
ImagePullSecrets []corev1.LocalObjectReference
Kind string
LatestImage string
LatestRunImage string
Name string
Namespace string
BuilderReady bool
BuilderUpToDate bool
BuilderMetadata []corev1alpha1.BuildpackMetadata
ImagePullSecrets []corev1.LocalObjectReference
Kind string
LatestImage string
LatestRunImage string
LatestLifecycleImage string
Name string
Namespace string
}

func (t TestBuilderResource) ConditionReadyMessage() string {
Expand Down Expand Up @@ -409,6 +410,10 @@ func (t TestBuilderResource) RunImage() string {
return t.LatestRunImage
}

func (t TestBuilderResource) LifecycleImage() string {
return t.LatestLifecycleImage
}

func (t TestBuilderResource) GetName() string {
return t.Name
}
Expand Down
52 changes: 52 additions & 0 deletions pkg/buildchange/lifecycle_change.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package buildchange

import (
"strings"

"github.com/google/go-containerregistry/pkg/name"
"github.com/pkg/errors"

buildapi "github.com/pivotal/kpack/pkg/apis/build/v1alpha2"
)

func NewLifecycleChange(oldLifecycleImageRefStr, newLifecycleImageRefStr string) Change {
var change lifecycleChange
var errStrs []string

oldLifecycleImageRef, err := name.ParseReference(oldLifecycleImageRefStr)
if err != nil {
errStrs = append(errStrs, err.Error())
} else {
change.oldLifecycleImageDigest = oldLifecycleImageRef.Identifier()
}

newLifecycleImageRef, err := name.ParseReference(newLifecycleImageRefStr)
if err != nil {
errStrs = append(errStrs, err.Error())
} else {
change.newLifecycleImageDigest = newLifecycleImageRef.Identifier()
}

if len(errStrs) > 0 {
change.err = errors.New(strings.Join(errStrs, "; "))
}
return change
}

type lifecycleChange struct {
oldLifecycleImageDigest string
newLifecycleImageDigest string
err error
}

func (l lifecycleChange) Reason() buildapi.BuildReason { return buildapi.BuildReasonLifecycle }

func (l lifecycleChange) IsBuildRequired() (bool, error) {
return l.oldLifecycleImageDigest != l.newLifecycleImageDigest, l.err
}

func (l lifecycleChange) Old() interface{} { return l.oldLifecycleImageDigest }

func (l lifecycleChange) New() interface{} { return l.newLifecycleImageDigest }

func (l lifecycleChange) Priority() buildapi.BuildPriority { return buildapi.BuildPriorityLow }
8 changes: 6 additions & 2 deletions pkg/duckbuilder/duck_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ func (b *DuckBuilder) Ready() bool {
}

func (b *DuckBuilder) UpToDate() bool {
return b.Status.GetCondition(buildapi.ConditionUpToDate).IsTrue() &&
(b.Generation == b.Status.ObservedGeneration)
return b.Status.GetCondition(buildapi.ConditionUpToDate).IsTrue() &&
(b.Generation == b.Status.ObservedGeneration)
}

func (b *DuckBuilder) BuildBuilderSpec() corev1alpha1.BuildBuilderSpec {
Expand All @@ -57,6 +57,10 @@ func (b *DuckBuilder) RunImage() string {
return b.Status.Stack.RunImage
}

func (b *DuckBuilder) LifecycleImage() string {
return b.Status.Lifecycle.Id
}

func (b *DuckBuilder) ConditionReadyMessage() string {
condition := b.Status.GetCondition(corev1alpha1.ConditionReady)
if condition == nil {
Expand Down
15 changes: 13 additions & 2 deletions pkg/reconciler/image/build_required.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ func newBuildRequiredResult(summary buildchange.ChangeSummary) buildRequiredResu
func isBuildRequired(img *buildapi.Image,
lastBuild *buildapi.Build,
srcResolver *buildapi.SourceResolver,
builder buildapi.BuilderResource) (buildRequiredResult, error) {

builder buildapi.BuilderResource,
) (buildRequiredResult, error) {
result := buildRequiredResult{ConditionStatus: corev1.ConditionUnknown}
if !srcResolver.Ready() || !builder.Ready() {
return result, nil
Expand All @@ -46,6 +46,7 @@ func isBuildRequired(img *buildapi.Image,
Process(configChange(img, lastBuild, srcResolver)).
Process(buildpackChange(lastBuild, builder)).
Process(stackChange(lastBuild, builder)).
Process(lifecycleChange(lastBuild, builder)).
Summarize()
if err != nil {
return result, err
Expand Down Expand Up @@ -131,3 +132,13 @@ func stackChange(lastBuild *buildapi.Build, builder buildapi.BuilderResource) bu
newRunImageRefStr := builder.RunImage()
return buildchange.NewStackChange(oldRunImageRefStr, newRunImageRefStr)
}

func lifecycleChange(lastBuild *buildapi.Build, builder buildapi.BuilderResource) buildchange.Change {
if lastBuild == nil || !lastBuild.IsSuccess() {
return nil
}

oldLifecycleImageRefStr := lastBuild.Status.Lifecycle.Id
newLifecycleImageRefStr := builder.LifecycleImage()
return buildchange.NewLifecycleChange(oldLifecycleImageRefStr, newLifecycleImageRefStr)
}
51 changes: 40 additions & 11 deletions pkg/reconciler/image/build_required_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,9 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) {
BuilderMetadata: []corev1alpha1.BuildpackMetadata{
{Id: "buildpack.matches", Version: "1"},
},
LatestRunImage: "some.registry.io/run-image@sha256:67e3de2af270bf09c02e9a644aeb7e87e6b3c049abe6766bf6b6c3728a83e7fb",
Kind: buildapi.BuilderKind,
LatestRunImage: "some.registry.io/run-image@sha256:67e3de2af270bf09c02e9a644aeb7e87e6b3c049abe6766bf6b6c3728a83e7fb",
LatestLifecycleImage: "some.registry.io/lifecycle-image@sha256:01d09d19c2139a46aebfb577780d123d7396e97201bc7ead210a2ebff8239dee",
Kind: buildapi.BuilderKind,
}

latestBuild := &buildapi.Build{
Expand Down Expand Up @@ -93,6 +94,9 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) {
ID: "io.buildpacks.stack.bionic",
},
LatestImage: "some.registry.io/built@sha256:67e3de2af270bf09c02e9a644aeb7e87e6b3c049abe6766bf6b6c3728a83e7fb",
Lifecycle: buildapi.ResolvedClusterLifecycle{
Id: "some.registry.io/lifecycle-image@sha256:01d09d19c2139a46aebfb577780d123d7396e97201bc7ead210a2ebff8239dee",
},
},
}

Expand Down Expand Up @@ -397,6 +401,26 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) {
assert.Equal(t, buildapi.BuildPriorityClassLow, result.PriorityClass)
assert.Equal(t, expectedChanges, result.ChangesStr)
})

it("true if builder has a different lifecycle image", func() {
builder.LatestLifecycleImage = "some.registry.io/lifecycle-image@sha256:7aa7a5359173d05b63cfd682e3c38487f3cb4f7f1d60659fe59fab1505977d4c"

expectedChanges := testhelpers.CompactJSON(`
[
{
"reason": "LIFECYCLE",
"old": "sha256:01d09d19c2139a46aebfb577780d123d7396e97201bc7ead210a2ebff8239dee",
"new": "sha256:7aa7a5359173d05b63cfd682e3c38487f3cb4f7f1d60659fe59fab1505977d4c"
}
]`)

result, err := isBuildRequired(image, latestBuild, sourceResolver, builder)
assert.NoError(t, err)
assert.Equal(t, corev1.ConditionTrue, result.ConditionStatus)
assert.Equal(t, buildapi.BuildReasonLifecycle, result.ReasonsStr)
assert.Equal(t, buildapi.BuildPriorityClassLow, result.PriorityClass)
assert.Equal(t, expectedChanges, result.ChangesStr)
})
})

when("Git", func() {
Expand Down Expand Up @@ -799,15 +823,16 @@ func testImageBuilds(t *testing.T, when spec.G, it spec.S) {
}

type TestBuilderResource struct {
BuilderReady bool
BuilderUpToDate bool
BuilderMetadata []corev1alpha1.BuildpackMetadata
ImagePullSecrets []corev1.LocalObjectReference
LatestImage string
LatestRunImage string
Name string
Namespace string
Kind string
BuilderReady bool
BuilderUpToDate bool
BuilderMetadata []corev1alpha1.BuildpackMetadata
ImagePullSecrets []corev1.LocalObjectReference
LatestImage string
LatestRunImage string
LatestLifecycleImage string
Name string
Namespace string
Kind string
}

func (t TestBuilderResource) BuildBuilderSpec() corev1alpha1.BuildBuilderSpec {
Expand All @@ -833,6 +858,10 @@ func (t TestBuilderResource) RunImage() string {
return t.LatestRunImage
}

func (t TestBuilderResource) LifecycleImage() string {
return t.LatestLifecycleImage
}

func (t TestBuilderResource) GetName() string {
return t.Name
}
Expand Down
Loading

0 comments on commit 94736b7

Please sign in to comment.