diff --git a/api/v1alpha1/freight_types.go b/api/v1alpha1/freight_types.go index ae2f1c433b..1891edbcd2 100644 --- a/api/v1alpha1/freight_types.go +++ b/api/v1alpha1/freight_types.go @@ -30,6 +30,10 @@ type Freight struct { // present, the defaulting webhook will choose an available alias and assign // it to both the field and label. Alias string `json:"alias,omitempty" protobuf:"bytes,7,opt,name=alias"` + // DiscoveryTimestamp is the time at which the Freight was first discovered + // from its source. This is distinct from metadata.creationTimestamp, which is + // set by Kubernetes and cannot be controlled by users. + DiscoveryTimestamp *metav1.Time `json:"discoveryTimestamp,omitempty" protobuf:"bytes,11,opt,name=discoveryTimestamp"` // Origin describes a kind of Freight in terms of its origin. // // +kubebuilder:validation:Required diff --git a/api/v1alpha1/promotion_types.go b/api/v1alpha1/promotion_types.go index 08100b45e2..07b299b607 100644 --- a/api/v1alpha1/promotion_types.go +++ b/api/v1alpha1/promotion_types.go @@ -142,6 +142,10 @@ func (s PromotionStepStatus) Compare(other PromotionStepStatus) int { type Promotion struct { metav1.TypeMeta `json:",inline"` metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + // DiscoveryTimestamp is the time at which the Promotion was created. + // This is distinct from metadata.creationTimestamp, which is + // set by Kubernetes and cannot be controlled by users. + DiscoveryTimestamp *metav1.Time `json:"discoveryTimestamp,omitempty" protobuf:"bytes,4,opt,name=discoveryTimestamp"` // Spec describes the desired transition of a specific Stage into a specific // Freight. // diff --git a/pkg/controller/stages/regular_stages.go b/pkg/controller/stages/regular_stages.go index 2ab8db2e24..99a9650500 100644 --- a/pkg/controller/stages/regular_stages.go +++ b/pkg/controller/stages/regular_stages.go @@ -1721,10 +1721,15 @@ func (r *RegularStageReconciler) autoPromoteFreight( ) } - // Find the latest Freight by sorting the available Freight by creation time + // Find the latest Freight by sorting the available Freight by discovery time // in descending order. slices.SortFunc(freight, func(lhs, rhs kargoapi.Freight) int { - return rhs.CreationTimestamp.Compare(lhs.CreationTimestamp.Time) + lhsTime := lhs.DiscoveryTimestamp + rhsTime := rhs.DiscoveryTimestamp + if lhsTime == nil || rhsTime == nil { + return rhs.CreationTimestamp.Compare(lhs.CreationTimestamp.Time) + } + return rhsTime.Time.Compare(lhsTime.Time) }) latestFreight := freight[0] @@ -1811,11 +1816,16 @@ func (r *RegularStageReconciler) autoPromoteFreight( latestFreight.Name, stage.Namespace, err, ) } - if len(promotions.Items) > 0 { - // Sort the terminal Promotions by creation time in descending order - slices.SortFunc(promotions.Items, func(lhs, rhs kargoapi.Promotion) int { +if len(promotions.Items) > 0 { + // Sort the terminal Promotions by discovery time in descending order + slices.SortFunc(promotions.Items, func(lhs, rhs kargoapi.Promotion) int { + lhsTime := lhs.DiscoveryTimestamp + rhsTime := rhs.DiscoveryTimestamp + if lhsTime == nil || rhsTime == nil { return rhs.CreationTimestamp.Compare(lhs.CreationTimestamp.Time) - }) + } + return rhsTime.Time.Compare(lhsTime.Time) + }) newestPromotion := promotions.Items[0] if newestPromotion.Status.Phase != kargoapi.PromotionPhaseSucceeded { freightLogger.Debug( diff --git a/pkg/controller/warehouses/warehouses.go b/pkg/controller/warehouses/warehouses.go index 55c03ece0b..03d4b78109 100644 --- a/pkg/controller/warehouses/warehouses.go +++ b/pkg/controller/warehouses/warehouses.go @@ -572,6 +572,7 @@ func (r *reconciler) buildFreightFromLatestArtifacts( ObjectMeta: metav1.ObjectMeta{ Namespace: namespace, }, + DiscoveryTimestamp: &metav1.Time{Time: time.Now()}, } for _, result := range artifacts.Git { diff --git a/pkg/kargo/promotion_builder.go b/pkg/kargo/promotion_builder.go index f1f6c20818..677548f4ae 100644 --- a/pkg/kargo/promotion_builder.go +++ b/pkg/kargo/promotion_builder.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "strings" + "time" "github.com/oklog/ulid/v2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -82,6 +83,7 @@ func (b *PromotionBuilder) Build( Namespace: stage.Namespace, Annotations: annotations, }, + DiscoveryTimestamp: &metav1.Time{Time: time.Now()}, Spec: kargoapi.PromotionSpec{ Stage: stage.Name, Freight: freight, diff --git a/pkg/server/query_freights_v1alpha1.go b/pkg/server/query_freights_v1alpha1.go index e37dd408f1..f03e1206fe 100644 --- a/pkg/server/query_freights_v1alpha1.go +++ b/pkg/server/query_freights_v1alpha1.go @@ -292,7 +292,12 @@ func sortFreightSlice(orderBy string, reverse bool, freight []*kargoapi.Freight) return strings.Compare(lhsTag, rhsTag) } } - return lhs.CreationTimestamp.Compare(rhs.CreationTimestamp.Time) + lhsTime := lhs.DiscoveryTimestamp + rhsTime := rhs.DiscoveryTimestamp + if lhsTime == nil || rhsTime == nil { + return lhs.CreationTimestamp.Time.Compare(rhs.CreationTimestamp.Time) + } + return rhsTime.Time.Compare(lhsTime.Time) }) if reverse { slices.Reverse(freight)