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

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


The following commit(s) were added to refs/heads/main by this push:
     new 09dd6b0d8 feat(cmd): bind .spec.traits instead of annotations
09dd6b0d8 is described below

commit 09dd6b0d810203ed524e88450b9920f864fc5cd7
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Sat Nov 29 09:32:58 2025 +0100

    feat(cmd): bind .spec.traits instead of annotations
    
    Closes #6327
---
 docs/modules/ROOT/pages/pipes/bind-cli.adoc  |   4 +-
 docs/modules/ROOT/pages/pipes/pipes.adoc     |  18 +--
 docs/modules/ROOT/pages/pipes/promoting.adoc |  10 +-
 pkg/apis/camel/v1/common_types.go            |   1 +
 pkg/apis/camel/v1/pipe_types_support.go      |  26 +---
 pkg/apis/camel/v1/pipe_types_support_test.go |  25 ++--
 pkg/cmd/bind.go                              |  31 +----
 pkg/cmd/bind_test.go                         |  11 +-
 pkg/cmd/promote.go                           | 109 ++++++----------
 pkg/cmd/promote_test.go                      | 179 +++++++++++++++++++--------
 10 files changed, 215 insertions(+), 199 deletions(-)

diff --git a/docs/modules/ROOT/pages/pipes/bind-cli.adoc 
b/docs/modules/ROOT/pages/pipes/bind-cli.adoc
index d783dbf68..5133b22a6 100644
--- a/docs/modules/ROOT/pages/pipes/bind-cli.adoc
+++ b/docs/modules/ROOT/pages/pipes/bind-cli.adoc
@@ -67,7 +67,6 @@ kind: Pipe
 metadata:
   annotations:
     camel.apache.org/operator.id: camel-k
-    trait.camel.apache.org/camel.runtime-version: 3.6.0
   name: timer-source-to-log-sink
   namespace: camel-k
 spec:
@@ -85,5 +84,8 @@ spec:
       kind: Kamelet
       name: timer-source
       namespace: camel-k
+  traits:
+    camel:
+      runtime-version: 3.6.0
 status: {}
 ----
diff --git a/docs/modules/ROOT/pages/pipes/pipes.adoc 
b/docs/modules/ROOT/pages/pipes/pipes.adoc
index f11d0b46b..25d145f1b 100644
--- a/docs/modules/ROOT/pages/pipes/pipes.adoc
+++ b/docs/modules/ROOT/pages/pipes/pipes.adoc
@@ -67,31 +67,31 @@ In the example above we're making sure to call an 
intermediate resource in order
 
 === Traits configuration
 
-Although this should not be necessarily required (the operator do all the 
required configuration for you), you can tune your `Pipe` with 
xref:traits:traits.adoc[traits] configuration adding `.metadata.annotations`. 
Let's have a look at the following example:
+Although this should not be necessarily required (the operator do all the 
required configuration for you), you can tune your `Pipe` with 
xref:traits:traits.adoc[traits] configuration adding `.spec.traits` as you are 
used to do with Integration. Let's have a look at the following example:
 
-.timer-2-log-annotation.yaml
+.timer-2-log.yaml
 [source,yaml,subs="attributes+"]
 ----
 apiVersion: camel.apache.org/v1
 kind: Pipe
 metadata:
-  name: timer-2-log-annotation
-  annotations: # <1>
-    trait.camel.apache.org/logging.level: DEBUG
-    trait.camel.apache.org/logging.color: "false"
+  name: timer-2-log
 spec:
   source:
     uri: timer:foo
   sink:
     uri: log:bar
+  traits:
+    mount:
+      configs:
+      - configmap:my-cm
 ----
-<1> Include `.metadata.annotations` to specify the list of traits we want to 
configure
 
-In this example, we've set the `logging` trait to specify certain 
configuration we want to apply. You can do the same with all the traits 
available, just by setting `trait.camel.apache.org/trait-name.trait-property` 
with the expected value.
+In this example, we've set the `mount` trait to add a given Configmap at 
runtime. You can do the same with all the traits available.
 
 [NOTE]
 ====
-If you need to specify an array of values, the syntax will be 
`trait.camel.apache.org/trait.conf: "[\"opt1\", \"opt2\", ...]"`
+You can use `kamel bind -t` as well.
 ====
 
 == Using Kamel CLI
diff --git a/docs/modules/ROOT/pages/pipes/promoting.adoc 
b/docs/modules/ROOT/pages/pipes/promoting.adoc
index 4e31ba68b..c7bde9367 100644
--- a/docs/modules/ROOT/pages/pipes/promoting.adoc
+++ b/docs/modules/ROOT/pages/pipes/promoting.adoc
@@ -32,9 +32,6 @@ kind: Pipe
 metadata:
   annotations:
     camel.apache.org/kamelet.icon: 
data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gU3ZnIFZlY3RvciBJY29ucyA6IGh0dHA6Ly93d3cub25saW5ld2ViZm9udHMuY29tL2ljb24gLS0...
-    trait.camel.apache.org/camel.runtime-version: 3.8.1
-    trait.camel.apache.org/container.image: 
10.100.107.57/camel-k/camel-k-kit-crbhu56n5tgc73cb1ts0@sha256:e3f66b61148e77ceda8531632847b455219300d95c9e640f4924b7e69419c2b9
-    trait.camel.apache.org/jvm.classpath: 
dependencies/*:dependencies/app/*:dependencies/lib/boot/*:dependencies/lib/main/*:dependencies/quarkus/*
   name: timer-source-to-log-sink
   namespace: prod
 spec:
@@ -52,6 +49,13 @@ spec:
       kind: Kamelet
       name: timer-source
       namespace: prod
+  traits:
+    camel:
+      runtime-version: 3.8.1
+    container:
+      image: 
10.100.107.57/camel-k/camel-k-kit-crbhu56n5tgc73cb1ts0@sha256:e3f66b61148e77ceda8531632847b455219300d95c9e640f4924b7e69419c2b9
+    jvm:
+      classpath: 
dependencies/*:dependencies/app/*:dependencies/lib/boot/*:dependencies/lib/main/*:dependencies/quarkus/*
 status: {}
 ----
 
diff --git a/pkg/apis/camel/v1/common_types.go 
b/pkg/apis/camel/v1/common_types.go
index 39d7fe9c5..f70e0f5b5 100644
--- a/pkg/apis/camel/v1/common_types.go
+++ b/pkg/apis/camel/v1/common_types.go
@@ -25,6 +25,7 @@ import (
 
 const (
        // TraitAnnotationPrefix represents the prefix used for traits 
annotations.
+       // Deprecated: use .spec.traits instead.
        TraitAnnotationPrefix = "trait.camel.apache.org/"
        // OperatorIDAnnotation operator id annotation label.
        OperatorIDAnnotation = "camel.apache.org/operator.id"
diff --git a/pkg/apis/camel/v1/pipe_types_support.go 
b/pkg/apis/camel/v1/pipe_types_support.go
index eee0ff853..173f74d9f 100644
--- a/pkg/apis/camel/v1/pipe_types_support.go
+++ b/pkg/apis/camel/v1/pipe_types_support.go
@@ -22,7 +22,6 @@ import (
        "encoding/json"
        "fmt"
 
-       scase "github.com/stoewer/go-strcase"
        corev1 "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
@@ -72,28 +71,9 @@ func (in *Pipe) SetOperatorID(operatorID string) {
        SetAnnotation(&in.ObjectMeta, OperatorIDAnnotation, operatorID)
 }
 
-// SetTrait converts a trait into the related annotation.
-func (in *Pipe) SetTraits(traits *Traits) error {
-       var mappedTraits map[string]map[string]interface{}
-       data, err := json.Marshal(traits)
-       if err != nil {
-               return err
-       }
-       err = json.Unmarshal(data, &mappedTraits)
-       if err != nil {
-               return err
-       }
-
-       if in.Annotations == nil && (len(mappedTraits) > 0) {
-               in.Annotations = make(map[string]string)
-       }
-       for id, trait := range mappedTraits {
-               for k, v := range trait {
-                       in.Annotations[fmt.Sprintf("%s%s.%s", 
TraitAnnotationPrefix, id, scase.KebabCase(k))] = fmt.Sprintf("%v", v)
-               }
-       }
-
-       return nil
+// SetTrait add the Trait specification to the Pipe.
+func (in *Pipe) SetTraits(traits *Traits) {
+       in.Spec.Traits = traits
 }
 
 // GetCondition returns the condition with the provided type.
diff --git a/pkg/apis/camel/v1/pipe_types_support_test.go 
b/pkg/apis/camel/v1/pipe_types_support_test.go
index 312515fc5..dfa71e2a5 100644
--- a/pkg/apis/camel/v1/pipe_types_support_test.go
+++ b/pkg/apis/camel/v1/pipe_types_support_test.go
@@ -67,15 +67,22 @@ func TestSetTraits(t *testing.T) {
                },
        }
 
-       expectedAnnotations := map[string]string(map[string]string{
-               "trait.camel.apache.org/affinity.enabled":        "true",
-               "trait.camel.apache.org/affinity.pod-affinity":   "true",
-               "trait.camel.apache.org/knative.channel-sources": "[channel-a 
channel-b]",
-               "trait.camel.apache.org/knative.enabled":         "true",
-       })
+       expectedTraits := &Traits{
+               Affinity: &trait.AffinityTrait{
+                       Trait: trait.Trait{
+                               Enabled: ptr.To(true),
+                       },
+                       PodAffinity: ptr.To(true),
+               },
+               Knative: &trait.KnativeTrait{
+                       Trait: trait.Trait{
+                               Enabled: ptr.To(true),
+                       },
+                       ChannelSources: []string{"channel-a", "channel-b"},
+               },
+       }
 
        pipe := NewPipe("my-pipe", "my-ns")
-       err := pipe.SetTraits(&traits)
-       assert.NoError(t, err)
-       assert.Equal(t, expectedAnnotations, pipe.Annotations)
+       pipe.SetTraits(&traits)
+       assert.Equal(t, expectedTraits, pipe.Spec.Traits)
 }
diff --git a/pkg/cmd/bind.go b/pkg/cmd/bind.go
index ed37e9e09..9d417ae34 100644
--- a/pkg/cmd/bind.go
+++ b/pkg/cmd/bind.go
@@ -232,17 +232,9 @@ func (o *bindCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
        }
 
        if len(o.Traits) > 0 {
-               if pipe.Annotations == nil {
-                       pipe.Annotations = make(map[string]string)
-               }
-
-               for _, t := range o.Traits {
-                       kv := strings.SplitN(t, "=", 2)
-                       if len(kv) != 2 {
-                               return fmt.Errorf("could not parse trait 
configuration %s, expected format 'trait.property=value'", t)
-                       }
-                       value := 
maybeBuildArrayNotation(pipe.Annotations[v1.TraitAnnotationPrefix+kv[0]], kv[1])
-                       pipe.Annotations[v1.TraitAnnotationPrefix+kv[0]] = value
+               catalog := trait.NewCatalog(client)
+               if err := trait.ConfigureTraits(o.Traits, &pipe.Spec.Traits, 
catalog); err != nil {
+                       return err
                }
        }
 
@@ -278,23 +270,6 @@ func (o *bindCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
        return nil
 }
 
-// buildArrayNotation is used to build an array annotation to support traits 
array configuration
-// for example, `-t camel.properties=a=1 -t camel.properties=b=2` would 
convert into annotation
-// `camel.properties=[a=1,b=2]“.
-func maybeBuildArrayNotation(array, value string) string {
-       if array == "" {
-               return value
-       }
-       // append
-       if strings.HasPrefix(array, "[") && strings.HasSuffix(array, "]") {
-               content := array[1:len(array)-1] + "," + value
-
-               return "[" + content + "]"
-       }
-       // init the array notation
-       return "[" + array + "," + value + "]"
-}
-
 func showPipeOutput(cmd *cobra.Command, binding *v1.Pipe, outputFormat string, 
scheme runtime.ObjectTyper) error {
        printer := printers.NewTypeSetter(scheme)
        printer.Delegate = &kubernetes.CLIPrinter{
diff --git a/pkg/cmd/bind_test.go b/pkg/cmd/bind_test.go
index 1a90437e9..956d54fa9 100644
--- a/pkg/cmd/bind_test.go
+++ b/pkg/cmd/bind_test.go
@@ -181,13 +181,16 @@ kind: Pipe
 metadata:
   annotations:
     camel.apache.org/operator.id: camel-k
-    trait.camel.apache.org/mount.configs: configmap:my-cm
   name: my-to-my
 spec:
   sink:
     uri: my:dst
   source:
     uri: my:src
+  traits:
+    mount:
+      configs:
+      - configmap:my-cm
 status: {}
 `, output)
 }
@@ -204,13 +207,17 @@ kind: Pipe
 metadata:
   annotations:
     camel.apache.org/operator.id: camel-k
-    trait.camel.apache.org/camel.properties: '[a=1,b=2]'
   name: my-to-my
 spec:
   sink:
     uri: my:dst
   source:
     uri: my:src
+  traits:
+    camel:
+      properties:
+      - a=1
+      - b=2
 status: {}
 `, output)
 }
diff --git a/pkg/cmd/promote.go b/pkg/cmd/promote.go
index b9d1e5abe..e7990a081 100644
--- a/pkg/cmd/promote.go
+++ b/pkg/cmd/promote.go
@@ -142,10 +142,7 @@ func (o *promoteCmdOptions) run(cmd *cobra.Command, args 
[]string) error {
 
        // Pipe promotion
        if promotePipe {
-               destPipe, err := o.editPipe(sourcePipe, sourceIntegration, 
sourceKit)
-               if err != nil {
-                       return err
-               }
+               destPipe := o.editPipe(sourcePipe, sourceIntegration, sourceKit)
                if o.OutputFormat != "" {
                        return showPipeOutput(cmd, destPipe, o.OutputFormat, 
c.GetScheme())
                }
@@ -265,7 +262,7 @@ func (o *promoteCmdOptions) editIntegration(it 
*v1.Integration, kit *v1.Integrat
                        dstIt.Spec.Traits.JVM = &traitv1.JVMTrait{}
                }
                jvmTrait := dstIt.Spec.Traits.JVM
-               mergedClasspath := getClasspath(kit, jvmTrait.Classpath)
+               mergedClasspath := getClasspath(kit, jvmTrait)
                jvmTrait.Classpath = mergedClasspath
                // We must also set the runtime version so we pin it to the 
given catalog on which
                // the container image was built
@@ -279,7 +276,11 @@ func (o *promoteCmdOptions) editIntegration(it 
*v1.Integration, kit *v1.Integrat
 }
 
 // getClasspath merges the classpath required by the kit with any value 
provided in the trait.
-func getClasspath(kit *v1.IntegrationKit, jvmTraitClasspath string) string {
+func getClasspath(kit *v1.IntegrationKit, jvmTraitSpec *traitv1.JVMTrait) 
string {
+       jvmTraitClasspath := ""
+       if jvmTraitSpec != nil {
+               jvmTraitClasspath = jvmTraitSpec.Classpath
+       }
        kitClasspathSet := kit.Status.GetDependenciesPaths()
        if !kitClasspathSet.IsEmpty() {
                if jvmTraitClasspath != "" {
@@ -335,7 +336,7 @@ func cloneLabels(lbs map[string]string) map[string]string {
        return newMap
 }
 
-func (o *promoteCmdOptions) editPipe(kb *v1.Pipe, it *v1.Integration, kit 
*v1.IntegrationKit) (*v1.Pipe, error) {
+func (o *promoteCmdOptions) editPipe(kb *v1.Pipe, it *v1.Integration, kit 
*v1.IntegrationKit) *v1.Pipe {
        contImage := it.Status.Image
        // Pipe
        dst := v1.NewPipe(o.To, kb.Name)
@@ -354,11 +355,12 @@ func (o *promoteCmdOptions) editPipe(kb *v1.Pipe, it 
*v1.Integration, kit *v1.In
                // We must provide the classpath expected for the 
IntegrationKit. This is calculated dynamically and
                // would get lost when creating the non managed build 
Integration. For this reason
                // we must report it in the promoted Integration.
-               mergedClasspath := getClasspath(kit, 
dst.Annotations[v1.TraitAnnotationPrefix+"jvm.classpath"])
                if traits.JVM == nil {
                        traits.JVM = &traitv1.JVMTrait{}
                }
-               traits.JVM.Classpath = mergedClasspath
+               jvmTrait := traits.JVM
+               mergedClasspath := getClasspath(kit, jvmTrait)
+               jvmTrait.Classpath = mergedClasspath
                // We must also set the runtime version so we pin it to the 
given catalog on which
                // the container image was built
                if traits.Camel == nil {
@@ -366,9 +368,8 @@ func (o *promoteCmdOptions) editPipe(kb *v1.Pipe, it 
*v1.Integration, kit *v1.In
                }
                traits.Camel.RuntimeVersion = kit.Status.RuntimeVersion
        }
-       if err := dst.SetTraits(traits); err != nil {
-               return nil, err
-       }
+       dst.SetTraits(traits)
+
        if dst.Spec.Source.Ref != nil {
                dst.Spec.Source.Ref.Namespace = o.To
        }
@@ -383,7 +384,7 @@ func (o *promoteCmdOptions) editPipe(kb *v1.Pipe, it 
*v1.Integration, kit *v1.In
                }
        }
 
-       return &dst, nil
+       return &dst
 }
 
 func (o *promoteCmdOptions) replaceResource(res k8sclient.Object) (bool, 
error) {
@@ -481,10 +482,32 @@ patches:
 
 // getIntegrationPatch will filter those traits/configuration we want to 
include in the Integration patch.
 func getIntegrationPatch(baseIt *v1.Integration) *v1.Integration {
+       patchedTraits := patchTraits(baseIt.Spec.Traits)
+
+       patchedIt := v1.NewIntegration("", baseIt.Name)
+       patchedIt.Spec = v1.IntegrationSpec{
+               Traits: patchedTraits,
+       }
+
+       return &patchedIt
+}
+
+// getPipePatch will filter those traits/configuration we want to include in 
the Pipe patch.
+func getPipePatch(basePipe *v1.Pipe) *v1.Pipe {
+       patchedTraits := patchTraits(*basePipe.Spec.Traits)
+
+       patchedPipe := v1.NewPipe("", basePipe.Name)
+       patchedPipe.Spec = v1.PipeSpec{
+               Traits: &patchedTraits,
+       }
+
+       return &patchedPipe
+}
+
+func patchTraits(baseTraits v1.Traits) v1.Traits {
        patchedTraits := v1.Traits{}
-       baseTraits := baseIt.Spec.Traits
        if baseTraits.Affinity != nil {
-               patchedTraits.Affinity = baseIt.Spec.Traits.Affinity
+               patchedTraits.Affinity = baseTraits.Affinity
        }
        if baseTraits.Camel != nil && baseTraits.Camel.Properties != nil {
                patchedTraits.Camel = &traitv1.CamelTrait{
@@ -520,15 +543,10 @@ func getIntegrationPatch(baseIt *v1.Integration) 
*v1.Integration {
                }
        }
        if baseTraits.Toleration != nil {
-               patchedTraits.Toleration = baseIt.Spec.Traits.Toleration
+               patchedTraits.Toleration = baseTraits.Toleration
        }
 
-       patchedIt := v1.NewIntegration("", baseIt.Name)
-       patchedIt.Spec = v1.IntegrationSpec{
-               Traits: patchedTraits,
-       }
-
-       return &patchedIt
+       return patchedTraits
 }
 
 // appendKustomizePipe creates a Kustomize GitOps based directory structure 
for the chosen Pipe.
@@ -593,50 +611,3 @@ patches:
 
        return err
 }
-
-// getPipePatch will filter those traits/configuration we want to include in 
the Pipe patch.
-func getPipePatch(basePipe *v1.Pipe) *v1.Pipe {
-       patchedPipe := v1.NewPipe("", basePipe.Name)
-       patchedPipe.Annotations = basePipe.Annotations
-       // Only keep those traits we want to include in the patch
-       for kAnn := range basePipe.Annotations {
-               if strings.HasPrefix(kAnn, v1.TraitAnnotationPrefix) {
-                       if !isPipeTraitPatch(kAnn) {
-                               delete(basePipe.Annotations, kAnn)
-                       }
-               }
-       }
-
-       return &patchedPipe
-}
-
-// isPipeTraitPatch returns true if it belongs to the list of the opinionated 
traits we want to keep in the patch.
-func isPipeTraitPatch(keyAnnotation string) bool {
-       if strings.HasPrefix(keyAnnotation, 
v1.TraitAnnotationPrefix+"affinity") {
-               return true
-       }
-       if keyAnnotation == v1.TraitAnnotationPrefix+"camel.properties" {
-               return true
-       }
-       if strings.HasPrefix(keyAnnotation, 
v1.TraitAnnotationPrefix+"container.request") ||
-               strings.HasPrefix(keyAnnotation, 
v1.TraitAnnotationPrefix+"container.limit") {
-               return true
-       }
-       if keyAnnotation == v1.TraitAnnotationPrefix+"environment.vars" {
-               return true
-       }
-       if keyAnnotation == v1.TraitAnnotationPrefix+"jvm.options" {
-               return true
-       }
-       if strings.HasPrefix(keyAnnotation, 
v1.TraitAnnotationPrefix+"mount.configs") ||
-               strings.HasPrefix(keyAnnotation, 
v1.TraitAnnotationPrefix+"mount.resources") ||
-               strings.HasPrefix(keyAnnotation, 
v1.TraitAnnotationPrefix+"mount.volumes") ||
-               strings.HasPrefix(keyAnnotation, 
v1.TraitAnnotationPrefix+"mount.empty-dirs") {
-               return true
-       }
-       if strings.HasPrefix(keyAnnotation, 
v1.TraitAnnotationPrefix+"toleration") {
-               return true
-       }
-
-       return false
-}
diff --git a/pkg/cmd/promote_test.go b/pkg/cmd/promote_test.go
index fbbb44e7c..4c55880db 100644
--- a/pkg/cmd/promote_test.go
+++ b/pkg/cmd/promote_test.go
@@ -154,15 +154,18 @@ func TestPipeDryRun(t *testing.T) {
        assert.Equal(t, `apiVersion: camel.apache.org/v1
 kind: Pipe
 metadata:
-  annotations:
-    trait.camel.apache.org/camel.runtime-version: 1.2.3
-    trait.camel.apache.org/container.image: my-special-image
-    trait.camel.apache.org/jvm.classpath: 
/path/to/artifact-1/*:/path/to/artifact-2/*
   name: my-pipe-test
   namespace: prod-namespace
 spec:
   sink: {}
   source: {}
+  traits:
+    camel:
+      runtimeVersion: 1.2.3
+    container:
+      image: my-special-image
+    jvm:
+      classpath: /path/to/artifact-1/*:/path/to/artifact-2/*
 status: {}
 `, output)
 }
@@ -254,9 +257,6 @@ kind: Pipe
 metadata:
   annotations:
     my-annotation: my-value
-    trait.camel.apache.org/camel.runtime-version: 1.2.3
-    trait.camel.apache.org/container.image: my-special-image
-    trait.camel.apache.org/jvm.classpath: 
/path/to/artifact-1/*:/path/to/artifact-2/*
   labels:
     my-label: my-value
   name: my-pipe-test
@@ -264,6 +264,13 @@ metadata:
 spec:
   sink: {}
   source: {}
+  traits:
+    camel:
+      runtimeVersion: 1.2.3
+    container:
+      image: my-special-image
+    jvm:
+      classpath: /path/to/artifact-1/*:/path/to/artifact-2/*
 status: {}
 `, output)
 }
@@ -442,9 +449,6 @@ kind: Pipe
 metadata:
   annotations:
     my-annotation: my-value
-    trait.camel.apache.org/camel.runtime-version: 1.2.3
-    trait.camel.apache.org/container.image: my-special-image
-    trait.camel.apache.org/jvm.classpath: 
/path/to/artifact-1/*:/path/to/artifact-2/*
   labels:
     my-label: my-value
   name: my-pipe-test
@@ -452,6 +456,13 @@ metadata:
 spec:
   sink: {}
   source: {}
+  traits:
+    camel:
+      runtimeVersion: 1.2.3
+    container:
+      image: my-special-image
+    jvm:
+      classpath: /path/to/artifact-1/*:/path/to/artifact-2/*
 status: {}
 `, output)
 }
@@ -605,50 +616,83 @@ kind: Pipe
 metadata:
   annotations:
     my-annotation: my-value
-    trait.camel.apache.org/affinity.node-affinity-labels: '[node1,node2]'
-    trait.camel.apache.org/camel.properties: '[a=1]'
-    trait.camel.apache.org/camel.runtime-version: 1.2.3
-    trait.camel.apache.org/container.image: my-special-image
-    trait.camel.apache.org/container.image-pull-policy: Always
-    trait.camel.apache.org/container.limit-cpu: "2"
-    trait.camel.apache.org/container.limit-memory: 1024Mi
-    trait.camel.apache.org/container.request-cpu: "1"
-    trait.camel.apache.org/container.request-memory: 2048Mi
-    trait.camel.apache.org/environment.vars: '[MYVAR=1]'
-    trait.camel.apache.org/jvm.classpath: 
/path/to/artifact-1/*:/path/to/artifact-2/*
-    trait.camel.apache.org/jvm.jar: my.jar
-    trait.camel.apache.org/jvm.options: '[-XMX 123]'
-    trait.camel.apache.org/mount.resources: 
'[configmap:my-cm,secret:my-sec/my-key@/tmp/file.txt]'
-    trait.camel.apache.org/service.auto: "false"
-    trait.camel.apache.org/toleration.taints: '[mytaints:true]'
   labels:
     my-label: my-value
   name: my-pipe-test
 spec:
   sink: {}
   source: {}
+  traits:
+    affinity:
+      nodeAffinityLabels:
+      - my-node
+    camel:
+      properties:
+      - my.property=val
+      runtimeVersion: 1.2.3
+    container:
+      image: my-special-image
+      imagePullPolicy: Always
+      limitCPU: "1"
+      limitMemory: 1024Mi
+      port: 2000
+      requestCPU: "0.5"
+      requestMemory: 512Mi
+    environment:
+      vars:
+      - MY_VAR=val
+    jvm:
+      classpath: /path/to/artifact-1/*:/path/to/artifact-2/*
+      jar: my.jar
+      options:
+      - -XMX 123
+    mount:
+      configs:
+      - configmap:my-cm
+      - secret:my-sec
+    service:
+      annotations:
+        my-annotation: "123"
+      auto: false
+      enabled: true
+    toleration:
+      taints:
+      - taint1:true
 status: {}
 `
 
 const expectedGitOpsPipePatch = `apiVersion: camel.apache.org/v1
 kind: Pipe
 metadata:
-  annotations:
-    my-annotation: my-value
-    trait.camel.apache.org/affinity.node-affinity-labels: '[node1,node2]'
-    trait.camel.apache.org/camel.properties: '[a=1]'
-    trait.camel.apache.org/container.limit-cpu: "2"
-    trait.camel.apache.org/container.limit-memory: 1024Mi
-    trait.camel.apache.org/container.request-cpu: "1"
-    trait.camel.apache.org/container.request-memory: 2048Mi
-    trait.camel.apache.org/environment.vars: '[MYVAR=1]'
-    trait.camel.apache.org/jvm.options: '[-XMX 123]'
-    trait.camel.apache.org/mount.resources: 
'[configmap:my-cm,secret:my-sec/my-key@/tmp/file.txt]'
-    trait.camel.apache.org/toleration.taints: '[mytaints:true]'
   name: my-pipe-test
 spec:
   sink: {}
   source: {}
+  traits:
+    affinity:
+      nodeAffinityLabels:
+      - my-node
+    camel:
+      properties:
+      - my.property=val
+    container:
+      limitCPU: "1"
+      limitMemory: 1024Mi
+      requestCPU: "0.5"
+      requestMemory: 512Mi
+    environment:
+      vars:
+      - MY_VAR=val
+    jvm:
+      options:
+      - -XMX 123
+    mount:
+      configs:
+      - configmap:my-cm
+      - secret:my-sec
+    toleration:
+      taints:
+      - taint1:true
 status: {}
 `
 
@@ -661,34 +705,59 @@ func TestPipeGitOps(t *testing.T) {
        dstPlatform.Status.Version = defaults.Version
        dstPlatform.Status.Build.RuntimeVersion = defaults.DefaultRuntimeVersion
        dstPlatform.Status.Phase = v1.IntegrationPlatformPhaseReady
-       defaultKB := nominalPipe("my-pipe-test")
-       defaultKB.Annotations = map[string]string{
+       defaultPipe := nominalPipe("my-pipe-test")
+       defaultPipe.Annotations = map[string]string{
                "camel.apache.org/operator.id": "camel-k",
                "my-annotation":                "my-value",
-               v1.TraitAnnotationPrefix + "affinity.node-affinity-labels": 
"[node1,node2]",
-               v1.TraitAnnotationPrefix + "camel.properties":              
"[a=1]",
-               v1.TraitAnnotationPrefix + "container.limit-cpu":           "2",
-               v1.TraitAnnotationPrefix + "container.limit-memory":        
"1024Mi",
-               v1.TraitAnnotationPrefix + "container.request-cpu":         "1",
-               v1.TraitAnnotationPrefix + "container.request-memory":      
"2048Mi",
-               v1.TraitAnnotationPrefix + "container.image-pull-policy":   
"Always",
-               v1.TraitAnnotationPrefix + "environment.vars":              
"[MYVAR=1]",
-               v1.TraitAnnotationPrefix + "jvm.options":                   
"[-XMX 123]",
-               v1.TraitAnnotationPrefix + "jvm.jar":                       
"my.jar",
-               v1.TraitAnnotationPrefix + "mount.resources":               
"[configmap:my-cm,secret:my-sec/my-key@/tmp/file.txt]",
-               v1.TraitAnnotationPrefix + "service.auto":                  
"false",
-               v1.TraitAnnotationPrefix + "toleration.taints":             
"[mytaints:true]",
        }
-       defaultKB.Labels = map[string]string{
+       defaultPipe.Labels = map[string]string{
                "my-label": "my-value",
        }
        defaultIntegration, defaultKit := nominalIntegration("my-pipe-test")
+       defaultIntegration.Status.Traits = &v1.Traits{
+               Affinity: &trait.AffinityTrait{
+                       NodeAffinityLabels: []string{"my-node"},
+               },
+               Camel: &trait.CamelTrait{
+                       Properties: []string{"my.property=val"},
+               },
+               Container: &trait.ContainerTrait{
+                       LimitCPU:        "1",
+                       LimitMemory:     "1024Mi",
+                       RequestCPU:      "0.5",
+                       RequestMemory:   "512Mi",
+                       Port:            2000,
+                       ImagePullPolicy: corev1.PullAlways,
+               },
+               Environment: &trait.EnvironmentTrait{
+                       Vars: []string{"MY_VAR=val"},
+               },
+               JVM: &trait.JVMTrait{
+                       Jar:     "my.jar",
+                       Options: []string{"-XMX 123"},
+               },
+               Mount: &trait.MountTrait{
+                       Configs: []string{"configmap:my-cm", "secret:my-sec"},
+               },
+               Service: &trait.ServiceTrait{
+                       Trait: trait.Trait{
+                               Enabled: ptr.To(true),
+                       },
+                       Auto: ptr.To(false),
+                       Annotations: map[string]string{
+                               "my-annotation": "123",
+                       },
+               },
+               Toleration: &trait.TolerationTrait{
+                       Taints: []string{"taint1:true"},
+               },
+       }
        srcCatalog := createTestCamelCatalog(srcPlatform)
        dstCatalog := createTestCamelCatalog(dstPlatform)
 
        tmpDir := t.TempDir()
 
-       _, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, 
&dstPlatform, &defaultKB, &defaultIntegration, &defaultKit, &srcCatalog, 
&dstCatalog)
+       _, promoteCmd, _ := initializePromoteCmdOptions(t, &srcPlatform, 
&dstPlatform, &defaultPipe, &defaultIntegration, &defaultKit, &srcCatalog, 
&dstCatalog)
        output, err := ExecuteCommand(promoteCmd, cmdPromote, "my-pipe-test", 
"--to", "prod-namespace", "--export-gitops-dir", tmpDir, "-n", "default")
        require.NoError(t, err)
        assert.Contains(t, output, `Exported a Kustomize based Gitops 
directory`)

Reply via email to