You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by or...@apache.org on 2021/06/23 07:48:38 UTC

[camel-k] 07/15: languages: support kamelet eip #2375

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

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

commit c819a0576570e5e2b27b5f7cff4ff07c7fe4cd75
Author: Luca Burgazzoli <lb...@gmail.com>
AuthorDate: Tue Jun 8 15:02:03 2021 +0200

    languages: support kamelet eip #2375
---
 pkg/resources/resources.go                    |  8 +++
 pkg/trait/kamelets.go                         | 24 +------
 pkg/util/source/inspector.go                  | 12 ++++
 pkg/util/source/inspector_groovy.go           | 10 +++
 pkg/util/source/inspector_groovy_test.go      | 97 +++++++++++++++++++++++++++
 pkg/util/source/inspector_java_script.go      | 10 +++
 pkg/util/source/inspector_java_script_test.go | 81 ++++++++++++++++++++++
 pkg/util/source/inspector_java_source.go      | 10 +++
 pkg/util/source/inspector_java_source_test.go | 81 ++++++++++++++++++++++
 pkg/util/source/inspector_kamelet.go          | 50 ++++++++++++++
 pkg/util/source/inspector_kotlin.go           | 10 +++
 pkg/util/source/inspector_kotlin_test.go      | 81 ++++++++++++++++++++++
 pkg/util/source/inspector_xml.go              |  7 ++
 pkg/util/source/inspector_xml_test.go         | 90 +++++++++++++++++++++++++
 pkg/util/source/inspector_yaml.go             |  8 +++
 pkg/util/source/inspector_yaml_test.go        | 92 +++++++++++++++++++++++++
 pkg/util/source/types.go                      |  2 +
 17 files changed, 652 insertions(+), 21 deletions(-)

diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go
index d7e9c58..ca6c785 100644
--- a/pkg/resources/resources.go
+++ b/pkg/resources/resources.go
@@ -464,6 +464,13 @@ var assets = func() http.FileSystem {
 
 			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x7d\x4b\x77\xdb\x3a\x96\xee\x3c\xbf\x82\xeb\x64\xd2\xbd\x6e\x09\x75\x4e\x52\xb7\x4f\xdf\xdc\x91\x2d\xc7\x89\x1d\xcb\x71\x22\x57\x92\xaa\xc9\x59\x10\x09\x51\xb0\x48\x82\x06\x40\x59\xce\xaf\xef\x85\x07\x9f\x52\x36\x1f\x06\xd4\x1a\x88\x20\xb1\xf1\x6d\xec\x0f\x0f\x12\xef\xd7\xc1\xcc\xdd\xef\xd5\xeb\xe0\x86\x86\x24\x13\x24\x0a\x24\x0b\xe4\x86\x04\x67\x39\x0e\x37\x24\x58\xb2\xb5\x7c\xc2\x9c\x04\x97\xac\xc8\x22\x2c\x29\x [...]
 		},
+		"/camel-catalog-1.9.0-SNAPSHOT.yaml": &vfsgen۰CompressedFileInfo{
+			name:             "camel-catalog-1.9.0-SNAPSHOT.yaml",
+			modTime:          time.Time{},
+			uncompressedSize: 89731,
+
+			compressedContent: []byte("\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\xc4\x7d\x5b\x77\xdb\x38\xb6\xe6\x7b\x7e\x05\x57\xe5\xe5\x9c\x35\x2d\x74\x55\xaa\xe7\xd4\x4c\xcd\x93\x23\xc7\x89\x1d\xcb\x71\x22\x77\x92\xee\x97\x5a\x10\x09\x49\xb0\x48\x82\x06\x40\x59\xce\xaf\x9f\x05\x10\xbc\x4a\xd9\xbc\x78\xc3\xad\x07\xf1\x82\x8d\x6f\x63\x7f\xb8\x10\x77\xbc\x0e\x66\x78\xbf\x57\xaf\x83\x6b\x1e\xb2\x54\xb1\x28\xd0\x22\xd0\x5b\x16\x9c\x65\x34\xdc\xb2\x60\x29\xd6\xfa\x91\x4a\x16\x5c\x88\x3c\x8d\xa8\xe6\x [...]
+		},
 		"/traits.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "traits.yaml",
 			modTime:          time.Time{},
@@ -475,6 +482,7 @@ var assets = func() http.FileSystem {
 	fs["/"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
 		fs["/addons"].(os.FileInfo),
 		fs["/camel-catalog-1.7.0.yaml"].(os.FileInfo),
+		fs["/camel-catalog-1.9.0-SNAPSHOT.yaml"].(os.FileInfo),
 		fs["/crd"].(os.FileInfo),
 		fs["/default"].(os.FileInfo),
 		fs["/manager"].(os.FileInfo),
diff --git a/pkg/trait/kamelets.go b/pkg/trait/kamelets.go
index 8ef161d..1f3cdef 100644
--- a/pkg/trait/kamelets.go
+++ b/pkg/trait/kamelets.go
@@ -20,6 +20,7 @@ package trait
 import (
 	"errors"
 	"fmt"
+	"github.com/apache/camel-k/pkg/util/source"
 	"regexp"
 	"sort"
 	"strconv"
@@ -102,8 +103,7 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, error) {
 				return false, err
 			}
 			metadata.Each(e.CamelCatalog, sources, func(_ int, meta metadata.IntegrationMetadata) bool {
-				util.StringSliceUniqueConcat(&kamelets, extractKamelets(meta.FromURIs))
-				util.StringSliceUniqueConcat(&kamelets, extractKamelets(meta.ToURIs))
+				util.StringSliceUniqueConcat(&kamelets, meta.Kamelets)
 				return true
 			})
 		}
@@ -111,7 +111,7 @@ func (t *kameletsTrait) Configure(e *Environment) (bool, error) {
 		defaultErrorHandlerURI := e.Integration.Spec.GetConfigurationProperty(v1alpha1.ErrorHandlerAppPropertiesPrefix + ".deadLetterUri")
 		if defaultErrorHandlerURI != "" {
 			if strings.HasPrefix(defaultErrorHandlerURI, "kamelet:") {
-				kamelets = append(kamelets, extractKamelet(defaultErrorHandlerURI))
+				kamelets = append(kamelets, source.ExtractKamelet(defaultErrorHandlerURI))
 			}
 		}
 
@@ -444,21 +444,3 @@ func integrationSourceFromKameletSource(e *Environment, kamelet *v1alpha1.Kamele
 	target.ContentKey = contentKey
 	return *target, nil
 }
-
-func extractKamelets(uris []string) (kamelets []string) {
-	for _, uri := range uris {
-		kamelet := extractKamelet(uri)
-		if kamelet != "" {
-			kamelets = append(kamelets, kamelet)
-		}
-	}
-	return
-}
-
-func extractKamelet(uri string) (kamelet string) {
-	matches := kameletNameRegexp.FindStringSubmatch(uri)
-	if len(matches) > 1 {
-		return matches[1]
-	}
-	return ""
-}
diff --git a/pkg/util/source/inspector.go b/pkg/util/source/inspector.go
index 550d334..c2f80fd 100644
--- a/pkg/util/source/inspector.go
+++ b/pkg/util/source/inspector.go
@@ -58,6 +58,8 @@ var (
 	xqueryRegexp            = regexp.MustCompile(`.*\.xquery\s*\(.*\).*`)
 	xpathRegexp             = regexp.MustCompile(`.*\.?xpath\s*\(.*\).*`)
 	xtokenizeRegexp         = regexp.MustCompile(`.*\.xtokenize\s*\(.*\).*`)
+	singleQuotedKameletEip  = regexp.MustCompile(`kamelet\s*\(\s*'(?://)?([a-z0-9-.]+(/[a-z0-9-.]+)?)(?:$|[^a-z0-9-.].*)'`)
+	doubleQuotedKameletEip  = regexp.MustCompile(`kamelet\s*\(\s*"(?://)?([a-z0-9-.]+(/[a-z0-9-.]+)?)(?:$|[^a-z0-9-.].*)"`)
 
 	sourceCapabilities = map[*regexp.Regexp][]string{
 		circuitBreakerRegexp: {v1.CapabilityCircuitBreaker},
@@ -287,6 +289,16 @@ func (i *baseInspector) discoverDependencies(source v1.SourceSpec, meta *Metadat
 	}
 }
 
+// discoverDependencies inspects endpoints and extract kamelets
+func (i *baseInspector) discoverKamelets(source v1.SourceSpec, meta *Metadata) {
+	for _, uri := range meta.FromURIs {
+		AddKamelet(meta, uri)
+	}
+	for _, uri := range meta.ToURIs {
+		AddKamelet(meta, uri)
+	}
+}
+
 func (i *baseInspector) addDependency(dependency string, meta *Metadata) {
 	meta.Dependencies.Add(dependency)
 }
diff --git a/pkg/util/source/inspector_groovy.go b/pkg/util/source/inspector_groovy.go
index 1a49f71..3181078 100644
--- a/pkg/util/source/inspector_groovy.go
+++ b/pkg/util/source/inspector_groovy.go
@@ -47,8 +47,18 @@ func (i GroovyInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
 
+	kameletEips := util.FindAllDistinctStringSubmatch(
+		source.Content,
+		singleQuotedKameletEip,
+		doubleQuotedKameletEip)
+
+	for _, k := range kameletEips {
+		AddKamelet(meta, "kamelet:"+k)
+	}
+
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	hasRest := restRegexp.MatchString(source.Content) || restClosureRegexp.MatchString(source.Content)
 	if hasRest {
diff --git a/pkg/util/source/inspector_groovy_test.go b/pkg/util/source/inspector_groovy_test.go
new file mode 100644
index 0000000..b69aa28
--- /dev/null
+++ b/pkg/util/source/inspector_groovy_test.go
@@ -0,0 +1,97 @@
+/*
+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 source
+
+import (
+	"fmt"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/camel-k/pkg/util/camel"
+)
+
+const GroovyKameletEip = `
+from("direct:start")
+    .kamelet("foo/bar?baz=test")
+`
+const GroovyKameletEip_SingleQuote = `
+from("direct:start")
+    .kamelet('foo/bar?baz=test')
+`
+const GroovyKameletEndpoint = `
+from("direct:start")
+    .to("kamelet:foo/bar?baz=test")
+`
+const GroovyKameletEndpoint_SingleQuote = `
+from("direct:start")
+    .to('kamelet:foo/bar?baz=test')
+`
+
+func TestGroovyKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   GroovyKameletEip,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   GroovyKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   GroovyKameletEip_SingleQuote,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   GroovyKameletEndpoint_SingleQuote,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestGroovyKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := GroovyInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/inspector_java_script.go b/pkg/util/source/inspector_java_script.go
index dfc4b04..d8679e0 100644
--- a/pkg/util/source/inspector_java_script.go
+++ b/pkg/util/source/inspector_java_script.go
@@ -47,8 +47,18 @@ func (i JavaScriptInspector) Extract(source v1.SourceSpec, meta *Metadata) error
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
 
+	kameletEips := util.FindAllDistinctStringSubmatch(
+		source.Content,
+		singleQuotedKameletEip,
+		doubleQuotedKameletEip)
+
+	for _, k := range kameletEips {
+		AddKamelet(meta, "kamelet:"+k)
+	}
+
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	hasRest := restRegexp.MatchString(source.Content)
 	if hasRest {
diff --git a/pkg/util/source/inspector_java_script_test.go b/pkg/util/source/inspector_java_script_test.go
new file mode 100644
index 0000000..20f0a7b
--- /dev/null
+++ b/pkg/util/source/inspector_java_script_test.go
@@ -0,0 +1,81 @@
+/*
+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 source
+
+import (
+	"fmt"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/camel-k/pkg/util/camel"
+)
+
+const JavaScriptKameletEip = `
+from("direct:start")
+    .kamelet("foo/bar?baz=test")
+`
+const JavaScriptKameletEndpoint = `
+from("direct:start")
+    .to("kamelet:foo/bar?baz=test")
+`
+
+func TestJavaScriptKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   JavaScriptKameletEip,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   JavaScriptKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestJavaScriptKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := JavaScriptInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/inspector_java_source.go b/pkg/util/source/inspector_java_source.go
index 354370f..80981e7 100644
--- a/pkg/util/source/inspector_java_source.go
+++ b/pkg/util/source/inspector_java_source.go
@@ -42,8 +42,18 @@ func (i JavaSourceInspector) Extract(source v1.SourceSpec, meta *Metadata) error
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
 
+	kameletEips := util.FindAllDistinctStringSubmatch(
+		source.Content,
+		singleQuotedKameletEip,
+		doubleQuotedKameletEip)
+
+	for _, k := range kameletEips {
+		AddKamelet(meta, "kamelet:"+k)
+	}
+
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	hasRest := restRegexp.MatchString(source.Content)
 	if hasRest {
diff --git a/pkg/util/source/inspector_java_source_test.go b/pkg/util/source/inspector_java_source_test.go
new file mode 100644
index 0000000..52a7bf0
--- /dev/null
+++ b/pkg/util/source/inspector_java_source_test.go
@@ -0,0 +1,81 @@
+/*
+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 source
+
+import (
+	"fmt"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/camel-k/pkg/util/camel"
+)
+
+const JavaSourceKameletEip = `
+from("direct:start")
+    .kamelet("foo/bar?baz=test")
+`
+const JavaSourceKameletEndpoint = `
+from("direct:start")
+    .to("kamelet:foo/bar?baz=test")
+`
+
+func TestJavaSourceKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   JavaSourceKameletEip,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   JavaSourceKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestJavaSourceKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := JavaSourceInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/inspector_kamelet.go b/pkg/util/source/inspector_kamelet.go
new file mode 100644
index 0000000..3ae82a3
--- /dev/null
+++ b/pkg/util/source/inspector_kamelet.go
@@ -0,0 +1,50 @@
+/*
+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 source
+
+import (
+	"regexp"
+)
+
+var (
+	kameletNameRegexp = regexp.MustCompile("kamelet:(?://)?([a-z0-9-.]+(/[a-z0-9-.]+)?)(?:$|[^a-z0-9-.].*)")
+)
+
+func ExtractKamelets(uris []string) (kamelets []string) {
+	for _, uri := range uris {
+		kamelet := ExtractKamelet(uri)
+		if kamelet != "" {
+			kamelets = append(kamelets, kamelet)
+		}
+	}
+	return
+}
+
+func ExtractKamelet(uri string) (kamelet string) {
+	matches := kameletNameRegexp.FindStringSubmatch(uri)
+	if len(matches) > 1 {
+		return matches[1]
+	}
+	return ""
+}
+
+func AddKamelet(meta *Metadata, content string) {
+	if maybeKamelet := ExtractKamelet(content); maybeKamelet != "" {
+		meta.Kamelets = append(meta.Kamelets, maybeKamelet)
+	}
+}
diff --git a/pkg/util/source/inspector_kotlin.go b/pkg/util/source/inspector_kotlin.go
index 6de0a23..b2485c2 100644
--- a/pkg/util/source/inspector_kotlin.go
+++ b/pkg/util/source/inspector_kotlin.go
@@ -42,8 +42,18 @@ func (i KotlinInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 	meta.FromURIs = append(meta.FromURIs, from...)
 	meta.ToURIs = append(meta.ToURIs, to...)
 
+	kameletEips := util.FindAllDistinctStringSubmatch(
+		source.Content,
+		singleQuotedKameletEip,
+		doubleQuotedKameletEip)
+
+	for _, k := range kameletEips {
+		AddKamelet(meta, "kamelet:"+k)
+	}
+
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	hasRest := restRegexp.MatchString(source.Content) || restClosureRegexp.MatchString(source.Content)
 	if hasRest {
diff --git a/pkg/util/source/inspector_kotlin_test.go b/pkg/util/source/inspector_kotlin_test.go
new file mode 100644
index 0000000..bd4c7ce
--- /dev/null
+++ b/pkg/util/source/inspector_kotlin_test.go
@@ -0,0 +1,81 @@
+/*
+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 source
+
+import (
+	"fmt"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/camel-k/pkg/util/camel"
+)
+
+const KotlinKameletEip = `
+from("direct:start")
+    .kamelet("foo/bar?baz=test")
+`
+const KotlinKameletEndpoint = `
+from("direct:start")
+    .to("kamelet:foo/bar?baz=test")
+`
+
+func TestKotlinKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   KotlinKameletEip,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   KotlinKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestKotlinKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := KotlinInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/inspector_xml.go b/pkg/util/source/inspector_xml.go
index a1f1a9c..40c5489 100644
--- a/pkg/util/source/inspector_xml.go
+++ b/pkg/util/source/inspector_xml.go
@@ -68,6 +68,12 @@ func (i XMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 						meta.ToURIs = append(meta.ToURIs, a.Value)
 					}
 				}
+			case "kamelet":
+				for _, a := range se.Attr {
+					if a.Name.Local == "name" {
+						AddKamelet(meta, "kamelet:"+a.Value)
+					}
+				}
 			}
 
 			if dependency, ok := i.catalog.GetLanguageDependency(se.Name.Local); ok {
@@ -78,6 +84,7 @@ func (i XMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	meta.ExposesHTTPServices = meta.ExposesHTTPServices || i.containsHTTPURIs(meta.FromURIs)
 	meta.PassiveEndpoints = i.hasOnlyPassiveEndpoints(meta.FromURIs)
diff --git a/pkg/util/source/inspector_xml_test.go b/pkg/util/source/inspector_xml_test.go
new file mode 100644
index 0000000..75102a4
--- /dev/null
+++ b/pkg/util/source/inspector_xml_test.go
@@ -0,0 +1,90 @@
+/*
+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 source
+
+import (
+	"fmt"
+	v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+
+	"github.com/apache/camel-k/pkg/util/camel"
+)
+
+const XMLKameletEip = `
+<camelContext xmlns="http://camel.apache.org/schema/spring">
+  <route>
+    <from uri="direct:start"/>
+    <kamelet name="foo/bar?baz=test"/>
+    <to uri="mock:result"/>
+  </route>
+</camelContext>
+`
+const XMLKameletEndpoint = `
+<camelContext xmlns="http://camel.apache.org/schema/spring">
+  <route>
+    <from uri="direct:start"/>
+    <to uri="kamelet:foo/bar?baz=test"/>
+  </route>
+</camelContext>
+`
+
+func TestXMLKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   XMLKameletEip,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   XMLKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestXMLKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := XMLInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/inspector_yaml.go b/pkg/util/source/inspector_yaml.go
index 04a00f7..b5f9846 100644
--- a/pkg/util/source/inspector_yaml.go
+++ b/pkg/util/source/inspector_yaml.go
@@ -48,6 +48,7 @@ func (i YAMLInspector) Extract(source v1.SourceSpec, meta *Metadata) error {
 
 	i.discoverCapabilities(source, meta)
 	i.discoverDependencies(source, meta)
+	i.discoverKamelets(source, meta)
 
 	meta.ExposesHTTPServices = meta.ExposesHTTPServices || i.containsHTTPURIs(meta.FromURIs)
 	meta.PassiveEndpoints = i.hasOnlyPassiveEndpoints(meta.FromURIs)
@@ -87,6 +88,13 @@ func (i YAMLInspector) parseStep(key string, content interface{}, meta *Metadata
 				}
 			}
 		}
+	case "kamelet":
+		switch t := content.(type) {
+		case string:
+			AddKamelet(meta, "kamelet:"+t)
+		case map[interface{}]interface{}:
+			AddKamelet(meta, "kamelet:"+t["name"].(string))
+		}
 	}
 
 	var maybeURI string
diff --git a/pkg/util/source/inspector_yaml_test.go b/pkg/util/source/inspector_yaml_test.go
index 5858309..69ed703 100644
--- a/pkg/util/source/inspector_yaml_test.go
+++ b/pkg/util/source/inspector_yaml_test.go
@@ -327,3 +327,95 @@ func TestYAMLJson(t *testing.T) {
 		})
 	}
 }
+
+const YAMLKameletEipNoId = `
+- from:
+    uri: timer:tick
+    steps:
+    - kamelet: "foo"
+`
+
+const YAMLKameletEipInline = `
+- from:
+    uri: timer:tick
+    steps:
+    - kamelet: "foo/bar?baz=test"
+`
+const YAMLKameletEipMap = `
+- from:
+    uri: timer:tick
+    steps:
+    - kamelet: 
+        name: "foo/bar?baz=test"
+`
+const YAMLKameletEipMapWithParams = `
+- from:
+    uri: timer:tick
+    steps:
+    - kamelet: 
+        name: "foo/bar"
+        parameters:
+          baz:test
+`
+const YAMLKameletEndpoint = `
+- from:
+    uri: timer:tick
+    steps:
+    - to: "kamelet:foo/bar?baz=test"
+`
+
+func TestYAMLKamelet(t *testing.T) {
+	tc := []struct {
+		source   string
+		kamelets []string
+	}{
+		{
+			source:   YAMLKameletEipNoId,
+			kamelets: []string{"foo"},
+		},
+		{
+			source:   YAMLKameletEipInline,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   YAMLKameletEipMap,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   YAMLKameletEipMapWithParams,
+			kamelets: []string{"foo/bar"},
+		},
+		{
+			source:   YAMLKameletEndpoint,
+			kamelets: []string{"foo/bar"},
+		},
+	}
+
+	for i, test := range tc {
+		t.Run(fmt.Sprintf("TestYAMLKamelet-%d", i), func(t *testing.T) {
+			code := v1.SourceSpec{
+				DataSpec: v1.DataSpec{
+					Content: test.source,
+				},
+			}
+
+			catalog, err := camel.DefaultCatalog()
+			assert.Nil(t, err)
+
+			meta := NewMetadata()
+			inspector := YAMLInspector{
+				baseInspector: baseInspector{
+					catalog: catalog,
+				},
+			}
+
+			err = inspector.Extract(code, &meta)
+			assert.Nil(t, err)
+			assert.True(t, meta.RequiredCapabilities.IsEmpty())
+
+			for _, k := range test.kamelets {
+				assert.Contains(t, meta.Kamelets, k)
+			}
+		})
+	}
+}
diff --git a/pkg/util/source/types.go b/pkg/util/source/types.go
index f6f15e0..9bbbaa5 100644
--- a/pkg/util/source/types.go
+++ b/pkg/util/source/types.go
@@ -37,6 +37,8 @@ type Metadata struct {
 	// RequiredCapabilities lists the capabilities required by the integration
 	// to run
 	RequiredCapabilities *strset.Set
+	// All kamelets
+	Kamelets []string
 }
 
 // NewMetadata --