From daadf868db028bacde40e008524ba89d49b0dc8e Mon Sep 17 00:00:00 2001 From: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> Date: Mon, 13 Apr 2026 17:09:21 -0400 Subject: [PATCH] feat(health): additional promoter.argoproj.io health checks (#27170) Signed-off-by: Michael Crenshaw <350466+crenshaw-dev@users.noreply.github.com> --- .../ClusterScmProvider/health.lua | 57 +++++++++++ .../ClusterScmProvider/health_test.yaml | 29 ++++++ .../ClusterScmProvider/testdata/deleting.yaml | 10 ++ .../ClusterScmProvider/testdata/healthy.yaml | 17 ++++ .../testdata/no-ready-condition.yaml | 17 ++++ .../testdata/no-status.yaml | 9 ++ .../observed-generation-outdated.yaml | 17 ++++ .../testdata/ready-unknown.yaml | 17 ++++ .../testdata/reconcile-error.yaml | 17 ++++ .../GitCommitStatus/health.lua | 96 +++++++++++++++++++ .../GitCommitStatus/health_test.yaml | 49 ++++++++++ .../GitCommitStatus/testdata/all-success.yaml | 32 +++++++ .../testdata/commit-statuses-not-ready.yaml | 25 +++++ .../GitCommitStatus/testdata/deleting.yaml | 10 ++ .../testdata/empty-environments.yaml | 18 ++++ .../testdata/environment-failure.yaml | 23 +++++ .../testdata/environment-pending.yaml | 22 +++++ .../testdata/expression-compile-error.yaml | 26 +++++ .../testdata/no-ready-condition.yaml | 23 +++++ .../GitCommitStatus/testdata/no-status.yaml | 9 ++ .../observed-generation-outdated.yaml | 23 +++++ .../testdata/ready-unknown.yaml | 23 +++++ .../testdata/reconcile-error.yaml | 17 ++++ .../GitRepository/health.lua | 57 +++++++++++ .../GitRepository/health_test.yaml | 29 ++++++ .../GitRepository/testdata/deleting.yaml | 13 +++ .../GitRepository/testdata/healthy.yaml | 20 ++++ .../testdata/no-ready-condition.yaml | 20 ++++ .../GitRepository/testdata/no-status.yaml | 12 +++ .../observed-generation-outdated.yaml | 20 ++++ .../GitRepository/testdata/ready-unknown.yaml | 20 ++++ .../testdata/reconcile-error.yaml | 20 ++++ .../ScmProvider/health.lua | 57 +++++++++++ .../ScmProvider/health_test.yaml | 29 ++++++ .../ScmProvider/testdata/deleting.yaml | 11 +++ .../ScmProvider/testdata/healthy.yaml | 18 ++++ .../testdata/no-ready-condition.yaml | 18 ++++ .../ScmProvider/testdata/no-status.yaml | 10 ++ .../observed-generation-outdated.yaml | 18 ++++ .../ScmProvider/testdata/ready-unknown.yaml | 18 ++++ .../ScmProvider/testdata/reconcile-error.yaml | 18 ++++ .../TimedCommitStatus/health.lua | 93 ++++++++++++++++++ .../TimedCommitStatus/health_test.yaml | 37 +++++++ .../testdata/all-success.yaml | 34 +++++++ .../TimedCommitStatus/testdata/deleting.yaml | 12 +++ .../testdata/empty-environments.yaml | 20 ++++ .../testdata/environment-failure.yaml | 26 +++++ .../testdata/environment-pending.yaml | 26 +++++ .../testdata/no-ready-condition.yaml | 19 ++++ .../TimedCommitStatus/testdata/no-status.yaml | 11 +++ .../observed-generation-outdated.yaml | 26 +++++ .../testdata/reconcile-error.yaml | 19 ++++ .../WebRequestCommitStatus/health.lua | 95 ++++++++++++++++++ .../WebRequestCommitStatus/health_test.yaml | 41 ++++++++ .../testdata/all-success.yaml | 33 +++++++ .../testdata/commit-statuses-not-ready.yaml | 30 ++++++ .../testdata/deleting.yaml | 19 ++++ .../testdata/empty-environments.yaml | 27 ++++++ .../testdata/environment-failure.yaml | 31 ++++++ .../testdata/environment-pending.yaml | 30 ++++++ .../testdata/no-ready-condition.yaml | 26 +++++ .../testdata/no-status.yaml | 18 ++++ .../observed-generation-outdated.yaml | 30 ++++++ .../testdata/reconcile-error.yaml | 26 +++++ 64 files changed, 1723 insertions(+) create mode 100644 resource_customizations/promoter.argoproj.io/ClusterScmProvider/health.lua create mode 100644 resource_customizations/promoter.argoproj.io/ClusterScmProvider/health_test.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/deleting.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/healthy.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/no-ready-condition.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/no-status.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/observed-generation-outdated.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/ready-unknown.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/reconcile-error.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/health.lua create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/health_test.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/all-success.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/commit-statuses-not-ready.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/deleting.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/empty-environments.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/environment-failure.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/environment-pending.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/expression-compile-error.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/no-ready-condition.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/no-status.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/observed-generation-outdated.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/ready-unknown.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/reconcile-error.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitRepository/health.lua create mode 100644 resource_customizations/promoter.argoproj.io/GitRepository/health_test.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitRepository/testdata/deleting.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitRepository/testdata/healthy.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitRepository/testdata/no-ready-condition.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitRepository/testdata/no-status.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitRepository/testdata/observed-generation-outdated.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitRepository/testdata/ready-unknown.yaml create mode 100644 resource_customizations/promoter.argoproj.io/GitRepository/testdata/reconcile-error.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ScmProvider/health.lua create mode 100644 resource_customizations/promoter.argoproj.io/ScmProvider/health_test.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ScmProvider/testdata/deleting.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ScmProvider/testdata/healthy.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ScmProvider/testdata/no-ready-condition.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ScmProvider/testdata/no-status.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ScmProvider/testdata/observed-generation-outdated.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ScmProvider/testdata/ready-unknown.yaml create mode 100644 resource_customizations/promoter.argoproj.io/ScmProvider/testdata/reconcile-error.yaml create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/health.lua create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/health_test.yaml create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/all-success.yaml create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/deleting.yaml create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/empty-environments.yaml create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/environment-failure.yaml create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/environment-pending.yaml create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/no-ready-condition.yaml create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/no-status.yaml create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/observed-generation-outdated.yaml create mode 100644 resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/reconcile-error.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/health.lua create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/health_test.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/all-success.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/commit-statuses-not-ready.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/deleting.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/empty-environments.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/environment-failure.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/environment-pending.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/no-ready-condition.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/no-status.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/observed-generation-outdated.yaml create mode 100644 resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/reconcile-error.yaml diff --git a/resource_customizations/promoter.argoproj.io/ClusterScmProvider/health.lua b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/health.lua new file mode 100644 index 0000000000..3101e6f273 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/health.lua @@ -0,0 +1,57 @@ +local hs = {} +hs.status = "Progressing" +hs.message = "Initializing cluster SCM provider" + +-- ClusterScmProvider (gitops-promoter v1alpha1): cluster-scoped SCM provider; same Ready semantics as ScmProvider. + +if obj.metadata.deletionTimestamp then + hs.status = "Progressing" + hs.message = "ClusterScmProvider is being deleted" + return hs +end + +if not obj.status then + return hs +end + +local hasReadyCondition = false +if obj.status.conditions then + for _, condition in ipairs(obj.status.conditions) do + if condition.type == "Ready" then + hasReadyCondition = true + if condition.observedGeneration and obj.metadata.generation and condition.observedGeneration ~= obj.metadata.generation then + hs.status = "Progressing" + hs.message = "Waiting for ClusterScmProvider spec update to be observed" + return hs + end + if condition.status == "False" then + hs.status = "Degraded" + local msg = condition.message or "Unknown error" + local reason = condition.reason or "Unknown" + if reason == "ReconciliationError" then + hs.message = "Cluster SCM provider validation failed: " .. msg + else + hs.message = "Cluster SCM provider not ready (" .. reason .. "): " .. msg + end + return hs + end + if condition.status == "Unknown" then + hs.status = "Progressing" + local msg = condition.message or "Unknown" + local reason = condition.reason or "Unknown" + hs.message = "Cluster SCM provider readiness unknown (" .. reason .. "): " .. msg + return hs + end + end + end +end + +if not hasReadyCondition then + hs.status = "Progressing" + hs.message = "ClusterScmProvider Ready condition is missing" + return hs +end + +hs.status = "Healthy" +hs.message = "Cluster SCM provider is ready" +return hs diff --git a/resource_customizations/promoter.argoproj.io/ClusterScmProvider/health_test.yaml b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/health_test.yaml new file mode 100644 index 0000000000..9eec1a9b23 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/health_test.yaml @@ -0,0 +1,29 @@ +tests: +- healthStatus: + status: Progressing + message: Initializing cluster SCM provider + inputPath: testdata/no-status.yaml +- healthStatus: + status: Progressing + message: ClusterScmProvider is being deleted + inputPath: testdata/deleting.yaml +- healthStatus: + status: Progressing + message: Waiting for ClusterScmProvider spec update to be observed + inputPath: testdata/observed-generation-outdated.yaml +- healthStatus: + status: Degraded + message: "Cluster SCM provider validation failed: Reconciliation failed: invalid credentials" + inputPath: testdata/reconcile-error.yaml +- healthStatus: + status: Progressing + message: ClusterScmProvider Ready condition is missing + inputPath: testdata/no-ready-condition.yaml +- healthStatus: + status: Progressing + message: "Cluster SCM provider readiness unknown (ValidationPending): Probing SCM endpoint" + inputPath: testdata/ready-unknown.yaml +- healthStatus: + status: Healthy + message: Cluster SCM provider is ready + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/deleting.yaml b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/deleting.yaml new file mode 100644 index 0000000000..87a3bf533d --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/deleting.yaml @@ -0,0 +1,10 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ClusterScmProvider +metadata: + name: github-enterprise + deletionTimestamp: "2025-07-04T12:00:00Z" +spec: + secretRef: + name: github-app-secret + github: + appID: 1 diff --git a/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/healthy.yaml b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/healthy.yaml new file mode 100644 index 0000000000..6012f00a57 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/healthy.yaml @@ -0,0 +1,17 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ClusterScmProvider +metadata: + name: github-enterprise + generation: 1 +spec: + secretRef: + name: github-app-secret + github: + appID: 1 +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/no-ready-condition.yaml b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/no-ready-condition.yaml new file mode 100644 index 0000000000..5be59473cc --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/no-ready-condition.yaml @@ -0,0 +1,17 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ClusterScmProvider +metadata: + name: github-enterprise + generation: 1 +spec: + secretRef: + name: github-app-secret + github: + appID: 1 +status: + conditions: + - type: Example + status: "True" + reason: Example + message: ok + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/no-status.yaml b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/no-status.yaml new file mode 100644 index 0000000000..3b89264e2a --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/no-status.yaml @@ -0,0 +1,9 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ClusterScmProvider +metadata: + name: github-enterprise +spec: + secretRef: + name: github-app-secret + github: + appID: 1 diff --git a/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/observed-generation-outdated.yaml b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/observed-generation-outdated.yaml new file mode 100644 index 0000000000..73975be1f3 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/observed-generation-outdated.yaml @@ -0,0 +1,17 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ClusterScmProvider +metadata: + name: github-enterprise + generation: 2 +spec: + secretRef: + name: github-app-secret + github: + appID: 1 +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/ready-unknown.yaml b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/ready-unknown.yaml new file mode 100644 index 0000000000..524fb9bc5d --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/ready-unknown.yaml @@ -0,0 +1,17 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ClusterScmProvider +metadata: + name: github-enterprise + generation: 1 +spec: + secretRef: + name: github-app-secret + github: + appID: 1 +status: + conditions: + - type: Ready + status: Unknown + reason: ValidationPending + message: Probing SCM endpoint + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/reconcile-error.yaml b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/reconcile-error.yaml new file mode 100644 index 0000000000..22e9c65fef --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ClusterScmProvider/testdata/reconcile-error.yaml @@ -0,0 +1,17 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ClusterScmProvider +metadata: + name: github-enterprise + generation: 1 +spec: + secretRef: + name: github-app-secret + github: + appID: 1 +status: + conditions: + - type: Ready + status: "False" + reason: ReconciliationError + message: "Reconciliation failed: invalid credentials" + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/health.lua b/resource_customizations/promoter.argoproj.io/GitCommitStatus/health.lua new file mode 100644 index 0000000000..e37984225a --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/health.lua @@ -0,0 +1,96 @@ +local hs = {} +hs.status = "Progressing" +hs.message = "Initializing git commit validation" + +-- GitCommitStatus (gitops-promoter) reports per-environment validation in status.environments +-- (branch, phase, proposedHydratedSha, targetedSha, expressionResult). It is not CommitStatus: +-- there is no top-level status.sha / status.phase. + +if obj.metadata.deletionTimestamp then + hs.status = "Progressing" + hs.message = "GitCommitStatus is being deleted" + return hs +end + +if not obj.status then + return hs +end + +local hasReadyCondition = false +if obj.status.conditions then + for _, condition in ipairs(obj.status.conditions) do + if condition.type == "Ready" then + hasReadyCondition = true + if condition.observedGeneration and obj.metadata.generation and condition.observedGeneration ~= obj.metadata.generation then + hs.status = "Progressing" + hs.message = "Waiting for GitCommitStatus spec update to be observed" + return hs + end + if condition.status == "False" then + hs.status = "Degraded" + local msg = condition.message or "Unknown error" + local reason = condition.reason or "Unknown" + if reason == "ReconciliationError" then + hs.message = "Git commit validation failed: " .. msg + else + hs.message = "Git commit validation not ready (" .. reason .. "): " .. msg + end + return hs + end + if condition.status == "Unknown" then + hs.status = "Progressing" + local msg = condition.message or "Unknown" + local reason = condition.reason or "Unknown" + hs.message = "Git commit validation status unknown (" .. reason .. "): " .. msg + return hs + end + end + end +end + +if not hasReadyCondition then + hs.status = "Progressing" + hs.message = "GitCommitStatus Ready condition is missing" + return hs +end + +local envs = obj.status.environments +if not envs or #envs == 0 then + hs.status = "Healthy" + hs.message = "Git commit validation reconciled" + return hs +end + +local pendingBranches = {} +local failureBranches = {} +local successCount = 0 + +for _, env in ipairs(envs) do + local branch = env.branch or "?" + local phase = env.phase or "pending" + if phase == "failure" then + table.insert(failureBranches, branch) + elseif phase == "pending" then + table.insert(pendingBranches, branch) + elseif phase == "success" then + successCount = successCount + 1 + else + table.insert(pendingBranches, branch) + end +end + +if #failureBranches > 0 then + hs.status = "Degraded" + hs.message = "Git commit validation failed for branch(es): " .. table.concat(failureBranches, ", ") + return hs +end + +if #pendingBranches > 0 then + hs.status = "Progressing" + hs.message = "Git commit validation pending for branch(es): " .. table.concat(pendingBranches, ", ") + return hs +end + +hs.status = "Healthy" +hs.message = "Git commit validation passed for " .. tostring(successCount) .. " environment(s)" +return hs diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/health_test.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/health_test.yaml new file mode 100644 index 0000000000..10c8dabcce --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/health_test.yaml @@ -0,0 +1,49 @@ +tests: +- healthStatus: + status: Progressing + message: Initializing git commit validation + inputPath: testdata/no-status.yaml +- healthStatus: + status: Progressing + message: GitCommitStatus is being deleted + inputPath: testdata/deleting.yaml +- healthStatus: + status: Progressing + message: Waiting for GitCommitStatus spec update to be observed + inputPath: testdata/observed-generation-outdated.yaml +- healthStatus: + status: Degraded + message: "Git commit validation failed: Something went wrong" + inputPath: testdata/reconcile-error.yaml +- healthStatus: + status: Degraded + message: "Git commit validation not ready (CommitStatusesNotReady): CommitStatus \"git-commit-check-env-dev-git-commit-check\" is not Ready because \"ReconciliationError\": Failed to sync to SCM" + inputPath: testdata/commit-statuses-not-ready.yaml +- healthStatus: + status: Progressing + message: GitCommitStatus Ready condition is missing + inputPath: testdata/no-ready-condition.yaml +- healthStatus: + status: Progressing + message: "Git commit validation status unknown (CommitStatusesNotReady): CommitStatus \"child\" Ready condition is missing" + inputPath: testdata/ready-unknown.yaml +- healthStatus: + status: Healthy + message: Git commit validation reconciled + inputPath: testdata/empty-environments.yaml +- healthStatus: + status: Healthy + message: Git commit validation passed for 2 environment(s) + inputPath: testdata/all-success.yaml +- healthStatus: + status: Progressing + message: "Git commit validation pending for branch(es): env/dev" + inputPath: testdata/environment-pending.yaml +- healthStatus: + status: Degraded + message: "Git commit validation failed for branch(es): env/dev" + inputPath: testdata/environment-failure.yaml +- healthStatus: + status: Degraded + message: "Git commit validation failed: Reconciliation failed: failed to process environments: failed to evaluate expression for branch \"env/dev\": failed to compile expression: failed to compile expression: type string has no method startsWith (1:16)\n | Commit.Subject.startsWith(\"chore:\")\n | ...............^" + inputPath: testdata/expression-compile-error.yaml diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/all-success.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/all-success.yaml new file mode 100644 index 0000000000..73fbc24dbd --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/all-success.yaml @@ -0,0 +1,32 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: gitcommitstatus-proposed-mode + generation: 1 +spec: + promotionStrategyRef: + name: promotion-strategy-sample + key: commit-format-check + description: Commit message format validation + target: proposed + expression: 'Commit.Subject matches "^(feat|fix|docs|chore)(\\(.+\\))?: .+"' +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + proposedHydratedSha: "0123456789abcdef0123456789abcdef01234567" + targetedSha: "0123456789abcdef0123456789abcdef01234567" + activeHydratedSha: "fedcba0987654321fedcba0987654321fedcba09" + phase: success + expressionResult: true + - branch: env/staging + proposedHydratedSha: "abcdef0123456789abcdef0123456789abcdef01" + targetedSha: "abcdef0123456789abcdef0123456789abcdef01" + activeHydratedSha: "0123456789abcdef0123456789abcdef01234567" + phase: success + expressionResult: true diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/commit-statuses-not-ready.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/commit-statuses-not-ready.yaml new file mode 100644 index 0000000000..d515c5170b --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/commit-statuses-not-ready.yaml @@ -0,0 +1,25 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: git-commit-check + generation: 1 +spec: + promotionStrategyRef: + name: demo + key: git-commit-check + expression: 'Commit.Subject startsWith "chore:"' + target: proposed +status: + conditions: + - type: Ready + status: "False" + reason: CommitStatusesNotReady + message: 'CommitStatus "git-commit-check-env-dev-git-commit-check" is not Ready because "ReconciliationError": Failed to sync to SCM' + observedGeneration: 1 + environments: + - branch: env/dev + proposedHydratedSha: "0123456789abcdef0123456789abcdef01234567" + targetedSha: "0123456789abcdef0123456789abcdef01234567" + activeHydratedSha: "fedcba0987654321fedcba0987654321fedcba09" + phase: success + expressionResult: true diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/deleting.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/deleting.yaml new file mode 100644 index 0000000000..9098a38c75 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/deleting.yaml @@ -0,0 +1,10 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: test + deletionTimestamp: "2025-07-04T12:00:00Z" +spec: + promotionStrategyRef: + name: demo-strategy + key: my-check + expression: "true" diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/empty-environments.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/empty-environments.yaml new file mode 100644 index 0000000000..12d0820237 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/empty-environments.yaml @@ -0,0 +1,18 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: test + generation: 1 +spec: + promotionStrategyRef: + name: demo-strategy + key: orphaned-key + expression: "true" +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: [] diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/environment-failure.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/environment-failure.yaml new file mode 100644 index 0000000000..08d125c2c3 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/environment-failure.yaml @@ -0,0 +1,23 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: test + generation: 1 +spec: + promotionStrategyRef: + name: demo-strategy + key: my-check + expression: "false" +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + proposedHydratedSha: "0123456789abcdef0123456789abcdef01234567" + targetedSha: "0123456789abcdef0123456789abcdef01234567" + phase: failure + expressionResult: false diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/environment-pending.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/environment-pending.yaml new file mode 100644 index 0000000000..a47c1f0f1c --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/environment-pending.yaml @@ -0,0 +1,22 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: test + generation: 1 +spec: + promotionStrategyRef: + name: demo-strategy + key: my-check + expression: "true" +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + proposedHydratedSha: "0123456789abcdef0123456789abcdef01234567" + targetedSha: "0123456789abcdef0123456789abcdef01234567" + phase: pending diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/expression-compile-error.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/expression-compile-error.yaml new file mode 100644 index 0000000000..d05fdd9437 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/expression-compile-error.yaml @@ -0,0 +1,26 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: git-commit-check + namespace: gitops-promoter + generation: 1 +spec: + description: Commit subject must start with 'chore:' + expression: Commit.Subject.startsWith("chore:") + key: git-commit-check + promotionStrategyRef: + name: demo + target: proposed +status: + conditions: + - lastTransitionTime: '2026-04-05T17:54:11Z' + message: >- + Reconciliation failed: failed to process environments: failed to + evaluate expression for branch "env/dev": failed to compile expression: + failed to compile expression: type string has no method startsWith (1:16) + | Commit.Subject.startsWith("chore:") + | ...............^ + observedGeneration: 1 + reason: ReconciliationError + status: 'False' + type: Ready diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/no-ready-condition.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/no-ready-condition.yaml new file mode 100644 index 0000000000..f2a4a92ae6 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/no-ready-condition.yaml @@ -0,0 +1,23 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: test + generation: 1 +spec: + promotionStrategyRef: + name: demo-strategy + key: my-check + expression: "true" +status: + conditions: + - type: SomeOtherCondition + status: "True" + reason: Example + message: ok + observedGeneration: 1 + environments: + - branch: env/dev + proposedHydratedSha: "0123456789abcdef0123456789abcdef01234567" + targetedSha: "0123456789abcdef0123456789abcdef01234567" + phase: success + expressionResult: true diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/no-status.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/no-status.yaml new file mode 100644 index 0000000000..da4cd144df --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/no-status.yaml @@ -0,0 +1,9 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: test +spec: + promotionStrategyRef: + name: demo-strategy + key: my-check + expression: 'Commit.Subject startsWith "chore:"' diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/observed-generation-outdated.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/observed-generation-outdated.yaml new file mode 100644 index 0000000000..0ff04d40c1 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/observed-generation-outdated.yaml @@ -0,0 +1,23 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: test + generation: 2 +spec: + promotionStrategyRef: + name: demo-strategy + key: my-check + expression: "true" +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + proposedHydratedSha: "0123456789abcdef0123456789abcdef01234567" + targetedSha: "0123456789abcdef0123456789abcdef01234567" + phase: success + expressionResult: true diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/ready-unknown.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/ready-unknown.yaml new file mode 100644 index 0000000000..e9794afab5 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/ready-unknown.yaml @@ -0,0 +1,23 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: test + generation: 1 +spec: + promotionStrategyRef: + name: demo-strategy + key: my-check + expression: "true" +status: + conditions: + - type: Ready + status: Unknown + reason: CommitStatusesNotReady + message: CommitStatus "child" Ready condition is missing + observedGeneration: 1 + environments: + - branch: env/dev + proposedHydratedSha: "0123456789abcdef0123456789abcdef01234567" + targetedSha: "0123456789abcdef0123456789abcdef01234567" + phase: success + expressionResult: true diff --git a/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/reconcile-error.yaml b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/reconcile-error.yaml new file mode 100644 index 0000000000..527576e0fb --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitCommitStatus/testdata/reconcile-error.yaml @@ -0,0 +1,17 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitCommitStatus +metadata: + name: test + generation: 2 +spec: + promotionStrategyRef: + name: demo-strategy + key: my-check + expression: "true" +status: + conditions: + - type: Ready + status: "False" + reason: ReconciliationError + message: Something went wrong + observedGeneration: 2 diff --git a/resource_customizations/promoter.argoproj.io/GitRepository/health.lua b/resource_customizations/promoter.argoproj.io/GitRepository/health.lua new file mode 100644 index 0000000000..302fbe6a4c --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitRepository/health.lua @@ -0,0 +1,57 @@ +local hs = {} +hs.status = "Progressing" +hs.message = "Initializing Git repository" + +-- GitRepository (gitops-promoter v1alpha1): repo reference validated via standard Ready condition. + +if obj.metadata.deletionTimestamp then + hs.status = "Progressing" + hs.message = "GitRepository is being deleted" + return hs +end + +if not obj.status then + return hs +end + +local hasReadyCondition = false +if obj.status.conditions then + for _, condition in ipairs(obj.status.conditions) do + if condition.type == "Ready" then + hasReadyCondition = true + if condition.observedGeneration and obj.metadata.generation and condition.observedGeneration ~= obj.metadata.generation then + hs.status = "Progressing" + hs.message = "Waiting for GitRepository spec update to be observed" + return hs + end + if condition.status == "False" then + hs.status = "Degraded" + local msg = condition.message or "Unknown error" + local reason = condition.reason or "Unknown" + if reason == "ReconciliationError" then + hs.message = "Git repository validation failed: " .. msg + else + hs.message = "Git repository not ready (" .. reason .. "): " .. msg + end + return hs + end + if condition.status == "Unknown" then + hs.status = "Progressing" + local msg = condition.message or "Unknown" + local reason = condition.reason or "Unknown" + hs.message = "Git repository readiness unknown (" .. reason .. "): " .. msg + return hs + end + end + end +end + +if not hasReadyCondition then + hs.status = "Progressing" + hs.message = "GitRepository Ready condition is missing" + return hs +end + +hs.status = "Healthy" +hs.message = "Git repository is ready" +return hs diff --git a/resource_customizations/promoter.argoproj.io/GitRepository/health_test.yaml b/resource_customizations/promoter.argoproj.io/GitRepository/health_test.yaml new file mode 100644 index 0000000000..76e5864dbe --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitRepository/health_test.yaml @@ -0,0 +1,29 @@ +tests: +- healthStatus: + status: Progressing + message: Initializing Git repository + inputPath: testdata/no-status.yaml +- healthStatus: + status: Progressing + message: GitRepository is being deleted + inputPath: testdata/deleting.yaml +- healthStatus: + status: Progressing + message: Waiting for GitRepository spec update to be observed + inputPath: testdata/observed-generation-outdated.yaml +- healthStatus: + status: Degraded + message: "Git repository validation failed: Reconciliation failed: repository not found" + inputPath: testdata/reconcile-error.yaml +- healthStatus: + status: Progressing + message: GitRepository Ready condition is missing + inputPath: testdata/no-ready-condition.yaml +- healthStatus: + status: Progressing + message: "Git repository readiness unknown (ValidationPending): Resolving repository metadata" + inputPath: testdata/ready-unknown.yaml +- healthStatus: + status: Healthy + message: Git repository is ready + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/promoter.argoproj.io/GitRepository/testdata/deleting.yaml b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/deleting.yaml new file mode 100644 index 0000000000..1403cc0773 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/deleting.yaml @@ -0,0 +1,13 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitRepository +metadata: + name: app-repo + namespace: gitops-promoter + deletionTimestamp: "2025-07-04T12:00:00Z" +spec: + scmProviderRef: + kind: ScmProvider + name: github-provider + github: + owner: argoproj + name: argo-cd diff --git a/resource_customizations/promoter.argoproj.io/GitRepository/testdata/healthy.yaml b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/healthy.yaml new file mode 100644 index 0000000000..e6717b6ebd --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/healthy.yaml @@ -0,0 +1,20 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitRepository +metadata: + name: app-repo + namespace: gitops-promoter + generation: 1 +spec: + scmProviderRef: + kind: ScmProvider + name: github-provider + github: + owner: argoproj + name: argo-cd +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/GitRepository/testdata/no-ready-condition.yaml b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/no-ready-condition.yaml new file mode 100644 index 0000000000..d97a8f4bd2 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/no-ready-condition.yaml @@ -0,0 +1,20 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitRepository +metadata: + name: app-repo + namespace: gitops-promoter + generation: 1 +spec: + scmProviderRef: + kind: ScmProvider + name: github-provider + github: + owner: argoproj + name: argo-cd +status: + conditions: + - type: Example + status: "True" + reason: Example + message: ok + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/GitRepository/testdata/no-status.yaml b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/no-status.yaml new file mode 100644 index 0000000000..55734b0f8a --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/no-status.yaml @@ -0,0 +1,12 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitRepository +metadata: + name: app-repo + namespace: gitops-promoter +spec: + scmProviderRef: + kind: ScmProvider + name: github-provider + github: + owner: argoproj + name: argo-cd diff --git a/resource_customizations/promoter.argoproj.io/GitRepository/testdata/observed-generation-outdated.yaml b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/observed-generation-outdated.yaml new file mode 100644 index 0000000000..5da86ee41c --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/observed-generation-outdated.yaml @@ -0,0 +1,20 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitRepository +metadata: + name: app-repo + namespace: gitops-promoter + generation: 2 +spec: + scmProviderRef: + kind: ScmProvider + name: github-provider + github: + owner: argoproj + name: argo-cd +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/GitRepository/testdata/ready-unknown.yaml b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/ready-unknown.yaml new file mode 100644 index 0000000000..999b749af2 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/ready-unknown.yaml @@ -0,0 +1,20 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitRepository +metadata: + name: app-repo + namespace: gitops-promoter + generation: 1 +spec: + scmProviderRef: + kind: ScmProvider + name: github-provider + github: + owner: argoproj + name: argo-cd +status: + conditions: + - type: Ready + status: Unknown + reason: ValidationPending + message: Resolving repository metadata + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/GitRepository/testdata/reconcile-error.yaml b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/reconcile-error.yaml new file mode 100644 index 0000000000..0191d80193 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/GitRepository/testdata/reconcile-error.yaml @@ -0,0 +1,20 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: GitRepository +metadata: + name: app-repo + namespace: gitops-promoter + generation: 1 +spec: + scmProviderRef: + kind: ScmProvider + name: github-provider + github: + owner: argoproj + name: argo-cd +status: + conditions: + - type: Ready + status: "False" + reason: ReconciliationError + message: "Reconciliation failed: repository not found" + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/ScmProvider/health.lua b/resource_customizations/promoter.argoproj.io/ScmProvider/health.lua new file mode 100644 index 0000000000..93605a80b5 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ScmProvider/health.lua @@ -0,0 +1,57 @@ +local hs = {} +hs.status = "Progressing" +hs.message = "Initializing SCM provider" + +-- ScmProvider (gitops-promoter v1alpha1): credentials / SCM API reachability via standard Ready condition. + +if obj.metadata.deletionTimestamp then + hs.status = "Progressing" + hs.message = "ScmProvider is being deleted" + return hs +end + +if not obj.status then + return hs +end + +local hasReadyCondition = false +if obj.status.conditions then + for _, condition in ipairs(obj.status.conditions) do + if condition.type == "Ready" then + hasReadyCondition = true + if condition.observedGeneration and obj.metadata.generation and condition.observedGeneration ~= obj.metadata.generation then + hs.status = "Progressing" + hs.message = "Waiting for ScmProvider spec update to be observed" + return hs + end + if condition.status == "False" then + hs.status = "Degraded" + local msg = condition.message or "Unknown error" + local reason = condition.reason or "Unknown" + if reason == "ReconciliationError" then + hs.message = "SCM provider validation failed: " .. msg + else + hs.message = "SCM provider not ready (" .. reason .. "): " .. msg + end + return hs + end + if condition.status == "Unknown" then + hs.status = "Progressing" + local msg = condition.message or "Unknown" + local reason = condition.reason or "Unknown" + hs.message = "SCM provider readiness unknown (" .. reason .. "): " .. msg + return hs + end + end + end +end + +if not hasReadyCondition then + hs.status = "Progressing" + hs.message = "ScmProvider Ready condition is missing" + return hs +end + +hs.status = "Healthy" +hs.message = "SCM provider is ready" +return hs diff --git a/resource_customizations/promoter.argoproj.io/ScmProvider/health_test.yaml b/resource_customizations/promoter.argoproj.io/ScmProvider/health_test.yaml new file mode 100644 index 0000000000..c742d723a7 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ScmProvider/health_test.yaml @@ -0,0 +1,29 @@ +tests: +- healthStatus: + status: Progressing + message: Initializing SCM provider + inputPath: testdata/no-status.yaml +- healthStatus: + status: Progressing + message: ScmProvider is being deleted + inputPath: testdata/deleting.yaml +- healthStatus: + status: Progressing + message: Waiting for ScmProvider spec update to be observed + inputPath: testdata/observed-generation-outdated.yaml +- healthStatus: + status: Degraded + message: "SCM provider validation failed: Reconciliation failed: secret not found" + inputPath: testdata/reconcile-error.yaml +- healthStatus: + status: Progressing + message: ScmProvider Ready condition is missing + inputPath: testdata/no-ready-condition.yaml +- healthStatus: + status: Progressing + message: "SCM provider readiness unknown (ValidationPending): Checking GitHub API connectivity" + inputPath: testdata/ready-unknown.yaml +- healthStatus: + status: Healthy + message: SCM provider is ready + inputPath: testdata/healthy.yaml diff --git a/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/deleting.yaml b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/deleting.yaml new file mode 100644 index 0000000000..074e3a8b98 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/deleting.yaml @@ -0,0 +1,11 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ScmProvider +metadata: + name: github-provider + namespace: gitops-promoter + deletionTimestamp: "2025-07-04T12:00:00Z" +spec: + secretRef: + name: github-app-secret + github: + appID: 1 diff --git a/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/healthy.yaml b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/healthy.yaml new file mode 100644 index 0000000000..d90c22ecf9 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/healthy.yaml @@ -0,0 +1,18 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ScmProvider +metadata: + name: github-provider + namespace: gitops-promoter + generation: 1 +spec: + secretRef: + name: github-app-secret + github: + appID: 1 +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/no-ready-condition.yaml b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/no-ready-condition.yaml new file mode 100644 index 0000000000..d1d9fddb9d --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/no-ready-condition.yaml @@ -0,0 +1,18 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ScmProvider +metadata: + name: github-provider + namespace: gitops-promoter + generation: 1 +spec: + secretRef: + name: github-app-secret + github: + appID: 1 +status: + conditions: + - type: Example + status: "True" + reason: Example + message: ok + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/no-status.yaml b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/no-status.yaml new file mode 100644 index 0000000000..b9e1dca104 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/no-status.yaml @@ -0,0 +1,10 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ScmProvider +metadata: + name: github-provider + namespace: gitops-promoter +spec: + secretRef: + name: github-app-secret + github: + appID: 1 diff --git a/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/observed-generation-outdated.yaml b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/observed-generation-outdated.yaml new file mode 100644 index 0000000000..cbc84e8e4e --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/observed-generation-outdated.yaml @@ -0,0 +1,18 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ScmProvider +metadata: + name: github-provider + namespace: gitops-promoter + generation: 2 +spec: + secretRef: + name: github-app-secret + github: + appID: 1 +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/ready-unknown.yaml b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/ready-unknown.yaml new file mode 100644 index 0000000000..487e45a8c3 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/ready-unknown.yaml @@ -0,0 +1,18 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ScmProvider +metadata: + name: github-provider + namespace: gitops-promoter + generation: 1 +spec: + secretRef: + name: github-app-secret + github: + appID: 1 +status: + conditions: + - type: Ready + status: Unknown + reason: ValidationPending + message: Checking GitHub API connectivity + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/reconcile-error.yaml b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/reconcile-error.yaml new file mode 100644 index 0000000000..c84f125e98 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/ScmProvider/testdata/reconcile-error.yaml @@ -0,0 +1,18 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: ScmProvider +metadata: + name: github-provider + namespace: gitops-promoter + generation: 1 +spec: + secretRef: + name: github-app-secret + github: + appID: 1 +status: + conditions: + - type: Ready + status: "False" + reason: ReconciliationError + message: "Reconciliation failed: secret not found" + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/health.lua b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/health.lua new file mode 100644 index 0000000000..dfb1281291 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/health.lua @@ -0,0 +1,93 @@ +local hs = {} +hs.status = "Progressing" +hs.message = "Initializing timed commit gate" + +-- TimedCommitStatus (gitops-promoter v1alpha1): per-environment wait before reporting success. +-- status.environments[].phase is pending or success (see API). + +if obj.metadata.deletionTimestamp then + hs.status = "Progressing" + hs.message = "TimedCommitStatus is being deleted" + return hs +end + +if not obj.status then + return hs +end + +local hasReadyCondition = false +if obj.status.conditions then + for _, condition in ipairs(obj.status.conditions) do + if condition.type == "Ready" then + hasReadyCondition = true + if condition.observedGeneration and obj.metadata.generation and condition.observedGeneration ~= obj.metadata.generation then + hs.status = "Progressing" + hs.message = "Waiting for TimedCommitStatus spec update to be observed" + return hs + end + if condition.status == "False" then + hs.status = "Degraded" + local msg = condition.message or "Unknown error" + local reason = condition.reason or "Unknown" + if reason == "ReconciliationError" then + hs.message = "Timed commit gate failed: " .. msg + else + hs.message = "Timed commit gate not ready (" .. reason .. "): " .. msg + end + return hs + end + if condition.status == "Unknown" then + hs.status = "Progressing" + local msg = condition.message or "Unknown" + local reason = condition.reason or "Unknown" + hs.message = "Timed commit gate status unknown (" .. reason .. "): " .. msg + return hs + end + end + end +end + +if not hasReadyCondition then + hs.status = "Progressing" + hs.message = "TimedCommitStatus Ready condition is missing" + return hs +end + +local envs = obj.status.environments +if not envs or #envs == 0 then + hs.status = "Healthy" + hs.message = "Timed commit gate reconciled" + return hs +end + +local pendingBranches = {} +local failureBranches = {} +local successCount = 0 + +for _, env in ipairs(envs) do + local branch = env.branch or "?" + local phase = env.phase or "pending" + if phase == "failure" then + table.insert(failureBranches, branch) + elseif phase == "success" then + successCount = successCount + 1 + else + table.insert(pendingBranches, branch) + end +end + +if #failureBranches > 0 then + hs.status = "Degraded" + hs.message = "Timed commit gate failed for branch(es): " .. table.concat(failureBranches, ", ") + return hs +end + +if #pendingBranches > 0 then + hs.status = "Progressing" + hs.message = "Timed commit gate pending for branch(es): " .. table.concat(pendingBranches, ", ") + return hs +end + +hs.status = "Healthy" +hs.message = "Timed commit gate satisfied for " .. tostring(successCount) .. " environment(s)" +return hs diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/health_test.yaml b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/health_test.yaml new file mode 100644 index 0000000000..638e6e7466 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/health_test.yaml @@ -0,0 +1,37 @@ +tests: +- healthStatus: + status: Progressing + message: Initializing timed commit gate + inputPath: testdata/no-status.yaml +- healthStatus: + status: Progressing + message: TimedCommitStatus is being deleted + inputPath: testdata/deleting.yaml +- healthStatus: + status: Progressing + message: Waiting for TimedCommitStatus spec update to be observed + inputPath: testdata/observed-generation-outdated.yaml +- healthStatus: + status: Degraded + message: "Timed commit gate failed: Reconciliation failed: PromotionStrategy not found" + inputPath: testdata/reconcile-error.yaml +- healthStatus: + status: Progressing + message: TimedCommitStatus Ready condition is missing + inputPath: testdata/no-ready-condition.yaml +- healthStatus: + status: Healthy + message: Timed commit gate reconciled + inputPath: testdata/empty-environments.yaml +- healthStatus: + status: Progressing + message: "Timed commit gate pending for branch(es): env/dev" + inputPath: testdata/environment-pending.yaml +- healthStatus: + status: Healthy + message: Timed commit gate satisfied for 2 environment(s) + inputPath: testdata/all-success.yaml +- healthStatus: + status: Degraded + message: "Timed commit gate failed for branch(es): env/dev" + inputPath: testdata/environment-failure.yaml diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/all-success.yaml b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/all-success.yaml new file mode 100644 index 0000000000..9cc68c6d15 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/all-success.yaml @@ -0,0 +1,34 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: TimedCommitStatus +metadata: + name: soak-gate + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + environments: + - branch: env/dev + duration: 5m + - branch: env/staging + duration: 5m +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + sha: "0123456789abcdef0123456789abcdef01234567" + commitTime: "2026-03-01T12:00:00Z" + requiredDuration: 5m + phase: success + atMostDurationRemaining: 0s + - branch: env/staging + sha: "abcdef0123456789abcdef0123456789abcdef01" + commitTime: "2026-03-01T12:00:00Z" + requiredDuration: 5m + phase: success + atMostDurationRemaining: 0s diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/deleting.yaml b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/deleting.yaml new file mode 100644 index 0000000000..a56dd0284c --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/deleting.yaml @@ -0,0 +1,12 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: TimedCommitStatus +metadata: + name: soak-gate + namespace: gitops-promoter + deletionTimestamp: "2025-07-04T12:00:00Z" +spec: + promotionStrategyRef: + name: demo + environments: + - branch: env/dev + duration: 10m diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/empty-environments.yaml b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/empty-environments.yaml new file mode 100644 index 0000000000..acac6d9a99 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/empty-environments.yaml @@ -0,0 +1,20 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: TimedCommitStatus +metadata: + name: soak-gate + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + environments: + - branch: env/dev + duration: 10m +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: [] diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/environment-failure.yaml b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/environment-failure.yaml new file mode 100644 index 0000000000..b348cefae6 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/environment-failure.yaml @@ -0,0 +1,26 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: TimedCommitStatus +metadata: + name: soak-gate + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + environments: + - branch: env/dev + duration: 10m +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + sha: "0123456789abcdef0123456789abcdef01234567" + commitTime: "2026-03-01T12:00:00Z" + requiredDuration: 10m + phase: failure + atMostDurationRemaining: 0s diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/environment-pending.yaml b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/environment-pending.yaml new file mode 100644 index 0000000000..cccaf1016d --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/environment-pending.yaml @@ -0,0 +1,26 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: TimedCommitStatus +metadata: + name: soak-gate + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + environments: + - branch: env/dev + duration: 10m +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + sha: "0123456789abcdef0123456789abcdef01234567" + commitTime: "2026-03-01T12:00:00Z" + requiredDuration: 10m + phase: pending + atMostDurationRemaining: 5m diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/no-ready-condition.yaml b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/no-ready-condition.yaml new file mode 100644 index 0000000000..63b0f018ce --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/no-ready-condition.yaml @@ -0,0 +1,19 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: TimedCommitStatus +metadata: + name: soak-gate + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + environments: + - branch: env/dev + duration: 10m +status: + conditions: + - type: Example + status: "True" + reason: Example + message: ok + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/no-status.yaml b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/no-status.yaml new file mode 100644 index 0000000000..04f1a06941 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/no-status.yaml @@ -0,0 +1,11 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: TimedCommitStatus +metadata: + name: soak-gate + namespace: gitops-promoter +spec: + promotionStrategyRef: + name: demo + environments: + - branch: env/dev + duration: 10m diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/observed-generation-outdated.yaml b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/observed-generation-outdated.yaml new file mode 100644 index 0000000000..6f1e2fca17 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/observed-generation-outdated.yaml @@ -0,0 +1,26 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: TimedCommitStatus +metadata: + name: soak-gate + namespace: gitops-promoter + generation: 2 +spec: + promotionStrategyRef: + name: demo + environments: + - branch: env/dev + duration: 10m +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + sha: "0123456789abcdef0123456789abcdef01234567" + commitTime: "2026-03-01T12:00:00Z" + requiredDuration: 10m + phase: success + atMostDurationRemaining: 0s diff --git a/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/reconcile-error.yaml b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/reconcile-error.yaml new file mode 100644 index 0000000000..963a21b2e9 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/TimedCommitStatus/testdata/reconcile-error.yaml @@ -0,0 +1,19 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: TimedCommitStatus +metadata: + name: soak-gate + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + environments: + - branch: env/dev + duration: 10m +status: + conditions: + - type: Ready + status: "False" + reason: ReconciliationError + message: "Reconciliation failed: PromotionStrategy not found" + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/health.lua b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/health.lua new file mode 100644 index 0000000000..b14b8c47d2 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/health.lua @@ -0,0 +1,95 @@ +local hs = {} +hs.status = "Progressing" +hs.message = "Initializing web request commit validation" + +-- WebRequestCommitStatus (gitops-promoter v1alpha1): HTTP-based gating with per-environment phase +-- (pending / success / failure) in status.environments, plus aggregated Ready. + +if obj.metadata.deletionTimestamp then + hs.status = "Progressing" + hs.message = "WebRequestCommitStatus is being deleted" + return hs +end + +if not obj.status then + return hs +end + +local hasReadyCondition = false +if obj.status.conditions then + for _, condition in ipairs(obj.status.conditions) do + if condition.type == "Ready" then + hasReadyCondition = true + if condition.observedGeneration and obj.metadata.generation and condition.observedGeneration ~= obj.metadata.generation then + hs.status = "Progressing" + hs.message = "Waiting for WebRequestCommitStatus spec update to be observed" + return hs + end + if condition.status == "False" then + hs.status = "Degraded" + local msg = condition.message or "Unknown error" + local reason = condition.reason or "Unknown" + if reason == "ReconciliationError" then + hs.message = "Web request commit validation failed: " .. msg + else + hs.message = "Web request commit validation not ready (" .. reason .. "): " .. msg + end + return hs + end + if condition.status == "Unknown" then + hs.status = "Progressing" + local msg = condition.message or "Unknown" + local reason = condition.reason or "Unknown" + hs.message = "Web request commit validation unknown (" .. reason .. "): " .. msg + return hs + end + end + end +end + +if not hasReadyCondition then + hs.status = "Progressing" + hs.message = "WebRequestCommitStatus Ready condition is missing" + return hs +end + +local envs = obj.status.environments +if not envs or #envs == 0 then + hs.status = "Healthy" + hs.message = "Web request commit validation reconciled" + return hs +end + +local pendingBranches = {} +local failureBranches = {} +local successCount = 0 + +for _, env in ipairs(envs) do + local branch = env.branch or "?" + local phase = env.phase or "pending" + if phase == "failure" then + table.insert(failureBranches, branch) + elseif phase == "pending" then + table.insert(pendingBranches, branch) + elseif phase == "success" then + successCount = successCount + 1 + else + table.insert(pendingBranches, branch) + end +end + +if #failureBranches > 0 then + hs.status = "Degraded" + hs.message = "Web request validation failed for branch(es): " .. table.concat(failureBranches, ", ") + return hs +end + +if #pendingBranches > 0 then + hs.status = "Progressing" + hs.message = "Web request validation pending for branch(es): " .. table.concat(pendingBranches, ", ") + return hs +end + +hs.status = "Healthy" +hs.message = "Web request validation passed for " .. tostring(successCount) .. " environment(s)" +return hs diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/health_test.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/health_test.yaml new file mode 100644 index 0000000000..e35670f85f --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/health_test.yaml @@ -0,0 +1,41 @@ +tests: +- healthStatus: + status: Progressing + message: Initializing web request commit validation + inputPath: testdata/no-status.yaml +- healthStatus: + status: Progressing + message: WebRequestCommitStatus is being deleted + inputPath: testdata/deleting.yaml +- healthStatus: + status: Progressing + message: Waiting for WebRequestCommitStatus spec update to be observed + inputPath: testdata/observed-generation-outdated.yaml +- healthStatus: + status: Degraded + message: "Web request commit validation failed: Reconciliation failed: invalid URL template" + inputPath: testdata/reconcile-error.yaml +- healthStatus: + status: Degraded + message: "Web request commit validation not ready (CommitStatusesNotReady): CommitStatus \"external-check-env-dev-ext-approval\" is not Ready because \"ReconciliationError\": SCM error" + inputPath: testdata/commit-statuses-not-ready.yaml +- healthStatus: + status: Progressing + message: WebRequestCommitStatus Ready condition is missing + inputPath: testdata/no-ready-condition.yaml +- healthStatus: + status: Healthy + message: Web request commit validation reconciled + inputPath: testdata/empty-environments.yaml +- healthStatus: + status: Progressing + message: "Web request validation pending for branch(es): env/dev" + inputPath: testdata/environment-pending.yaml +- healthStatus: + status: Degraded + message: "Web request validation failed for branch(es): env/dev" + inputPath: testdata/environment-failure.yaml +- healthStatus: + status: Healthy + message: Web request validation passed for 2 environment(s) + inputPath: testdata/all-success.yaml diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/all-success.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/all-success.yaml new file mode 100644 index 0000000000..1fd3cb226d --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/all-success.yaml @@ -0,0 +1,33 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: WebRequestCommitStatus +metadata: + name: external-check + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + key: ext-approval + httpRequest: + urlTemplate: "https://example.com/health" + method: GET + success: + when: + expression: "Response.StatusCode == 200" + mode: + polling: + interval: 1m +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + reportedSha: "0123456789abcdef0123456789abcdef01234567" + phase: success + - branch: env/staging + reportedSha: "abcdef0123456789abcdef0123456789abcdef01" + phase: success diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/commit-statuses-not-ready.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/commit-statuses-not-ready.yaml new file mode 100644 index 0000000000..c48d802235 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/commit-statuses-not-ready.yaml @@ -0,0 +1,30 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: WebRequestCommitStatus +metadata: + name: external-check + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + key: ext-approval + httpRequest: + urlTemplate: "https://example.com/health" + method: GET + success: + when: + expression: "Response.StatusCode == 200" + mode: + polling: + interval: 1m +status: + conditions: + - type: Ready + status: "False" + reason: CommitStatusesNotReady + message: 'CommitStatus "external-check-env-dev-ext-approval" is not Ready because "ReconciliationError": SCM error' + observedGeneration: 1 + environments: + - branch: env/dev + reportedSha: "0123456789abcdef0123456789abcdef01234567" + phase: success diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/deleting.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/deleting.yaml new file mode 100644 index 0000000000..464cdfe777 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/deleting.yaml @@ -0,0 +1,19 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: WebRequestCommitStatus +metadata: + name: external-check + namespace: gitops-promoter + deletionTimestamp: "2025-07-04T12:00:00Z" +spec: + promotionStrategyRef: + name: demo + key: ext-approval + httpRequest: + urlTemplate: "https://example.com/health" + method: GET + success: + when: + expression: "Response.StatusCode == 200" + mode: + polling: + interval: 1m diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/empty-environments.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/empty-environments.yaml new file mode 100644 index 0000000000..8e50108368 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/empty-environments.yaml @@ -0,0 +1,27 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: WebRequestCommitStatus +metadata: + name: external-check + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + key: ext-approval + httpRequest: + urlTemplate: "https://example.com/health" + method: GET + success: + when: + expression: "Response.StatusCode == 200" + mode: + polling: + interval: 1m +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: [] diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/environment-failure.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/environment-failure.yaml new file mode 100644 index 0000000000..cab0e0aa8c --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/environment-failure.yaml @@ -0,0 +1,31 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: WebRequestCommitStatus +metadata: + name: external-check + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + key: ext-approval + httpRequest: + urlTemplate: "https://example.com/health" + method: GET + success: + when: + expression: "Response.StatusCode == 200" + mode: + polling: + interval: 1m +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + reportedSha: "0123456789abcdef0123456789abcdef01234567" + phase: failure + lastResponseStatusCode: 500 diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/environment-pending.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/environment-pending.yaml new file mode 100644 index 0000000000..237f47a47f --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/environment-pending.yaml @@ -0,0 +1,30 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: WebRequestCommitStatus +metadata: + name: external-check + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + key: ext-approval + httpRequest: + urlTemplate: "https://example.com/health" + method: GET + success: + when: + expression: "Response.StatusCode == 200" + mode: + polling: + interval: 1m +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + reportedSha: "0123456789abcdef0123456789abcdef01234567" + phase: pending diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/no-ready-condition.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/no-ready-condition.yaml new file mode 100644 index 0000000000..f0c5dc0b3b --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/no-ready-condition.yaml @@ -0,0 +1,26 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: WebRequestCommitStatus +metadata: + name: external-check + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + key: ext-approval + httpRequest: + urlTemplate: "https://example.com/health" + method: GET + success: + when: + expression: "Response.StatusCode == 200" + mode: + polling: + interval: 1m +status: + conditions: + - type: Example + status: "True" + reason: Example + message: ok + observedGeneration: 1 diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/no-status.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/no-status.yaml new file mode 100644 index 0000000000..7c50e34f67 --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/no-status.yaml @@ -0,0 +1,18 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: WebRequestCommitStatus +metadata: + name: external-check + namespace: gitops-promoter +spec: + promotionStrategyRef: + name: demo + key: ext-approval + httpRequest: + urlTemplate: "https://example.com/health" + method: GET + success: + when: + expression: "Response.StatusCode == 200" + mode: + polling: + interval: 1m diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/observed-generation-outdated.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/observed-generation-outdated.yaml new file mode 100644 index 0000000000..3c79474b3b --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/observed-generation-outdated.yaml @@ -0,0 +1,30 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: WebRequestCommitStatus +metadata: + name: external-check + namespace: gitops-promoter + generation: 2 +spec: + promotionStrategyRef: + name: demo + key: ext-approval + httpRequest: + urlTemplate: "https://example.com/health" + method: GET + success: + when: + expression: "Response.StatusCode == 200" + mode: + polling: + interval: 1m +status: + conditions: + - type: Ready + status: "True" + reason: ReconciliationSuccess + message: Reconciliation successful + observedGeneration: 1 + environments: + - branch: env/dev + reportedSha: "0123456789abcdef0123456789abcdef01234567" + phase: success diff --git a/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/reconcile-error.yaml b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/reconcile-error.yaml new file mode 100644 index 0000000000..7be535b6be --- /dev/null +++ b/resource_customizations/promoter.argoproj.io/WebRequestCommitStatus/testdata/reconcile-error.yaml @@ -0,0 +1,26 @@ +apiVersion: promoter.argoproj.io/v1alpha1 +kind: WebRequestCommitStatus +metadata: + name: external-check + namespace: gitops-promoter + generation: 1 +spec: + promotionStrategyRef: + name: demo + key: ext-approval + httpRequest: + urlTemplate: "https://example.com/health" + method: GET + success: + when: + expression: "Response.StatusCode == 200" + mode: + polling: + interval: 1m +status: + conditions: + - type: Ready + status: "False" + reason: ReconciliationError + message: "Reconciliation failed: invalid URL template" + observedGeneration: 1