This is an automated email from the ASF dual-hosted git repository.

oscerd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-kamelets.git


The following commit(s) were added to refs/heads/main by this push:
     new 6b1282eb3 ci: add catalog consistency rules to the Kamelet validator 
(#2881)
6b1282eb3 is described below

commit 6b1282eb3583508b4a55f604df87622f22b0dfbe
Author: Andrea Cosentino <[email protected]>
AuthorDate: Thu Jun 25 18:26:17 2026 +0200

    ci: add catalog consistency rules to the Kamelet validator (#2881)
    
    Now that the validator inspects every Kamelet again, add four
    regression-guard rules to script/validator:
    
    - reject the deprecated "urn:alm:descriptor:com.tectonic.ui" x-descriptor
      prefix (use "urn:camel:group:credentials" instead);
    - enforce the routing convention: a source Kamelet routes to
      "kamelet:sink" and a sink Kamelet consumes from "kamelet:source";
    - validate spec.dependencies syntax (camel: / mvn:group:artifact:version
      / github:apache/...);
    - check that every Kamelet shares the same
      camel.apache.org/catalog.version annotation.
    
    All four are green on the current catalog and were each verified to fire
    on an injected violation.
    
    Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
---
 script/validator/validator.go | 67 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/script/validator/validator.go b/script/validator/validator.go
index 147cca105..cff38b7aa 100644
--- a/script/validator/validator.go
+++ b/script/validator/validator.go
@@ -72,6 +72,9 @@ func main() {
        errors = append(errors, verifyDescriptors(kamelets)...)
        errors = append(errors, verifyDuplicates(kamelets)...)
        errors = append(errors, verifyUsedParams(kamelets)...)
+       errors = append(errors, verifyTemplateConvention(kamelets)...)
+       errors = append(errors, verifyDependencies(kamelets)...)
+       errors = append(errors, verifyCatalogVersion(kamelets)...)
 
        for _, err := range errors {
                fmt.Printf("ERROR: %v\n", err)
@@ -114,7 +117,71 @@ func verifyDescriptors(kamelets []KameletInfo) (errors 
[]error) {
                        if p.Format == "password" && !hasXDescriptor(p, 
credDescriptor) {
                                errors = append(errors, fmt.Errorf("property %q 
in kamelet %q has \"password\" format but misses descriptor %q", k, 
kamelet.Name, credDescriptor))
                        }
+                       deprecatedDescriptorPrefix := 
"urn:alm:descriptor:com.tectonic.ui"
+                       if hasXDescriptorPrefix(p, deprecatedDescriptorPrefix) {
+                               errors = append(errors, fmt.Errorf("property %q 
in kamelet %q uses the deprecated x-descriptor prefix %q; use %q instead", k, 
kamelet.Name, deprecatedDescriptorPrefix, credDescriptor))
+                       }
+               }
+       }
+       return errors
+}
+
+// verifyTemplateConvention enforces the routing convention documented in the
+// catalog README: a source Kamelet sends to "kamelet:sink" and a sink Kamelet
+// consumes from "kamelet:source". Action Kamelets are not constrained here.
+func verifyTemplateConvention(kamelets []KameletInfo) (errors []error) {
+       for _, kamelet := range kamelets {
+               if kamelet.Spec.Template == nil {
+                       continue
+               }
+               template := string(kamelet.Spec.Template.RawMessage)
+               switch kamelet.Labels["camel.apache.org/kamelet.type"] {
+               case "source":
+                       if !strings.Contains(template, "kamelet:sink") {
+                               errors = append(errors, fmt.Errorf("source 
kamelet %q must route to \"kamelet:sink\"", kamelet.Name))
+                       }
+               case "sink":
+                       if !strings.Contains(template, "kamelet:source") {
+                               errors = append(errors, fmt.Errorf("sink 
kamelet %q must consume from \"kamelet:source\"", kamelet.Name))
+                       }
+               }
+       }
+       return errors
+}
+
+// verifyDependencies enforces the dependency syntax documented in the catalog
+// README: every spec.dependencies entry must be a "camel:<component>",
+// "mvn:group:artifact:version" or "github:apache/..." reference.
+func verifyDependencies(kamelets []KameletInfo) (errors []error) {
+       for _, kamelet := range kamelets {
+               for _, dep := range kamelet.Spec.Dependencies {
+                       if !strings.HasPrefix(dep, "camel:") &&
+                               !strings.HasPrefix(dep, "mvn:") &&
+                               !strings.HasPrefix(dep, "github:apache/") {
+                               errors = append(errors, fmt.Errorf("kamelet %q 
declares dependency %q that is not a \"camel:\", \"mvn:group:artifact:version\" 
or \"github:apache/...\" reference", kamelet.Name, dep))
+                       }
+               }
+       }
+       return errors
+}
+
+// verifyCatalogVersion checks that every Kamelet shares the same
+// camel.apache.org/catalog.version annotation, catching a Kamelet that was
+// added or edited without bumping the catalog version.
+func verifyCatalogVersion(kamelets []KameletInfo) (errors []error) {
+       const versionAnnotation = "camel.apache.org/catalog.version"
+       versions := make(map[string][]string)
+       for _, kamelet := range kamelets {
+               v := kamelet.Annotations[versionAnnotation]
+               versions[v] = append(versions[v], kamelet.Name)
+       }
+       if len(versions) > 1 {
+               summary := make([]string, 0, len(versions))
+               for v, names := range versions {
+                       summary = append(summary, fmt.Sprintf("%q (%d 
kamelets)", v, len(names)))
                }
+               sort.Strings(summary)
+               errors = append(errors, fmt.Errorf("inconsistent %s across the 
catalog: %s", versionAnnotation, strings.Join(summary, ", ")))
        }
        return errors
 }

Reply via email to