-- CRD spec: https://gitops-promoter.readthedocs.io/en/latest/crd-specs/#changetransferpolicy -- Promoter finalizers: https://gitops-promoter.readthedocs.io/en/latest/debugging/finalizers/ local function formatDeletingWithFinalizers(base, finalizers, catalog) if not finalizers then return base end local parts = { base } for _, f in ipairs(finalizers) do local e = catalog[f] if e then table.insert(parts, f .. ": " .. e.wait .. " Risk if removed manually: " .. e.risk) end end return table.concat(parts, " ") end local hs = {} hs.status = "Progressing" hs.message = "Initializing change transfer policy" -- Check for deletion timestamp if obj.metadata.deletionTimestamp then hs.status = "Progressing" hs.message = formatDeletingWithFinalizers( "Change transfer policy is being deleted.", obj.metadata.finalizers, { ["changetransferpolicy.promoter.argoproj.io/finalizer"] = { wait = "Waiting to clear related PullRequest finalizers and finish cleanup before this policy is removed.", risk = "The 'changetransferpolicy.promoter.argoproj.io/pullrequest-finalizer' finalizer may not be cleaned up from PullRequests owned by this ChangeTransferPolicy.", }, } ) return hs end -- Check if status exists if not obj.status then return hs end -- Check for reconciliation conditions local hasReadyCondition = false if obj.status.conditions then for _, condition in ipairs(obj.status.conditions) do if condition.type == "Ready" then hasReadyCondition = true -- Check observedGeneration vs metadata.generation within the reconciliation condition if condition.observedGeneration and obj.metadata.generation and condition.observedGeneration ~= obj.metadata.generation then hs.status = "Progressing" hs.message = "Waiting for change transfer policy spec update to be observed" return hs end -- Check for any False condition status if condition.status == "False" then hs.status = "Degraded" local msg = condition.message or "Unknown error" local reason = condition.reason or "Unknown" -- Don't include ReconciliationError in the message since it's redundant if reason == "ReconciliationError" then hs.message = "Change transfer policy reconciliation failed: " .. msg else hs.message = "Change transfer policy reconciliation failed (" .. reason .. "): " .. msg end return hs end end end end if not hasReadyCondition then hs.status = "Progressing" hs.message = "Change transfer policy is not ready yet" return hs end if not obj.status.active or not obj.status.active.dry or not obj.status.active.dry.sha or obj.status.active.dry.sha == "" then hs.status = "Progressing" hs.message = "The active commit DRY SHA is missing or empty." return hs end if not obj.status.proposed or not obj.status.proposed.dry or not obj.status.proposed.dry.sha or obj.status.proposed.dry.sha == "" then hs.status = "Progressing" hs.message = "The proposed commit DRY SHA is missing or empty." return hs end -- Helper function to get short SHA local function getShortSha(sha) if not sha or sha == "" then return "" end if string.len(sha) > 7 then return string.sub(sha, 1, 7) end return sha end if obj.status.proposed.dry.sha ~= obj.status.active.dry.sha then local pendingCount = 0 local successCount = 0 local failureCount = 0 local pendingKeys = {} local failedKeys = {} for _, status in ipairs(obj.status.proposed.commitStatuses or {}) do if status.phase == "pending" then pendingCount = pendingCount + 1 table.insert(pendingKeys, status.key) elseif status.phase == "success" then successCount = successCount + 1 elseif status.phase == "failure" then failureCount = failureCount + 1 table.insert(failedKeys, status.key) end end hs.status = "Progressing" hs.message = "Promotion in progress from '" .. getShortSha(obj.status.active.dry.sha) .. "' to '" .. getShortSha(obj.status.proposed.dry.sha) .. "': " .. pendingCount .. " pending, " .. successCount .. " successful, " .. failureCount .. " failed. " if pendingCount > 0 then hs.message = hs.message .. "Pending commit statuses: " .. table.concat(pendingKeys, ", ") .. ". " end if failureCount > 0 then hs.message = hs.message .. "Failed commit statuses: " .. table.concat(failedKeys, ", ") .. ". " end return hs end local pendingCount = 0 local failureCount = 0 local successCount = 0 local pendingKeys = {} local failedKeys = {} for _, status in ipairs(obj.status.active.commitStatuses or {}) do if status.phase == "pending" then pendingCount = pendingCount + 1 table.insert(pendingKeys, status.key) elseif status.phase == "success" then successCount = successCount + 1 elseif status.phase == "failure" then failureCount = failureCount + 1 table.insert(failedKeys, status.key) end end if pendingCount > 0 or failureCount > 0 then hs.status = "Healthy" hs.message = "Environment is up-to-date, but there are non-successful active commit statuses: " .. pendingCount .. " pending, " .. successCount .. " successful, " .. failureCount .. " failed. " if pendingCount > 0 then hs.message = hs.message .. "Pending commit statuses: " .. table.concat(pendingKeys, ", ") .. ". " end if failureCount > 0 then hs.message = hs.message .. "Failed commit statuses: " .. table.concat(failedKeys, ", ") .. ". " end return hs end hs.status = "Healthy" hs.message = "Environment is up-to-date on commit " .. getShortSha(obj.status.active.dry.sha) .. "." return hs