109 lines
3.7 KiB
Go
109 lines
3.7 KiB
Go
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"slices"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||
|
|
)
|
||
|
|
|
||
|
|
func (c *controller) recoverBuilds(ctx context.Context, delivery *projectDelivery) (bool, error) {
|
||
|
|
known := make(map[string]bool)
|
||
|
|
for _, attempt := range delivery.Status.Points {
|
||
|
|
known[attempt.WorkflowName] = true
|
||
|
|
}
|
||
|
|
continuous := delivery.Status.Continuous
|
||
|
|
if continuous != nil && continuous.Attempt != nil {
|
||
|
|
known[continuous.Attempt.WorkflowName] = true
|
||
|
|
if continuous.Attempt.History != nil {
|
||
|
|
for _, name := range continuous.Attempt.History.Workflows {
|
||
|
|
known[name] = true
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
items, err := c.client.Resource(workflowGVR).Namespace(delivery.Metadata.Namespace).List(ctx, metav1.ListOptions{LabelSelector: purposeAnnotation + "=build"})
|
||
|
|
if err != nil {
|
||
|
|
return false, err
|
||
|
|
}
|
||
|
|
slices.SortFunc(items.Items, func(a, b unstructured.Unstructured) int {
|
||
|
|
left, right := a.GetCreationTimestamp(), b.GetCreationTimestamp()
|
||
|
|
if order := left.Time.Compare(right.Time); order != 0 {
|
||
|
|
return order
|
||
|
|
}
|
||
|
|
return strings.Compare(a.GetName(), b.GetName())
|
||
|
|
})
|
||
|
|
recovered := false
|
||
|
|
if continuous != nil && continuous.Attempt != nil && continuous.Attempt.CreatedAt == nil {
|
||
|
|
for _, item := range items.Items {
|
||
|
|
if item.GetName() == continuous.Attempt.WorkflowName && ownedBy(&item, delivery.Metadata.UID) {
|
||
|
|
created := item.GetCreationTimestamp()
|
||
|
|
continuous.Attempt.CreatedAt = &created.Time
|
||
|
|
recovered = true
|
||
|
|
break
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
for _, item := range items.Items {
|
||
|
|
knownBuild := known[item.GetName()]
|
||
|
|
if knownBuild {
|
||
|
|
if continuous == nil || continuous.Attempt == nil || continuous.Attempt.History == nil ||
|
||
|
|
!slices.Contains(continuous.Attempt.History.Workflows, item.GetName()) || continuous.Attempt.CreatedAt == nil {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
created := item.GetCreationTimestamp()
|
||
|
|
if !created.Time.After(*continuous.Attempt.CreatedAt) {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if !ownedBy(&item, delivery.Metadata.UID) {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
state, err := c.workflow(ctx, delivery.Metadata.Namespace, item.GetName())
|
||
|
|
if err != nil {
|
||
|
|
return false, err
|
||
|
|
}
|
||
|
|
attempt := &attemptStatus{
|
||
|
|
WorkflowName: item.GetName(), Ref: state.Input["source-ref"], Revision: state.Input["source-revision"],
|
||
|
|
SourceIdentity: item.GetAnnotations()[sourceKey], RetryOf: item.GetAnnotations()[retryKey],
|
||
|
|
Phase: phaseOrPending(state.Phase), Input: state.Input, CreatedAt: state.CreatedAt,
|
||
|
|
}
|
||
|
|
if knownBuild && attempt.SourceIdentity == "" && continuous.Delivered != nil && continuous.Delivered.Revision == attempt.Revision {
|
||
|
|
attempt.SourceIdentity = continuous.Delivered.Identity
|
||
|
|
}
|
||
|
|
if result, found := state.Outputs["delivery-result"]; found {
|
||
|
|
attempt.Result = opaqueResult(result)
|
||
|
|
}
|
||
|
|
if attempt.Ref == "" {
|
||
|
|
if slices.ContainsFunc(delivery.Status.Points, func(point attemptStatus) bool { return !terminalPhase(point.Phase) }) {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
delivery.Status.Points = append(delivery.Status.Points, *attempt)
|
||
|
|
} else {
|
||
|
|
if continuous == nil {
|
||
|
|
continuous = &continuousStatus{}
|
||
|
|
delivery.Status.Continuous = continuous
|
||
|
|
}
|
||
|
|
if previous := continuous.Attempt; previous != nil {
|
||
|
|
if !terminalPhase(previous.Phase) {
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
if previous.CreatedAt != nil && previous.CreatedAt.After(*attempt.CreatedAt) {
|
||
|
|
rememberAttempt(continuous, previous)
|
||
|
|
addHistory(previous.History, attempt)
|
||
|
|
recovered = true
|
||
|
|
continue
|
||
|
|
}
|
||
|
|
}
|
||
|
|
rememberAttempt(continuous, attempt)
|
||
|
|
recordDelivered(continuous)
|
||
|
|
}
|
||
|
|
if attempt.RetryOf != "" && attempt.RetryOf == delivery.Metadata.Annotations[retryAnnotation] {
|
||
|
|
delivery.Status.LastHandledRetry = attempt.RetryOf
|
||
|
|
}
|
||
|
|
observeQualBuild(delivery, attempt)
|
||
|
|
recovered = true
|
||
|
|
}
|
||
|
|
return recovered, nil
|
||
|
|
}
|