Skip to content

Commit 60974d8

Browse files
authored
Add last-deployed annotation in history (#102)
1 parent a8c730c commit 60974d8

4 files changed

Lines changed: 62 additions & 7 deletions

File tree

api/v1alpha1/function_lifecycle.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package v1alpha1
22

33
import (
44
"fmt"
5+
"sort"
6+
"time"
57

68
"k8s.io/apimachinery/pkg/api/meta"
79
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -224,11 +226,28 @@ func (f *Function) MarkServiceNotReady(reason, messageFormat string, messageA ..
224226

225227
const MaxHistoryEntries = 20
226228

227-
func (f *Function) RecordHistoryEvent(message string) {
228-
f.Status.History = append([]FunctionStatusHistoryEntry{{
229+
type historyEventOption func(entry *FunctionStatusHistoryEntry)
230+
231+
func WithHistoryEventTime(t time.Time) historyEventOption {
232+
return func(entry *FunctionStatusHistoryEntry) {
233+
entry.Time = metav1.NewTime(t)
234+
}
235+
}
236+
237+
func (f *Function) RecordHistoryEvent(message string, options ...historyEventOption) {
238+
entry := FunctionStatusHistoryEntry{
229239
Time: metav1.Now(),
230240
Message: message,
231-
}}, f.Status.History...)
241+
}
242+
243+
for _, opt := range options {
244+
opt(&entry)
245+
}
246+
247+
f.Status.History = append(f.Status.History, entry)
248+
sort.Slice(f.Status.History, func(i, j int) bool {
249+
return f.Status.History[i].Time.After(f.Status.History[j].Time.Time)
250+
})
232251
if len(f.Status.History) > MaxHistoryEntries {
233252
f.Status.History = f.Status.History[:MaxHistoryEntries]
234253
}

api/v1alpha1/function_lifecycle_test.go

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package v1alpha1
33
import (
44
"fmt"
55
"testing"
6+
"time"
67

78
"k8s.io/apimachinery/pkg/api/meta"
89
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -28,7 +29,7 @@ func TestRecordHistoryEvent(t *testing.T) {
2829
{
2930
name: "prepends event to existing history",
3031
existingHistory: []FunctionStatusHistoryEntry{
31-
{Time: metav1.Now(), Message: "Older event"},
32+
{Time: metav1.NewTime(time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)), Message: "Older event"},
3233
},
3334
newMessage: "Newer event",
3435
expectedLen: 2,
@@ -38,10 +39,11 @@ func TestRecordHistoryEvent(t *testing.T) {
3839
{
3940
name: "trims oldest entries when exceeding max",
4041
existingHistory: func() []FunctionStatusHistoryEntry {
42+
base := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
4143
entries := make([]FunctionStatusHistoryEntry, MaxHistoryEntries)
4244
for i := range entries {
4345
entries[i] = FunctionStatusHistoryEntry{
44-
Time: metav1.Now(),
46+
Time: metav1.NewTime(base.Add(time.Duration(i) * time.Minute)),
4547
Message: fmt.Sprintf("Event %d", i),
4648
}
4749
}
@@ -50,7 +52,7 @@ func TestRecordHistoryEvent(t *testing.T) {
5052
newMessage: "Overflow event",
5153
expectedLen: MaxHistoryEntries,
5254
expectedFirst: "Overflow event",
53-
expectedLast: fmt.Sprintf("Event %d", MaxHistoryEntries-2),
55+
expectedLast: fmt.Sprintf("Event %d", 1),
5456
},
5557
}
5658

@@ -76,9 +78,10 @@ func TestRecordHistoryEvent(t *testing.T) {
7678

7779
func TestRecordHistoryEventFIFOOrder(t *testing.T) {
7880
f := &Function{}
81+
base := time.Date(2025, 1, 1, 0, 0, 0, 0, time.UTC)
7982

8083
for i := 0; i < MaxHistoryEntries+5; i++ {
81-
f.RecordHistoryEvent(fmt.Sprintf("Event %d", i))
84+
f.RecordHistoryEvent(fmt.Sprintf("Event %d", i), WithHistoryEventTime(base.Add(time.Duration(i)*time.Minute)))
8285
}
8386

8487
if len(f.Status.History) != MaxHistoryEntries {
@@ -93,6 +96,28 @@ func TestRecordHistoryEventFIFOOrder(t *testing.T) {
9396
}
9497
}
9598

99+
func TestRecordHistoryEventSortsByTime(t *testing.T) {
100+
f := &Function{}
101+
now := time.Date(2025, 6, 15, 12, 0, 0, 0, time.UTC)
102+
103+
f.RecordHistoryEvent("Second event", WithHistoryEventTime(now))
104+
f.RecordHistoryEvent("First event (older)", WithHistoryEventTime(now.Add(-1*time.Hour)))
105+
f.RecordHistoryEvent("Third event", WithHistoryEventTime(now.Add(1*time.Hour)))
106+
107+
if len(f.Status.History) != 3 {
108+
t.Fatalf("expected 3 entries, got %d", len(f.Status.History))
109+
}
110+
if f.Status.History[0].Message != "Third event" {
111+
t.Errorf("expected first entry to be newest, got %q", f.Status.History[0].Message)
112+
}
113+
if f.Status.History[1].Message != "Second event" {
114+
t.Errorf("expected second entry to be middle, got %q", f.Status.History[1].Message)
115+
}
116+
if f.Status.History[2].Message != "First event (older)" {
117+
t.Errorf("expected last entry to be oldest, got %q", f.Status.History[2].Message)
118+
}
119+
}
120+
96121
func TestRecordHistoryEventSetsTime(t *testing.T) {
97122
f := &Function{}
98123
f.RecordHistoryEvent("test event")

internal/controller/function_controller.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ func applyLastDeployedAnnotation(ctx context.Context, function *v1alpha1.Functio
154154
log.FromContext(ctx).Info("could not parse "+funcAnnotationLastDeployed+" annotation", "error", err)
155155
} else {
156156
function.Status.Deployment.ImageBuilt = metav1.NewTime(t)
157+
function.RecordHistoryEvent("Function was deployed/redeployed", v1alpha1.WithHistoryEventTime(t))
157158
}
158159
}
159160
}

internal/controller/function_controller_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,16 @@ var _ = Describe("Function Controller", func() {
476476
expectedTime, err := time.Parse(time.RFC3339, "2026-01-02T15:04:05+06:00")
477477
Expect(err).NotTo(HaveOccurred())
478478
Expect(status.Deployment.ImageBuilt.UTC()).To(Equal(expectedTime.UTC()))
479+
480+
// check if it is in the history too
481+
Expect(status.History).To(ContainElement(
482+
SatisfyAll(
483+
HaveField("Message", "Function was deployed/redeployed"),
484+
WithTransform(func(e functionsdevv1alpha1.FunctionStatusHistoryEntry) time.Time {
485+
return e.Time.UTC()
486+
}, Equal(expectedTime.UTC())),
487+
),
488+
))
479489
},
480490
}),
481491
Entry("should set ServiceReady condition to false with unknown reason when ready status is empty", reconcileTestCase{

0 commit comments

Comments
 (0)