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 f3a76b4f2 feat(trait): add InfluencesBuild() func
f3a76b4f2 is described below

commit f3a76b4f2e8564a47bc661f8becc28d860f66b18
Author: Pasquale Congiusti <[email protected]>
AuthorDate: Mon Jun 26 12:48:01 2023 +0200

    feat(trait): add InfluencesBuild() func
    
    With this func we have a lower level of granularity, giving the possibility 
to each trait to define when influences a build.
    
    Closes #4511
---
 docs/modules/ROOT/pages/architecture/traits.adoc |  3 ++
 e2e/common/traits/camel_test.go                  | 61 ++++++++++++++++++++++++
 pkg/controller/integration/kits.go               | 25 +++++-----
 pkg/resources/resources.go                       | 17 +++++++
 pkg/trait/builder.go                             |  5 ++
 pkg/trait/camel.go                               |  5 ++
 pkg/trait/quarkus.go                             |  5 ++
 pkg/trait/registry.go                            |  5 ++
 pkg/trait/trait_types.go                         | 11 +++++
 9 files changed, 124 insertions(+), 13 deletions(-)

diff --git a/docs/modules/ROOT/pages/architecture/traits.adoc 
b/docs/modules/ROOT/pages/architecture/traits.adoc
index d773c6a6c..3457b3b4e 100644
--- a/docs/modules/ROOT/pages/architecture/traits.adoc
+++ b/docs/modules/ROOT/pages/architecture/traits.adoc
@@ -43,6 +43,7 @@ type Trait interface {
        Configure(environment *Environment) (bool, error)
        Apply(environment *Environment) error
        InfluencesKit() bool
+       InfluencesBuild(this, prev map[string]interface{}) bool
        IsPlatformTrait() bool
        RequiresIntegrationPlatform() bool
        IsAllowedInProfile(v1.TraitProfile) bool
@@ -58,4 +59,6 @@ The `Order()` method helps in resolving the order of 
execution of different trai
 
 The `InfluencesKit()`, `IsPlatformTrait()` and `RequiresIntegrationPlatform()` 
methods are easy to understand. They are used to determine if a trait has to 
influence an `IntegrationKit` build/initialization, if it's a platform trait 
(ie, needed by the platform itself) or are requiring the presence of an 
`IntegrationPlatform`.
 
+The presence of `InfluencesBuild()` will let specify the level of granularity 
of a trait down to its properties for a rebuild. So, if you need, you can 
compare the traits properties coming from the `prev` (previous) Integration to 
decide if it is worth to rebuild an Integration or the trait can reuse the one 
already provided in `this` version.
+
 Finally, through the `IsAllowedInProfile()` method we can override the default 
behavior (allow the trait for any profile). We must specify the profile we 
expect for this trait to be executed properly.
diff --git a/e2e/common/traits/camel_test.go b/e2e/common/traits/camel_test.go
new file mode 100644
index 000000000..aa41d69f9
--- /dev/null
+++ b/e2e/common/traits/camel_test.go
@@ -0,0 +1,61 @@
+//go:build integration
+// +build integration
+
+// To enable compilation of this file in Goland, go to "Settings -> Go -> 
Vendoring & Build Tags -> Custom Tags" and add "integration"
+
+/*
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package traits
+
+import (
+       "testing"
+
+       . "github.com/onsi/gomega"
+
+       corev1 "k8s.io/api/core/v1"
+
+       . "github.com/apache/camel-k/v2/e2e/support"
+       v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
+)
+
+func TestCamelTrait(t *testing.T) {
+       RegisterTestingT(t)
+
+       t.Run("properties changes should not rebuild", func(t *testing.T) {
+               name := "java"
+               Expect(KamelRunWithID(operatorID, ns, "files/Java.java",
+                       "--name", name,
+               ).Execute()).To(Succeed())
+               Eventually(IntegrationPodPhase(ns, name), 
TestTimeoutLong).Should(Equal(corev1.PodRunning))
+               Eventually(IntegrationConditionStatus(ns, name, 
v1.IntegrationConditionReady), 
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+               Eventually(IntegrationLogs(ns, name), 
TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
+               integrationKit := IntegrationKit(ns, name)()
+
+               Expect(KamelRunWithID(operatorID, ns, "files/Java.java",
+                       "--name", name,
+                       "-p", "a=1",
+               ).Execute()).To(Succeed())
+               Eventually(IntegrationPodPhase(ns, name), 
TestTimeoutShort).Should(Equal(corev1.PodRunning))
+               Eventually(IntegrationConditionStatus(ns, name, 
v1.IntegrationConditionReady), 
TestTimeoutShort).Should(Equal(corev1.ConditionTrue))
+               Eventually(IntegrationLogs(ns, name), 
TestTimeoutShort).Should(ContainSubstring("Magicstring!"))
+               Eventually(IntegrationKit(ns, 
name)).Should(Equal(integrationKit))
+       })
+
+       // Clean-up
+       Expect(Kamel("delete", "--all", "-n", ns).Execute()).To(Succeed())
+}
diff --git a/pkg/controller/integration/kits.go 
b/pkg/controller/integration/kits.go
index 8dbc7337f..e26c9f544 100644
--- a/pkg/controller/integration/kits.go
+++ b/pkg/controller/integration/kits.go
@@ -199,8 +199,7 @@ func hasMatchingTraits(traitMap trait.Options, kitTraitMap 
trait.Options) (bool,
        catalog := trait.NewCatalog(nil)
 
        for _, t := range catalog.AllTraits() {
-               if t == nil || !t.InfluencesKit() {
-                       // We don't store the trait configuration if the trait 
cannot influence the kit behavior
+               if t == nil {
                        continue
                }
 
@@ -211,17 +210,17 @@ func hasMatchingTraits(traitMap trait.Options, 
kitTraitMap trait.Options) (bool,
                if !ok1 && !ok2 {
                        continue
                }
-               if !ok1 || !ok2 {
-                       return false, nil
-               }
-               if ct, ok := t.(trait.ComparableTrait); ok {
-                       // if it's match trait use its matches method to 
determine the match
-                       if match, err := matchesComparableTrait(ct, it, kt); 
!match || err != nil {
-                               return false, err
-                       }
-               } else {
-                       if !matchesTrait(it, kt) {
-                               return false, nil
+
+               if t.InfluencesKit() && t.InfluencesBuild(it, kt) {
+                       if ct, ok := t.(trait.ComparableTrait); ok {
+                               // if it's match trait use its matches method 
to determine the match
+                               if match, err := matchesComparableTrait(ct, it, 
kt); !match || err != nil {
+                                       return false, err
+                               }
+                       } else {
+                               if !matchesTrait(it, kt) {
+                                       return false, nil
+                               }
                        }
                }
        }
diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go
index d6daa4592..b0d7a821a 100644
--- a/pkg/resources/resources.go
+++ b/pkg/resources/resources.go
@@ -174,6 +174,18 @@ var assets = func() http.FileSystem {
                        name:    "manager",
                        modTime: time.Time{},
                },
+               "/manager/bundle": &vfsgen۰DirInfo{
+                       name:    "bundle",
+                       modTime: time.Time{},
+               },
+               "/manager/bundle/manifests": &vfsgen۰DirInfo{
+                       name:    "manifests",
+                       modTime: time.Time{},
+               },
+               "/manager/bundle/metadata": &vfsgen۰DirInfo{
+                       name:    "metadata",
+                       modTime: time.Time{},
+               },
                "/manager/operator-deployment.yaml": &vfsgen۰CompressedFileInfo{
                        name:             "operator-deployment.yaml",
                        modTime:          time.Time{},
@@ -686,6 +698,7 @@ var assets = func() http.FileSystem {
                fs["/crd/bases/camel.apache.org_pipes.yaml"].(os.FileInfo),
        }
        fs["/manager"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
+               fs["/manager/bundle"].(os.FileInfo),
                fs["/manager/operator-deployment.yaml"].(os.FileInfo),
                fs["/manager/operator-pvc.yaml"].(os.FileInfo),
                fs["/manager/operator-service-account.yaml"].(os.FileInfo),
@@ -699,6 +712,10 @@ var assets = func() http.FileSystem {
                fs["/manager/patch-toleration.yaml"].(os.FileInfo),
                fs["/manager/patch-watch-namespace-global.yaml"].(os.FileInfo),
        }
+       fs["/manager/bundle"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
+               fs["/manager/bundle/manifests"].(os.FileInfo),
+               fs["/manager/bundle/metadata"].(os.FileInfo),
+       }
        fs["/prometheus"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
                fs["/prometheus/operator-pod-monitor.yaml"].(os.FileInfo),
                fs["/prometheus/operator-prometheus-rule.yaml"].(os.FileInfo),
diff --git a/pkg/trait/builder.go b/pkg/trait/builder.go
index 5c18f42c6..6e583d88c 100644
--- a/pkg/trait/builder.go
+++ b/pkg/trait/builder.go
@@ -53,6 +53,11 @@ func (t *builderTrait) InfluencesKit() bool {
        return true
 }
 
+// InfluencesBuild overrides base class method.
+func (t *builderTrait) InfluencesBuild(this, prev map[string]interface{}) bool 
{
+       return true
+}
+
 func (t *builderTrait) Configure(e *Environment) (bool, error) {
        if e.IntegrationKit == nil || !pointer.BoolDeref(t.Enabled, true) {
                return false, nil
diff --git a/pkg/trait/camel.go b/pkg/trait/camel.go
index 8974b7879..ecb5137f8 100644
--- a/pkg/trait/camel.go
+++ b/pkg/trait/camel.go
@@ -58,6 +58,11 @@ func (t *camelTrait) InfluencesKit() bool {
        return true
 }
 
+// InfluencesBuild only when the runtime has changed.
+func (t *camelTrait) InfluencesBuild(this, prev map[string]interface{}) bool {
+       return this["runtimeVersion"] != prev["runtimeVersion"]
+}
+
 func (t *camelTrait) Configure(e *Environment) (bool, error) {
        if !pointer.BoolDeref(t.Enabled, true) {
                return false, errors.New("trait camel cannot be disabled")
diff --git a/pkg/trait/quarkus.go b/pkg/trait/quarkus.go
index 23f011ae0..ae182e740 100644
--- a/pkg/trait/quarkus.go
+++ b/pkg/trait/quarkus.go
@@ -106,6 +106,11 @@ func (t *quarkusTrait) InfluencesKit() bool {
        return true
 }
 
+// InfluencesBuild overrides base class method.
+func (t *quarkusTrait) InfluencesBuild(this, prev map[string]interface{}) bool 
{
+       return true
+}
+
 var _ ComparableTrait = &quarkusTrait{}
 
 func (t *quarkusTrait) Matches(trait Trait) bool {
diff --git a/pkg/trait/registry.go b/pkg/trait/registry.go
index 508fa1905..27aed1355 100644
--- a/pkg/trait/registry.go
+++ b/pkg/trait/registry.go
@@ -53,6 +53,11 @@ func (t *registryTrait) InfluencesKit() bool {
        return true
 }
 
+// InfluencesBuild overrides base class method.
+func (t *registryTrait) InfluencesBuild(this, prev map[string]interface{}) 
bool {
+       return true
+}
+
 func (t *registryTrait) Configure(e *Environment) (bool, error) {
        // disabled by default
        if e.IntegrationKit == nil || !pointer.BoolDeref(t.Enabled, false) {
diff --git a/pkg/trait/trait_types.go b/pkg/trait/trait_types.go
index 6fb7e7b2d..7114f5667 100644
--- a/pkg/trait/trait_types.go
+++ b/pkg/trait/trait_types.go
@@ -69,6 +69,11 @@ type Trait interface {
        // InfluencesKit determines if the trait has any influence on 
Integration Kits
        InfluencesKit() bool
 
+       // InfluencesBuild defines a low level of granularity for those traits 
which influences the build.
+       // The trait can specify if any particular trait configuration 
influences a build or not.
+       // Note: You must override this method if you override `InfluencesKit()`
+       InfluencesBuild(this, prev map[string]interface{}) bool
+
        // IsPlatformTrait marks all fundamental traits that allow the platform 
to work
        IsPlatformTrait() bool
 
@@ -135,6 +140,12 @@ func (trait *BaseTrait) InfluencesKit() bool {
        return false
 }
 
+// InfluencesBuild defines a low level of granularity for those traits which 
influences the build.
+// The trait can specify if any particular trait configuration influences a 
build or not.
+func (trait *BaseTrait) InfluencesBuild(this, prev map[string]interface{}) 
bool {
+       return false
+}
+
 // IsPlatformTrait marks all fundamental traits that allow the platform to 
work.
 func (trait *BaseTrait) IsPlatformTrait() bool {
        return false

Reply via email to