diff --git a/cmd/release-controller/sync_release_payload.go b/cmd/release-controller/sync_release_payload.go index adcbb26ff..a8fd90935 100644 --- a/cmd/release-controller/sync_release_payload.go +++ b/cmd/release-controller/sync_release_payload.go @@ -51,10 +51,6 @@ func newReleasePayload(release *releasecontroller.Release, tag *imagev1.TagRefer Namespace: jobNamespace, ReleaseCreationJobName: name, }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: jobNamespace, - ReleaseMirrorJobName: releaseMirrorJobName(name), - }, ProwCoordinates: v1alpha1.ProwCoordinates{Namespace: prowNamespace}, }, PayloadVerificationConfig: v1alpha1.PayloadVerificationConfig{ @@ -79,6 +75,14 @@ func newReleasePayload(release *releasecontroller.Release, tag *imagev1.TagRefer }} } + // We should only be populating the ReleaseMirrorCoordinates if/when they are actually defined... + if release.Config.AlternateImageRepository != "" && release.Config.AlternateImageRepositorySecretName != "" { + payload.Spec.PayloadCreationConfig.ReleaseMirrorCoordinates = v1alpha1.ReleaseMirrorCoordinates{ + Namespace: jobNamespace, + ReleaseMirrorJobName: releaseMirrorJobName(name), + } + } + // Sort the ReleaseVerification items into a consistent order var sortedKeys []string for key := range verificationJobs { diff --git a/cmd/release-controller/sync_release_payload_test.go b/cmd/release-controller/sync_release_payload_test.go index 7313fbc5c..f84c723ae 100644 --- a/cmd/release-controller/sync_release_payload_test.go +++ b/cmd/release-controller/sync_release_payload_test.go @@ -70,10 +70,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -121,10 +117,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -177,10 +169,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -234,10 +222,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -292,10 +276,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -350,10 +330,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -417,10 +393,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.12.11", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.12.11-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -492,10 +464,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.12.11", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.12.11-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -556,10 +524,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -625,10 +589,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -694,10 +654,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -768,10 +724,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -923,10 +875,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -1033,10 +981,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.11.0-0.nightly-2022-03-11-113341", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.11.0-0.nightly-2022-03-11-113341-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -1106,10 +1050,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.18.0-0.nightly-2025-01-01-000000", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.18.0-0.nightly-2025-01-01-000000-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, @@ -1172,10 +1112,6 @@ func TestNewReleasePayload(t *testing.T) { Namespace: "ci-release", ReleaseCreationJobName: "4.12.0", }, - ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ - Namespace: "ci-release", - ReleaseMirrorJobName: "4.12.0-alternate-mirror", - }, ProwCoordinates: v1alpha1.ProwCoordinates{ Namespace: "ci", }, diff --git a/pkg/cmd/release-payload-controller/payload_accepted_controller.go b/pkg/cmd/release-payload-controller/payload_accepted_controller.go index f43e6c174..b80aa35e0 100644 --- a/pkg/cmd/release-payload-controller/payload_accepted_controller.go +++ b/pkg/cmd/release-payload-controller/payload_accepted_controller.go @@ -39,6 +39,7 @@ const ( // - .spec.payloadOverride.override // - .status.blockingJobResults // - .status.releaseCreationJobResult.status +// - .status.releaseMirrorJobResult.status // // and populates the following condition: // - .status.conditions.PayloadAccepted @@ -137,6 +138,10 @@ func computeReleasePayloadAcceptedCondition(payload *v1alpha1.ReleasePayload) me return acceptedCondition } + if mirrorJobPending(payload) { + return acceptedCondition + } + // Check for "Accepted" PayloadOverride switch payload.Spec.PayloadOverride.Override { case v1alpha1.ReleasePayloadOverrideAccepted: @@ -180,3 +185,18 @@ func computeReleasePayloadAcceptedCondition(payload *v1alpha1.ReleasePayload) me return acceptedCondition } + +// mirrorJobPending reports whether a configured mirror job has not yet reached +// a terminal state and the payload has not already been accepted or rejected. +// When true, acceptance/rejection evaluation should wait. +func mirrorJobPending(payload *v1alpha1.ReleasePayload) bool { + if payload.Spec.PayloadCreationConfig.ReleaseMirrorCoordinates.ReleaseMirrorJobName == "" { + return false + } + if v1helpers.IsConditionTrue(payload.Status.Conditions, v1alpha1.ConditionPayloadAccepted) || + v1helpers.IsConditionTrue(payload.Status.Conditions, v1alpha1.ConditionPayloadRejected) { + return false + } + return payload.Status.ReleaseMirrorJobResult.Status != v1alpha1.ReleaseMirrorJobSuccess && + payload.Status.ReleaseMirrorJobResult.Status != v1alpha1.ReleaseMirrorJobFailed +} diff --git a/pkg/cmd/release-payload-controller/payload_accepted_controller_test.go b/pkg/cmd/release-payload-controller/payload_accepted_controller_test.go index b4cbcadfc..1cc1ea63b 100644 --- a/pkg/cmd/release-payload-controller/payload_accepted_controller_test.go +++ b/pkg/cmd/release-payload-controller/payload_accepted_controller_test.go @@ -139,6 +139,9 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{ Status: v1alpha1.ReleaseCreationJobSuccess, }, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobSuccess, + }, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateSuccess}, }, @@ -168,7 +171,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { Reason: ReleasePayloadAcceptedReason, }, }, - // === PayloadOverride (second precedence) === + // === PayloadOverride (third precedence — after mirror job) === { name: "OverrideAccepted", payload: &v1alpha1.ReleasePayload{ @@ -293,12 +296,347 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { Message: "Force reject despite success", }, }, + // === Mirror job (second precedence — blocks overrides until terminal) === + { + name: "MirrorJobUnsetBlocksAcceptance", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.11.0-0.nightly-2022-02-09-091559-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateSuccess}, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionUnknown, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "MirrorJobUnknownBlocksAcceptance", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.11.0-0.nightly-2022-02-09-091559-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateSuccess}, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionUnknown, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "MirrorJobFailedDoesNotPreventAcceptance", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.11.0-0.nightly-2022-02-09-091559-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobFailed, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateSuccess}, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "MirrorJobSuccessAllowsAcceptance", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.11.0-0.nightly-2022-02-09-091559-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobSuccess, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateSuccess}, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "NoMirrorJobConfiguredSkipsGate", + payload: &v1alpha1.ReleasePayload{ + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateSuccess}, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "AlreadyAcceptedSkipsMirrorGate", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-104147-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateSuccess}, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadAcceptedReason, + }, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "AlreadyAcceptedWithUnsetMirrorSkipsGate", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-104147-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateSuccess}, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadAcceptedReason, + }, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "AlreadyRejectedSkipsMirrorGateInAcceptedController", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-104147-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateFailure}, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionFalse, + Reason: ReleasePayloadAcceptedReason, + }, + { + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadRejectedReason, + }, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionFalse, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "NotYetAcceptedStillBlockedByMirror", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-104147-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateSuccess}, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionUnknown, + Reason: ReleasePayloadAcceptedReason, + }, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionUnknown, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "MirrorJobBlocksOverrideAccepted", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.11.0-0.nightly-2022-02-09-091559-alternate-mirror", + }, + }, + PayloadOverride: v1alpha1.ReleasePayloadOverride{ + Override: v1alpha1.ReleasePayloadOverrideAccepted, + Reason: "Force accept", + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionUnknown, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "MirrorJobBlocksOverrideRejected", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.11.0-0.nightly-2022-02-09-091559-alternate-mirror", + }, + }, + PayloadOverride: v1alpha1.ReleasePayloadOverride{ + Override: v1alpha1.ReleasePayloadOverrideRejected, + Reason: "Force reject", + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionUnknown, + Reason: ReleasePayloadAcceptedReason, + }, + }, + { + name: "MirrorJobTerminalAllowsOverrideAccepted", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.11.0-0.nightly-2022-02-09-091559-alternate-mirror", + }, + }, + PayloadOverride: v1alpha1.ReleasePayloadOverride{ + Override: v1alpha1.ReleasePayloadOverrideAccepted, + Reason: "Force accept", + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobFailed, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadManuallyAcceptedReason, + Message: "Force accept", + }, + }, // === Blocking job results (lowest precedence) === { name: "AllBlockingJobsSuccessful", payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {CIConfigurationName: "job-a", AggregateState: v1alpha1.JobStateSuccess}, {CIConfigurationName: "job-b", AggregateState: v1alpha1.JobStateSuccess}, @@ -317,6 +655,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateSuccess}, }, @@ -333,6 +672,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateFailure}, }, @@ -349,6 +689,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStatePending}, }, @@ -365,6 +706,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateSuccess}, {AggregateState: v1alpha1.JobStatePending}, @@ -383,6 +725,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateSuccess}, {AggregateState: v1alpha1.JobStateSuccess}, @@ -401,6 +744,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateSuccess}, {AggregateState: v1alpha1.JobStateFailure}, @@ -419,6 +763,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStatePending}, {AggregateState: v1alpha1.JobStatePending}, @@ -436,6 +781,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateFailure}, {AggregateState: v1alpha1.JobStateFailure}, @@ -453,6 +799,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateSuccess}, {AggregateState: v1alpha1.JobStateUnknown}, @@ -471,6 +818,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateSuccess}, {AggregateState: ""}, @@ -489,7 +837,8 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, - BlockingJobResults: []v1alpha1.JobStatus{}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, + BlockingJobResults: []v1alpha1.JobStatus{}, }, }, expected: metav1.Condition{ @@ -504,6 +853,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateSuccess}, }, @@ -523,6 +873,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ {AggregateState: v1alpha1.JobStateSuccess}, }, @@ -543,6 +894,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, InformingJobResults: []v1alpha1.JobStatus{ {CIConfigurationName: "informing-a", AggregateState: v1alpha1.JobStateSuccess}, {CIConfigurationName: "informing-b", AggregateState: v1alpha1.JobStateSuccess}, @@ -560,6 +912,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, InformingJobResults: []v1alpha1.JobStatus{ {CIConfigurationName: "informing-a", AggregateState: v1alpha1.JobStateSuccess}, {CIConfigurationName: "informing-b", AggregateState: v1alpha1.JobStateFailure}, @@ -577,6 +930,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, InformingJobResults: []v1alpha1.JobStatus{ {CIConfigurationName: "informing-a", AggregateState: v1alpha1.JobStatePending}, {CIConfigurationName: "informing-b", AggregateState: v1alpha1.JobStateSuccess}, @@ -594,6 +948,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, InformingJobResults: []v1alpha1.JobStatus{ {CIConfigurationName: "informing-a"}, {CIConfigurationName: "informing-b"}, @@ -611,6 +966,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, UpgradeJobResults: []v1alpha1.JobStatus{ {CIConfigurationName: "upgrade-a", AggregateState: v1alpha1.JobStateSuccess}, }, @@ -627,6 +983,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, UpgradeJobResults: []v1alpha1.JobStatus{ {CIConfigurationName: "upgrade-a", AggregateState: v1alpha1.JobStatePending}, }, @@ -643,6 +1000,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, InformingJobResults: []v1alpha1.JobStatus{ {CIConfigurationName: "informing-a", AggregateState: v1alpha1.JobStateSuccess}, }, @@ -665,6 +1023,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, InformingJobResults: []v1alpha1.JobStatus{ {CIConfigurationName: "informing-a", AggregateState: v1alpha1.JobStateFailure}, }, @@ -684,6 +1043,7 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { payload: &v1alpha1.ReleasePayload{ Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, InformingJobResults: []v1alpha1.JobStatus{ {CIConfigurationName: "informing-a", AggregateState: v1alpha1.JobStateSuccess}, {CIConfigurationName: "informing-b", AggregateState: v1alpha1.JobStateFailure}, @@ -711,6 +1071,171 @@ func TestComputeReleasePayloadAcceptedCondition(t *testing.T) { } } +func TestMirrorJobPending(t *testing.T) { + t.Parallel() + testCases := []struct { + name string + payload *v1alpha1.ReleasePayload + expected bool + }{ + { + name: "NoMirrorConfigured", + payload: &v1alpha1.ReleasePayload{}, + expected: false, + }, + { + name: "MirrorConfiguredStatusUnset", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "test-alternate-mirror", + }, + }, + }, + }, + expected: true, + }, + { + name: "MirrorConfiguredStatusUnknown", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "test-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + }, + }, + expected: true, + }, + { + name: "MirrorConfiguredStatusSuccess", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "test-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobSuccess, + }, + }, + }, + expected: false, + }, + { + name: "MirrorConfiguredStatusFailed", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "test-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobFailed, + }, + }, + }, + expected: false, + }, + { + name: "AlreadyAcceptedSkipsGate", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "test-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadAcceptedReason, + }, + }, + }, + }, + expected: false, + }, + { + name: "AlreadyRejectedSkipsGate", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "test-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadRejectedReason, + }, + }, + }, + }, + expected: false, + }, + { + name: "ConditionFalseDoesNotSkipGate", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "test-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionFalse, + Reason: ReleasePayloadAcceptedReason, + }, + }, + }, + }, + expected: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := mirrorJobPending(tc.payload) + if result != tc.expected { + t.Errorf("expected %v, got %v", tc.expected, result) + } + }) + } +} func TestPayloadAcceptedSync(t *testing.T) { t.Parallel() @@ -920,6 +1445,7 @@ func TestPayloadAcceptedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -940,6 +1466,7 @@ func TestPayloadAcceptedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -970,6 +1497,7 @@ func TestPayloadAcceptedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -990,6 +1518,7 @@ func TestPayloadAcceptedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -1020,6 +1549,7 @@ func TestPayloadAcceptedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -1040,6 +1570,7 @@ func TestPayloadAcceptedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -1070,6 +1601,7 @@ func TestPayloadAcceptedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -1090,6 +1622,7 @@ func TestPayloadAcceptedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, diff --git a/pkg/cmd/release-payload-controller/payload_rejected_controller.go b/pkg/cmd/release-payload-controller/payload_rejected_controller.go index 89613633c..31380bfc6 100644 --- a/pkg/cmd/release-payload-controller/payload_rejected_controller.go +++ b/pkg/cmd/release-payload-controller/payload_rejected_controller.go @@ -40,6 +40,7 @@ const ( // - .spec.payloadOverride.override // - .status.blockingJobResults // - .status.releaseCreationJobResult.status +// - .status.releaseMirrorJobResult.status // // and populates the following condition: // - .status.conditions.PayloadRejected @@ -140,6 +141,10 @@ func computeReleasePayloadRejectedCondition(payload *v1alpha1.ReleasePayload) me return rejectedCondition } + if mirrorJobPending(payload) { + return rejectedCondition + } + // Check for PayloadOverride switch payload.Spec.PayloadOverride.Override { case v1alpha1.ReleasePayloadOverrideRejected: diff --git a/pkg/cmd/release-payload-controller/payload_rejected_controller_test.go b/pkg/cmd/release-payload-controller/payload_rejected_controller_test.go index 3f695abfd..677fc18b6 100644 --- a/pkg/cmd/release-payload-controller/payload_rejected_controller_test.go +++ b/pkg/cmd/release-payload-controller/payload_rejected_controller_test.go @@ -383,6 +383,7 @@ func TestPayloadRejectedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -403,6 +404,7 @@ func TestPayloadRejectedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -433,6 +435,7 @@ func TestPayloadRejectedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -453,6 +456,7 @@ func TestPayloadRejectedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -483,6 +487,7 @@ func TestPayloadRejectedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -503,6 +508,7 @@ func TestPayloadRejectedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -533,6 +539,7 @@ func TestPayloadRejectedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -553,6 +560,7 @@ func TestPayloadRejectedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -583,6 +591,7 @@ func TestPayloadRejectedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -603,6 +612,7 @@ func TestPayloadRejectedSync(t *testing.T) { }, Status: v1alpha1.ReleasePayloadStatus{ ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{Status: v1alpha1.ReleaseMirrorJobSuccess}, BlockingJobResults: []v1alpha1.JobStatus{ { AggregateState: v1alpha1.JobStateSuccess, @@ -700,3 +710,247 @@ func TestPayloadRejectedSync(t *testing.T) { }) } } + +func TestComputeReleasePayloadRejectedCondition(t *testing.T) { + t.Parallel() + testCases := []struct { + name string + payload *v1alpha1.ReleasePayload + expected metav1.Condition + }{ + { + name: "MirrorJobUnsetBlocksRejection", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateFailure}, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionUnknown, + Reason: ReleasePayloadRejectedReason, + }, + }, + { + name: "MirrorJobUnknownBlocksRejection", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateFailure}, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionUnknown, + Reason: ReleasePayloadRejectedReason, + }, + }, + { + name: "MirrorJobFailedDoesNotCauseRejection", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobFailed, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateSuccess}, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionFalse, + Reason: ReleasePayloadRejectedReason, + }, + }, + { + name: "NoMirrorJobConfiguredSkipsGate", + payload: &v1alpha1.ReleasePayload{ + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateFailure}, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadRejectedReason, + }, + }, + { + name: "AlreadyRejectedSkipsMirrorGate", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateFailure}, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadRejectedReason, + }, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadRejectedReason, + }, + }, + { + name: "AlreadyRejectedWithUnsetMirrorSkipsGate", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateFailure}, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadRejectedReason, + }, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadRejectedReason, + }, + }, + { + name: "AlreadyAcceptedSkipsMirrorGateInRejectedController", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateSuccess}, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadAccepted, + Status: metav1.ConditionTrue, + Reason: ReleasePayloadAcceptedReason, + }, + { + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionFalse, + Reason: ReleasePayloadRejectedReason, + }, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionFalse, + Reason: ReleasePayloadRejectedReason, + }, + }, + { + name: "NotYetRejectedStillBlockedByMirror", + payload: &v1alpha1.ReleasePayload{ + Spec: v1alpha1.ReleasePayloadSpec{ + PayloadCreationConfig: v1alpha1.PayloadCreationConfig{ + ReleaseMirrorCoordinates: v1alpha1.ReleaseMirrorCoordinates{ + ReleaseMirrorJobName: "4.23.0-0.nightly-2026-07-14-alternate-mirror", + }, + }, + }, + Status: v1alpha1.ReleasePayloadStatus{ + ReleaseCreationJobResult: v1alpha1.ReleaseCreationJobResult{Status: v1alpha1.ReleaseCreationJobSuccess}, + ReleaseMirrorJobResult: v1alpha1.ReleaseMirrorJobResult{ + Status: v1alpha1.ReleaseMirrorJobUnknown, + }, + BlockingJobResults: []v1alpha1.JobStatus{ + {AggregateState: v1alpha1.JobStateFailure}, + }, + Conditions: []metav1.Condition{ + { + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionUnknown, + Reason: ReleasePayloadRejectedReason, + }, + }, + }, + }, + expected: metav1.Condition{ + Type: v1alpha1.ConditionPayloadRejected, + Status: metav1.ConditionUnknown, + Reason: ReleasePayloadRejectedReason, + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + result := computeReleasePayloadRejectedCondition(tc.payload) + if diff := cmp.Diff(tc.expected, result, cmpopts.IgnoreFields(metav1.Condition{}, "LastTransitionTime")); diff != "" { + t.Errorf("unexpected condition (-expected +got):\n%s", diff) + } + }) + } +}