tests: discover comparison components and build the CI matrix from them - #3577
tests: discover comparison components and build the CI matrix from them#3577danish9039 wants to merge 14 commits into
Conversation
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
4e4fdea to
5b9d2af
Compare
5b9d2af to
25daa92
Compare
There was a problem hiding this comment.
Pull request overview
Moves Helm–Kustomize comparison configuration into chart-local descriptors discovered by a new Python runner.
Changes:
- Adds descriptor discovery, validation, rendering, and scenario selection.
- Adds ten chart descriptors and corrects Katib’s default scenario.
- Removes shell runners and updates documentation, tests, workflow, and synchronization calls.
Reviewed changes
Copilot reviewed 27 out of 27 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
tests/test_istio_helm_chart.py |
Updates Istio workflow assertion. |
tests/test_helm_kustomize_compare.py |
Updates Dex workflow assertion. |
tests/test_comparison_descriptors.py |
Tests descriptor coverage and validation. |
tests/run_helm_kustomize_comparison.py |
Adds the discovered comparison runner. |
tests/helm_kustomize_compare.sh |
Removes the single-scenario shell runner. |
tests/helm_kustomize_compare.py |
Removes static component validation. |
tests/helm_kustomize_compare_all.sh |
Removes the aggregate shell runner. |
scripts/synchronize-dashboard-manifests.sh |
Uses the Python comparison runner. |
experimental/helm/charts/kserve-ui/ci/comparison.yaml |
Declares KServe UI comparison. |
experimental/helm/charts/katib/ci/comparison.yaml |
Declares Katib scenarios and default. |
experimental/helm/charts/hub/ci/comparison.yaml |
Declares Hub comparison scenarios. |
common/oauth2-proxy/helm/README.md |
Updates validation command. |
common/oauth2-proxy/helm/ci/comparison.yaml |
Declares OAuth2-Proxy comparison. |
common/kubeflow-roles/helm/README.md |
Updates validation command. |
common/kubeflow-roles/helm/ci/comparison.yaml |
Declares platform-role comparison. |
common/kubeflow-namespace/helm/README.md |
Updates validation commands. |
common/kubeflow-namespace/helm/ci/comparison.yaml |
Declares namespace scenarios. |
common/istio/helm/README.md |
Updates validation commands. |
common/istio/helm/ci/comparison.yaml |
Declares Istio scenarios. |
common/dex/helm/README.md |
Updates validation command. |
common/dex/helm/ci/comparison.yaml |
Declares Dex comparison. |
common/cert-manager/helm/README.md |
Updates validation commands. |
common/cert-manager/helm/ci/comparison.yaml |
Declares Cert Manager scenarios. |
applications/dashboard/helm/README.md |
Updates Dashboard validation commands. |
applications/dashboard/helm/ci/comparison.yaml |
Declares Dashboard comparison. |
AGENTS.md |
Documents the new runner. |
.github/workflows/helm-kustomize-comparison.yml |
Runs descriptor tests and the new runner. |
|
/retest |
4336c6a to
240ef0f
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 36 out of 36 changed files in this pull request and generated 1 comment.
Suppressed comments (3)
tests/run_helm_kustomize_comparison.py:135
- The loader rejects unknown fields only inside
knownDifferences; unknown top-level, scenario,ignoredLabels, andhelmOnlyResourcesfields are silently accepted. For example,value:instead ofvalues:loads successfully and compares Helm defaults rather than the intended values file. Define allowed fields for every descriptor level and reject unknown keys so misspellings cannot silently alter coverage.
tests/helm_kustomize_compare.py:84 retainedCustomResourceDefinitionsis represented as bare names, so these lifecycle allowances cannot carry the mandatory non-emptyreasonpromised by the pull request andtests/README.md:70. The loader also performs no reason validation for this family. Represent each declaration as a resource-and-reason entry and validate it consistently with the other allowance families.
self.retained_custom_resource_definitions = set(
descriptor.get("retainedCustomResourceDefinitions") or []
)
tests/helm_kustomize_compare.py:175
- The documented allowance syntax permits
*wildcards, buthelmOnlyResourcesis matched by exact string lookup here. A documented declaration such asSecret/kubeflow/*therefore never permits a matching resource and is reported as stale. Match each resource key throughresource_matches, and validate these patterns during descriptor loading.
def unexpected_helm_only(self, only_in_helm: set) -> set:
"""Filter Helm-side extras down to the undeclared ones."""
declared = {
entry["resource"]: f"helmOnlyResources[{index}]"
for index, entry in enumerate(self.helm_only_resources)
}
for key in only_in_helm:
if key in declared:
self._fired.add(declared[key])
return {key for key in only_in_helm if key not in declared}
Adding a component required eighteen edits across four shared files, every one an append to a list some other branch was also appending to. Four open pull requests appending to the same five lists conflicted every time one merged. Each chart now declares how it is compared in its own ci/comparison.yaml, and the harness discovers those files. Adding a component touches only that component's directory. tests/helm_kustomize_compare.sh and tests/helm_kustomize_compare_all.sh become shims so every command documented in the chart READMEs keeps working. Verified by running the previous and the new harness over all thirty-eight component and scenario pairs: identical verdicts, all passing. The descriptor validator also caught a latent defect. The previous default-scenario case fell through to 'base' for any unlisted component, but Katib has no 'base' scenario, so comparing Katib without naming one always failed. Its default is now 'standalone'. Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
The workflow named five hand-written jobs and ten component path prefixes. applications/katib was missing from the filter, so a Katib upstream synchronization changed all seven Katib baselines without running a comparison, and 'Compare All Scenarios' carried continue-on-error, so seven of the ten components had no blocking parity check at all. One discovery job reads the descriptors and one matrix job compares each component, so every component now reports its own blocking verdict. Five workflow tests pinned to the removed job names are replaced by four that hold for every component: the matrix is discovered rather than listed, no job or step is advisory, the comparison cannot be skipped by a condition, and kustomize reaches PATH. Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
The comparison matrix installs Kustomize once per component, so the same GitHub release asset is now fetched ten times per pull request instead of four. Neither curl retried, and a connection reset failed the whole job before any comparison ran. Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
The comparison depends on the exact Helm version. Continuous integration pins it; a contributor's machine does not, so a local run can fail on a rendering difference nobody can act on and block a routine upstream update. Every component now has its own blocking comparison job, so the scripts no longer need to enforce parity. They keep helm lint, which is fast and version-tolerant, and print the command to compare manually. The Dashboard and Notebooks scripts were the only two that compared. Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
The comparison printed a count and hid the names behind --verbose, so the
default output named a number and withheld the answer:
Resources only in Kustomize: 2
Every continuous integration job set VERBOSE, and nothing else did, so the
one caller who needed the detail most - a contributor running the command by
hand - was the one who did not get it.
Measured before removing the flag: a failure with half of the largest chart
missing prints 36 lines. There is nothing worth hiding, so --verbose and the
VERBOSE environment variable are gone.
Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
A failing kustomize build or helm template raised CalledProcessError, which
printed a Python traceback and discarded the captured standard error, so the
message explaining the failure was the one thing not shown:
subprocess.CalledProcessError: Command '['kustomize', 'build', ...]'
returned non-zero exit status 1.
instead of
Error: invalid Kustomization: json: cannot unmarshal string into Go
struct field Kustomization.patches of type types.Patch
The exception also escaped compare(), so 'all' and '--all-scenarios' stopped
at the first rendering failure rather than recording it and continuing, which
the deleted aggregate harness did.
Raised by review on pull request 3577.
Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
generation, resourceVersion, uid, creationTimestamp, managedFields and status are assigned by a live cluster, so they appear only in kubectl get output. This harness compares kustomize build against helm template, which are pure text renderers and cannot produce them. Parsing every document on both sides of all 39 comparisons finds zero occurrences at the popped positions. The namespace parameter of compare_manifests was never read; remove it from the comparator and its caller. Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
Roughly 300 of the comparator's lines were per-component exceptions: label filters with three divergent variants, whole resources deleted from the comparison, checksum and ConfigMap special cases, and opt-in maps where a missing entry silently meant no check. Each was an unscoped code branch that answered for every future resource of its shape, printed nothing when it fired, and never expired. Each chart now declares its allowances in ci/comparison.yaml, scoped to named resources and carrying a mandatory reason. The comparator becomes a generic engine that interprets them. Three rules close the failure modes the code form allowed: - an allowance names one resource, not a shape; - a malformed or reason-less allowance refuses to load; - an allowance that matches nothing in any scenario fails the run, because a stale allowance is indistinguishable from a wrong one. Every declaration was measured before being written, by rendering all 39 scenarios and removing candidate rules one at a time. Only load-bearing rules were kept, which shrank the exception surface considerably: eight of eleven components need no label filtering at all, cert-manager's counter-exception that re-added deliberately set labels disappears because the over-broad filter it corrected disappears, and the four whole-kind Namespace exclusions narrow to four named namespaces. The audit also surfaced 21 keep-annotated CustomResourceDefinitions that no check covered: upstream cert-manager and Istio annotate their CustomResourceDefinitions with helm.sh/resource-policy: keep, and the previous retention check only ran for components registered in its map. Retention expectations are now declared per chart, and an undeclared keep annotation fails the comparison for every component. Verdicts are unchanged: all 39 comparisons pass before and after, and every declared allowance fires. The descriptor loader rejects malformed allowances; each rejection is covered by a test proven to fail when its guard is removed. Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
The descriptor and its declared allowances had no documentation; a contributor had to read the runner to learn what the fields mean. The format is documented once in tests/README.md, and every chart README points at its own ci/comparison.yaml and that document. Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
ignoredLabels now strips top-level metadata only unless an entry declares
podTemplates: true; only cert-manager propagates an ignored label into pod
templates. The unused except mechanism is removed. trimDataWhitespace is
removed; katib-config.yaml is compared as parsed YAML, key-scoped.
retainedCustomResourceDefinitions becomes {reason, names}, both validated.
The dex checksum reason no longer claims Kustomize uses content-hashed
names, and the base scenarios are renamed to what they compare.
Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
The harness compares rendered snapshots, not runtime update behavior; tests/README.md says so and stops claiming every allowance is resource-scoped. The Dashboard README names dashboard-config as the one stable-named ConfigMap. The synchronization scripts lose the duplicated continuous integration policy commentary and a comment that claimed the script writes the comparison descriptor. Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
0745bda to
9b69987
Compare
|
@juliusvonkohout for review |
A misspelled onlyKinds or excludeKinds value filters both rendered sets to zero resources, and two empty sets compare equal, silently removing parity coverage. Comparing an empty selection now fails. Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
The repository convention puts the component first and the test suffix last: dex_login_test.py, kserve_manifest_test.py, pipeline_test.py. Rename the nine test_-prefixed Helm test files to match. Signed-off-by: danish9039 <danishsiddiqui040@gmail.com>
Pull Request Template for Kubeflow Manifests
✏️ Summary of Changes
Problem
Adding a component to the Helm and Kustomize comparison harness required eighteen edits across four shared files, and every one was an append to a list that other open branches were appending to at the same time.
tests/helm_kustomize_compare.shtests/helm_kustomize_compare_all.shallloop, help, error,prepare_componenttests/helm_kustomize_compare.py.github/workflows/helm-kustomize-comparison.ymlpaths:entries, a jobFour component pull requests were open simultaneously, so each merge forced the other three to rebase. The Notebooks chart #3525 merging mid-review demonstrated it once more: it registered itself in all four shared files and set every open Helm pull request conflicting at once.
The registration model also hid real defects, found while replacing it:
Compare All Scenarioscarriedcontinue-on-error: true, so onlydex,istioandkubeflow-dashboardcould fail a pull request.applications/katib/**was absent from thepaths:filter, whilescripts/synchronize-katib-manifests.shwrites toapplications/katib/upstream, the baseline for all seven Katib scenarios.casefell through tobase, and Katib has nobasescenario.helm.sh/resource-policy: keep(upstream cert-manager and Istio) were covered by no check at all.Changes
1. Each chart declares how it is compared, in its own directory (
tests: discover comparison components instead of registering them).Eleven descriptors (Notebooks included after rebasing onto its merge) replace the four shared registries.
tests/run_helm_kustomize_comparison.pydiscovers charts by glob, so adding a component touches only that component's directory. Both shell entry points are deleted and every call site invokes the Python entry point directly.2. The workflow builds its jobs from those descriptors (
tests: build the comparison job matrix from the descriptors).Hand-written jobs become one discovery job and one matrix. Every component now has its own blocking job. The
paths:filter is deliberately broad, because a narrower hand-maintained list is indistinguishable from a complete one when it is wrong. Workflow tests pinned to the removed job names are replaced by four that hold for every future component: the matrix is discovered rather than listed, no job or step is advisory, the comparison step carries no condition, and Kustomize reachesPATH.3. Every chart-specific comparison exception becomes a declared allowance in that chart's descriptor (
tests: declare comparison allowances in each chart's descriptor).tests/helm_kustomize_compare.pybecomes a generic engine that interprets these declarations; only universal facts about the renderers stay in code (thehelm.shlabel and annotation namespaces, Kustomize's content-hash suffixes). Three rules close the failure modes the code form allowed:reason, which the loader enforces;Every declaration was measured before being written, by rendering all scenarios and removing candidate rules one at a time. Only load-bearing rules were kept: eight of eleven components need no label filtering at all, the four whole-kind
Namespaceexclusions narrow to four named namespaces, and cert-manager's normalizer-undoing-a-normalizer disappears because the over-broad filter it corrected disappears. CustomResourceDefinition retention expectations are now declared per chart, so an undeclaredhelm.sh/resource-policy: keepannotation fails the comparison for every component, closing the gap that let 21 keep-annotated CustomResourceDefinitions ship unchecked.4. Smaller fixes surfaced by the redesign.
popcalls foruid,statusand friends are deleted:kustomize buildandhelm templateare pure text renderers and cannot emit live-cluster fields (tests: delete normalization of fields the renderers never emit).--verbose; the flag and theVERBOSEenvironment variable are removed (tests: always print which resources differ).tests: report the tool's own failure and keep comparing).tests/kustomize_install.shretries the download; the matrix fetches the asset once per component and a single connection reset failed the whole job (tests: retry the Kustomize download).helm: stop comparing parity inside the synchronization scripts). The comparison depends on the exact Helm version, which continuous integration pins and a contributor's machine does not; now that every component has its own blocking job, the scripts keephelm lintand print the command to compare manually.6. Review findings are folded in, as a net deletion (
tests: tighten comparison allowances per descriptor review,docs: correct comparison harness documentation and script comments,tests: name the Dashboard generator test by component).ignoredLabelsnow strips top-level metadata only; an entry declarespodTemplates: truewhen the chart also writes the keys into workload template metadata. Measured: only the three cert-manager Deployments do, so the pod templates of every other chart are now compared strictly. The unusedexceptmechanism is removed.trimDataWhitespaceis deleted from the harness. The Katib configuration is compared as parsed YAML, scoped to the singlekatib-config.yamldata key, after measuring that parsed equality holds in all seven Katib scenarios.retainedCustomResourceDefinitionsbecomes{reason, names}, both validated at load, so the retention rationale is a reviewed field rather than a YAML comment.common/dex/basesetsdisableNameSuffixHash: true, so the reason is corrected. The Dashboard README now namesdashboard-configas the one stable-named ConfigMap.basescenarios are renamed to what they compare:platform-network-policies(kubeflow-namespaces) andplatform-cluster-roles(kubeflow-roles).test_-prefixed Helm test files are renamed to the repository's component-first convention (dex_login_test.py,kserve_manifest_test.py), for exampletests/dashboard_helm_manifest_generator_test.pyandtests/helm_kustomize_compare_test.py(tests: use component-first test file names).5. The descriptor format is documented in
tests/README.md— every field, the pattern syntax, the staleness rule, and how to add a chart — with a pointer from each chart README (tests: document the comparison descriptor format).Verification
Run with Helm
v4.2.2, the version the workflow pins.origin/master, instrumented, and run against the new one: byte-identical rendered inputs and identical verdicts across all 38 comparisons (39 after Notebooks joined the matrix).tests/comparison_descriptors_test.py(18 tests) andtests/helm_kustomize_compare_test.py(21 tests, both invocation forms the workflow uses) pass;actionlint,black,shellcheckandgit diff --checkare clean.scripts/synchronize-dashboard-manifests.shre-run end to end produces no tree change, so it remains idempotent.Note for reviewers with repository administration access
Job names change. Any branch protection required status check configured on
Compare All Scenarios,Test Dex Helm behavior,Test Istio Helm behavior,Compare Dashboard Helm and Kustomize manifests,Compare Notebooks Helm and Kustomize manifestsorTest comparison normalizationmust be remapped toDiscover comparison components,Compare <component>andTest chart behavior. This is the one part of the change a contributor cannot make.Deliberately out of scope
remove_empty_valuesstill treats an empty list as equal to an absent field on both sides, the one remaining normalization that can hide a real difference (an emptyjobNamespaceslist renders a different operator configuration than an absent one). Narrowing it changes verdicts, so it is a follow-up; with this pull request in place, that follow-up is a data change reviewed per chart.📦 Dependencies
None. This pull request stands alone.
It deletes shared files that the Pipelines chart #3552, the Dex CustomResourceDefinition lifecycle fix #3574 and the Spark Operator wrapper chart #3575 all touch; all three are conflicting today because the Notebooks chart #3525 merged into those files. Merging this first means each of them rebases onto it once and stops conflicting with the others.
🐛 Related Issues
None.
✅ Contributor Checklist