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

nfilotto pushed a commit to branch 2850/add-custom-kamelet-catalog
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit f4facf6e6e444a70ef2795ba24a0aadae47b4e44
Author: Nicolas Filotto <nfilo...@talend.com>
AuthorDate: Thu Sep 8 19:18:31 2022 +0200

    feat(cli): Add add-repo command to add a repo for custom Kamelet catalog
---
 .../files/TimerCustomKameletIntegration.java       |  28 ++++++
 e2e/global/common/kamelet_test.go                  |  46 ++++++---
 pkg/cmd/kamelet.go                                 |   1 +
 pkg/cmd/kamelet_add_repo.go                        | 111 +++++++++++++++++++++
 pkg/cmd/kamelet_get.go                             |   5 +-
 pkg/cmd/kit_get.go                                 |   5 +-
 6 files changed, 176 insertions(+), 20 deletions(-)

diff --git a/e2e/global/common/files/TimerCustomKameletIntegration.java 
b/e2e/global/common/files/TimerCustomKameletIntegration.java
new file mode 100644
index 000000000..9f749d834
--- /dev/null
+++ b/e2e/global/common/files/TimerCustomKameletIntegration.java
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+import java.lang.Exception;
+import java.lang.Override;
+import org.apache.camel.builder.RouteBuilder;
+
+public class TimerCustomKameletIntegration extends RouteBuilder {
+    @Override
+    public void configure() throws Exception {
+        from("kamelet:timer-custom-source?message=great%20message")
+            .to("log:info");
+    }
+}
diff --git a/e2e/global/common/kamelet_test.go 
b/e2e/global/common/kamelet_test.go
index d255f7319..c9e08e251 100644
--- a/e2e/global/common/kamelet_test.go
+++ b/e2e/global/common/kamelet_test.go
@@ -41,18 +41,40 @@ func TestKameletClasspathLoading(t *testing.T) {
 
                Eventually(Kamelet(kameletName, ns)).Should(BeNil())
 
-               Expect(KamelRunWithID(operatorID, ns, 
"files/TimerKameletIntegration.java", "-t", "kamelets.enabled=false",
-                       "--resource", 
"file:files/timer-source.kamelet.yaml@/kamelets/timer-source.kamelet.yaml",
-                       "-p camel.component.kamelet.location=file:/kamelets",
-                       "-d", "camel:yaml-dsl",
-                       // kamelet dependencies
-                       "-d", "camel:timer").Execute()).To(Succeed())
-               Eventually(IntegrationPodPhase(ns, 
"timer-kamelet-integration"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
-
-               Eventually(IntegrationLogs(ns, 
"timer-kamelet-integration")).Should(ContainSubstring("important message"))
-
-               // Cleanup
-               Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).Should(BeNil())
+               // Basic
+               t.Run("test basic case", func(t *testing.T) {
+
+                       Expect(KamelRunWithID(operatorID, ns, 
"files/TimerKameletIntegration.java", "-t", "kamelets.enabled=false",
+                               "--resource", 
"file:files/timer-source.kamelet.yaml@/kamelets/timer-source.kamelet.yaml",
+                               "-p 
camel.component.kamelet.location=file:/kamelets",
+                               "-d", "camel:yaml-dsl",
+                               // kamelet dependencies
+                               "-d", "camel:timer").Execute()).To(Succeed())
+                       Eventually(IntegrationPodPhase(ns, 
"timer-kamelet-integration"), TestTimeoutLong).Should(Equal(corev1.PodRunning))
+
+                       Eventually(IntegrationLogs(ns, 
"timer-kamelet-integration")).Should(ContainSubstring("important message"))
+
+                       // Cleanup
+                       Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).Should(BeNil())
+               })
+
+               // Custom repo
+               t.Run("test custom Kamelet repository", func(t *testing.T) {
+
+                       // Add the custom repository
+                       Expect(Kamel("kamelet", "add-repo", 
"github:essobedo/camel-k-test/kamelets", "-n", ns, "-x", 
operatorID).Execute()).To(Succeed())
+
+                       Expect(KamelRunWithID(operatorID, ns, 
"files/TimerCustomKameletIntegration.java",
+                               "-d", "camel:yaml-dsl",
+                               // kamelet dependencies
+                               "-d", "camel:timer").Execute()).To(Succeed())
+                       Eventually(IntegrationPodPhase(ns, 
"timer-custom-kamelet-integration"), 
TestTimeoutLong).Should(Equal(corev1.PodRunning))
+
+                       Eventually(IntegrationLogs(ns, 
"timer-custom-kamelet-integration")).Should(ContainSubstring("great message"))
+
+                       // Cleanup
+                       Expect(Kamel("delete", "--all", "-n", 
ns).Execute()).Should(BeNil())
+               })
        })
 }
 
diff --git a/pkg/cmd/kamelet.go b/pkg/cmd/kamelet.go
index 89a09062c..7645fd0c2 100644
--- a/pkg/cmd/kamelet.go
+++ b/pkg/cmd/kamelet.go
@@ -30,6 +30,7 @@ func newCmdKamelet(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
 
        cmd.AddCommand(cmdOnly(newKameletGetCmd(rootCmdOptions)))
        cmd.AddCommand(cmdOnly(newKameletDeleteCmd(rootCmdOptions)))
+       cmd.AddCommand(cmdOnly(newKameletAddRepoCmd(rootCmdOptions)))
 
        return &cmd
 }
diff --git a/pkg/cmd/kamelet_add_repo.go b/pkg/cmd/kamelet_add_repo.go
new file mode 100644
index 000000000..c288ff2b9
--- /dev/null
+++ b/pkg/cmd/kamelet_add_repo.go
@@ -0,0 +1,111 @@
+/*
+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 cmd
+
+import (
+       "errors"
+       "fmt"
+       "regexp"
+
+       v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       "github.com/spf13/cobra"
+       k8serrors "k8s.io/apimachinery/pkg/api/errors"
+       "sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+// kameletRepositoryURIRegexp is the regular expression used to validate the 
URI of a Kamelet repository.
+var kameletRepositoryURIRegexp = 
regexp.MustCompile(`^github:[^/]+/[^/]+((/[^/]+)*)?$`)
+
+func newKameletAddRepoCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, 
*kameletAddRepoCommandOptions) {
+       options := kameletAddRepoCommandOptions{
+               RootCmdOptions: rootCmdOptions,
+       }
+
+       cmd := cobra.Command{
+               Use:     "add-repo 
github:owner/repo[/path_to_kamelets_folder][@version] ...",
+               Short:   "Add a Kamelet repository",
+               Long:    `Add a Kamelet repository.`,
+               PreRunE: decode(&options),
+               RunE: func(cmd *cobra.Command, args []string) error {
+                       if err := options.validate(args); err != nil {
+                               return err
+                       }
+                       return options.run(cmd, args)
+               },
+       }
+
+       cmd.Flags().StringP("operator-id", "x", "camel-k", "Id of the Operator 
to update.")
+
+       return &cmd, &options
+}
+
+type kameletAddRepoCommandOptions struct {
+       *RootCmdOptions
+       OperatorID string `mapstructure:"operator-id" yaml:",omitempty"`
+}
+
+func (o *kameletAddRepoCommandOptions) validate(args []string) error {
+       if len(args) < 1 {
+               return errors.New("at least one Kamelet repository is expected")
+       }
+       if o.OperatorID == "" {
+               return fmt.Errorf("cannot use empty operator id")
+       }
+       return nil
+}
+
+func (o *kameletAddRepoCommandOptions) run(cmd *cobra.Command, args []string) 
error {
+       c, err := o.GetCmdClient()
+       if err != nil {
+               return err
+       }
+       key := client.ObjectKey{
+               Namespace: o.Namespace,
+               Name:      o.OperatorID,
+       }
+       platform := v1.IntegrationPlatform{}
+       if err := c.Get(o.Context, key, &platform); err != nil {
+               if k8serrors.IsNotFound(err) {
+                       // IntegrationPlatform may be in the operator 
namespace, but we currently don't have a way to determine it: we just warn
+                       fmt.Fprintf(cmd.ErrOrStderr(), "Warning: 
IntegrationPlatform %q not found in namespace %q\n", key.Name, key.Namespace)
+                       return nil
+               }
+               return err
+       }
+       for _, uri := range args {
+               if err := checkURI(uri, platform.Spec.Kamelet.Repositories); 
err != nil {
+                       return err
+               }
+               platform.Spec.Kamelet.Repositories = 
append(platform.Spec.Kamelet.Repositories, 
v1.IntegrationPlatformKameletRepositorySpec{
+                       URI: uri,
+               })
+       }
+       return c.Update(o.Context, &platform)
+}
+
+func checkURI(uri string, repositories 
[]v1.IntegrationPlatformKameletRepositorySpec) error {
+       if !kameletRepositoryURIRegexp.MatchString(uri) {
+               return fmt.Errorf("malformed Kamelet repository uri %s, the 
expected format is github:owner/repo[/path_to_kamelets_folder][@version]", uri)
+       }
+       for _, repo := range repositories {
+               if repo.URI == uri {
+                       return fmt.Errorf("duplicate Kamelet repository uri 
%s", uri)
+               }
+       }
+       return nil
+}
diff --git a/pkg/cmd/kamelet_get.go b/pkg/cmd/kamelet_get.go
index 013e92c0f..ced23216a 100644
--- a/pkg/cmd/kamelet_get.go
+++ b/pkg/cmd/kamelet_get.go
@@ -44,11 +44,8 @@ func newKameletGetCmd(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *kameletG
                        if err := options.validate(); err != nil {
                                return err
                        }
-                       if err := options.run(cmd); err != nil {
-                               fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
-                       }
 
-                       return nil
+                       return options.run(cmd)
                },
        }
 
diff --git a/pkg/cmd/kit_get.go b/pkg/cmd/kit_get.go
index e74864897..47f78268a 100644
--- a/pkg/cmd/kit_get.go
+++ b/pkg/cmd/kit_get.go
@@ -42,11 +42,8 @@ func newKitGetCmd(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *kitGetComman
                        if err := options.validate(cmd, args); err != nil {
                                return err
                        }
-                       if err := options.run(cmd); err != nil {
-                               fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
-                       }
 
-                       return nil
+                       return options.run(cmd)
                },
        }
 

Reply via email to