From 765007bb875cc381421bbcd5e8d3572528310af8 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 28 Feb 2026 04:09:56 +0000 Subject: [PATCH] Fix stale resourceVersion bug in push controller The push controller updates status to InProgress then later to Succeeded/Failed. The first UpdateStatus call returns a new object with an updated resourceVersion, but the code was discarding it. Subsequent status updates used the stale resourceVersion, causing 409 Conflict errors and an infinite retry loop where transactions never reached a terminal phase. Fix: capture the returned object from the InProgress UpdateStatus so subsequent calls use the correct resourceVersion. Also adds better timeout diagnostics in e2e test helpers. https://claude.ai/code/session_01QfFzqKQUsxxBsiZUhuJ3pG --- pkg/reconciler/push/push.go | 6 ++++-- test/e2e/e2e_test.go | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/pkg/reconciler/push/push.go b/pkg/reconciler/push/push.go index 50ea906..a333e98 100644 --- a/pkg/reconciler/push/push.go +++ b/pkg/reconciler/push/push.go @@ -48,11 +48,13 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, key string) reconciler.E return nil } - // Mark as in-progress. + // Mark as in-progress. Capture the returned object to get the + // updated resourceVersion for subsequent status updates. now := metav1.Now() txn.Status.Phase = gitv1alpha1.TransactionPhaseInProgress txn.Status.StartTime = &now - if _, err := r.gitClient.GitPushTransactions(namespace).UpdateStatus(ctx, txn, metav1.UpdateOptions{}); err != nil { + txn, err = r.gitClient.GitPushTransactions(namespace).UpdateStatus(ctx, txn, metav1.UpdateOptions{}) + if err != nil { return fmt.Errorf("updating status to InProgress: %w", err) } diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index a59898b..92ebc67 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -227,6 +227,7 @@ func waitForPushTransaction(t *testing.T, name string) *gitv1alpha1.GitPushTrans ctx := context.Background() deadline := time.Now().Add(pollTimeout) + var lastTxn *gitv1alpha1.GitPushTransaction for time.Now().Before(deadline) { txn, err := gitClient.GitPushTransactions(testNamespace).Get(ctx, name, metav1.GetOptions{}) if err != nil { @@ -234,6 +235,7 @@ func waitForPushTransaction(t *testing.T, name string) *gitv1alpha1.GitPushTrans time.Sleep(pollInterval) continue } + lastTxn = txn t.Logf("GitPushTransaction %q phase: %s", name, txn.Status.Phase) switch txn.Status.Phase { case gitv1alpha1.TransactionPhaseSucceeded: @@ -243,6 +245,9 @@ func waitForPushTransaction(t *testing.T, name string) *gitv1alpha1.GitPushTrans } time.Sleep(pollInterval) } + if lastTxn != nil { + t.Logf("Last seen state: phase=%q message=%q resourceVersion=%s", lastTxn.Status.Phase, lastTxn.Status.Message, lastTxn.ResourceVersion) + } t.Fatalf("timed out waiting for GitPushTransaction %q", name) return nil }