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

tsato 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 5d6829d30 feat(cli): Make add-repo and remove-repo compatible with a 
global op
5d6829d30 is described below

commit 5d6829d30e54b657ff81eb8590519dfd986aeaa8
Author: Nicolas Filotto <nfilo...@talend.com>
AuthorDate: Mon Oct 10 12:58:53 2022 +0200

    feat(cli): Make add-repo and remove-repo compatible with a global op
---
 e2e/global/common/kamelet_test.go                  | 33 ++++----
 .../cli/files/TimerCustomKameletIntegration.java   | 28 +++++++
 e2e/namespace/install/cli/kamelet_test.go          | 60 +++++++++++++
 pkg/cmd/kamelet.go                                 |  1 +
 pkg/cmd/kamelet_add_repo.go                        | 66 +++++++++++----
 pkg/cmd/kamelet_remove_repo.go                     | 98 ++++++++++++++++++++++
 pkg/cmd/kamelet_remove_repo_test.go                | 86 +++++++++++++++++++
 7 files changed, 338 insertions(+), 34 deletions(-)

diff --git a/e2e/global/common/kamelet_test.go 
b/e2e/global/common/kamelet_test.go
index e6b8834fb..778bc3419 100644
--- a/e2e/global/common/kamelet_test.go
+++ b/e2e/global/common/kamelet_test.go
@@ -23,7 +23,6 @@ limitations under the License.
 package common
 
 import (
-       "os"
        "testing"
 
        . "github.com/onsi/gomega"
@@ -32,27 +31,19 @@ import (
        . "github.com/apache/camel-k/e2e/support"
 )
 
-/*
- * This seems to be problematic in a global context
- * See https://github.com/apache/camel-k/issues/3667 for details
- */
 func TestKameletClasspathLoading(t *testing.T) {
-       if os.Getenv("CAMEL_K_TEST_SKIP_PROBLEMATIC") == "true" {
-               t.Skip("WARNING: Test marked as problematic ... skipping")
-       }
 
        WithNewTestNamespace(t, func(ns string) {
                operatorID := "camel-k-kamelet"
                Expect(KamelInstallWithID(operatorID, 
ns).Execute()).To(Succeed())
 
-               kameletName := "timer-source"
-               removeKamelet(kameletName, ns)
-
-               Eventually(Kamelet(kameletName, ns)).Should(BeNil())
-
                // Basic
                t.Run("test basic case", func(t *testing.T) {
 
+                       kameletName := "timer-source"
+                       removeKamelet(kameletName, ns)
+                       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",
@@ -62,21 +53,25 @@ func TestKameletClasspathLoading(t *testing.T) {
                        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) {
+               // Custom repo without operator ID
+               t.Run("test custom Kamelet repository without operator ID", 
func(t *testing.T) {
+
+                       kameletName := "timer-custom-source"
+                       removeKamelet(kameletName, ns)
+                       Eventually(Kamelet(kameletName, ns)).Should(BeNil())
 
                        // Add the custom repository
-                       Expect(Kamel("kamelet", "add-repo", 
"github:apache/camel-k/e2e/global/common/files/kamelets", "-n", ns, "-x", 
operatorID).Execute()).To(Succeed())
+                       Expect(Kamel("kamelet", "add-repo", 
"github:apache/camel-k/e2e/global/common/files/kamelets", "-n", 
ns).Execute()).To(Succeed())
 
                        Expect(KamelRunWithID(operatorID, ns, 
"files/TimerCustomKameletIntegration.java").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"))
+
+                       // Remove the custom repository
+                       Expect(Kamel("kamelet", "remove-repo", 
"github:apache/camel-k/e2e/global/common/files/kamelets", "-n", 
ns).Execute()).To(Succeed())
                })
        })
 }
diff --git a/e2e/namespace/install/cli/files/TimerCustomKameletIntegration.java 
b/e2e/namespace/install/cli/files/TimerCustomKameletIntegration.java
new file mode 100644
index 000000000..fe96710d1
--- /dev/null
+++ b/e2e/namespace/install/cli/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=hello%20world")
+            .to("log:info");
+    }
+}
diff --git a/e2e/namespace/install/cli/kamelet_test.go 
b/e2e/namespace/install/cli/kamelet_test.go
new file mode 100644
index 000000000..9df9a5bfc
--- /dev/null
+++ b/e2e/namespace/install/cli/kamelet_test.go
@@ -0,0 +1,60 @@
+//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 common
+
+import (
+       "testing"
+
+       . "github.com/onsi/gomega"
+       corev1 "k8s.io/api/core/v1"
+
+       . "github.com/apache/camel-k/e2e/support"
+)
+
+func TestKameletFromCustomRepository(t *testing.T) {
+       WithNewTestNamespace(t, func(ns string) {
+               operatorID := operatorID(ns)
+               installWithID(ns)
+
+               kameletName := "timer-custom-source"
+               removeKamelet(kameletName, ns)
+
+               Eventually(Kamelet(kameletName, ns)).Should(BeNil())
+
+               // Add the custom repository
+               Expect(Kamel("kamelet", "add-repo", 
"github:apache/camel-k/e2e/global/common/files/kamelets", "-n", ns, "-x", 
operatorID).Execute()).To(Succeed())
+
+               Expect(KamelRunWithID(operatorID, ns, 
"files/TimerCustomKameletIntegration.java").Execute()).To(Succeed())
+               Eventually(IntegrationPodPhase(ns, 
"timer-custom-kamelet-integration"), 
TestTimeoutLong).Should(Equal(corev1.PodRunning))
+
+               Eventually(IntegrationLogs(ns, 
"timer-custom-kamelet-integration")).Should(ContainSubstring("hello world"))
+
+               // Remove the custom repository
+               Expect(Kamel("kamelet", "remove-repo", 
"github:apache/camel-k/e2e/global/common/files/kamelets", "-n", ns, "-x", 
operatorID).Execute()).To(Succeed())
+       })
+}
+
+func removeKamelet(name string, ns string) {
+       kamelet := Kamelet(name, ns)()
+       TestClient().Delete(TestContext, kamelet)
+}
diff --git a/pkg/cmd/kamelet.go b/pkg/cmd/kamelet.go
index 7645fd0c2..8b1f48b96 100644
--- a/pkg/cmd/kamelet.go
+++ b/pkg/cmd/kamelet.go
@@ -31,6 +31,7 @@ func newCmdKamelet(rootCmdOptions *RootCmdOptions) 
*cobra.Command {
        cmd.AddCommand(cmdOnly(newKameletGetCmd(rootCmdOptions)))
        cmd.AddCommand(cmdOnly(newKameletDeleteCmd(rootCmdOptions)))
        cmd.AddCommand(cmdOnly(newKameletAddRepoCmd(rootCmdOptions)))
+       cmd.AddCommand(cmdOnly(newKameletRemoveRepoCmd(rootCmdOptions)))
 
        return &cmd
 }
diff --git a/pkg/cmd/kamelet_add_repo.go b/pkg/cmd/kamelet_add_repo.go
index 92591823d..f7f8b6d9f 100644
--- a/pkg/cmd/kamelet_add_repo.go
+++ b/pkg/cmd/kamelet_add_repo.go
@@ -23,6 +23,7 @@ import (
        "regexp"
 
        v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       platformutil "github.com/apache/camel-k/pkg/platform"
        "github.com/spf13/cobra"
        k8serrors "k8s.io/apimachinery/pkg/api/errors"
        "sigs.k8s.io/controller-runtime/pkg/client"
@@ -33,7 +34,9 @@ var kameletRepositoryURIRegexp = 
regexp.MustCompile(`^github:[^/]+/[^/]+((/[^/]+
 
 func newKameletAddRepoCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, 
*kameletAddRepoCommandOptions) {
        options := kameletAddRepoCommandOptions{
-               RootCmdOptions: rootCmdOptions,
+               kameletUpdateRepoCommandOptions: 
&kameletUpdateRepoCommandOptions{
+                       RootCmdOptions: rootCmdOptions,
+               },
        }
 
        cmd := cobra.Command{
@@ -49,23 +52,24 @@ func newKameletAddRepoCmd(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *kame
                },
        }
 
-       cmd.Flags().StringP("operator-id", "x", "camel-k", "Id of the Operator 
to update.")
+       cmd.Flags().StringP("operator-id", "x", "", "Id of the Operator to 
update. If not set, the active primary Integration Platform is updated.")
 
        return &cmd, &options
 }
 
-type kameletAddRepoCommandOptions struct {
+type kameletUpdateRepoCommandOptions struct {
        *RootCmdOptions
        OperatorID string `mapstructure:"operator-id" yaml:",omitempty"`
 }
 
+type kameletAddRepoCommandOptions struct {
+       *kameletUpdateRepoCommandOptions
+}
+
 func (o *kameletAddRepoCommandOptions) validate(args []string) error {
        if len(args) == 0 {
                return errors.New("at least one Kamelet repository is expected")
        }
-       if o.OperatorID == "" {
-               return fmt.Errorf("cannot use empty operator id")
-       }
        return nil
 }
 
@@ -74,6 +78,30 @@ func (o *kameletAddRepoCommandOptions) run(cmd 
*cobra.Command, args []string) er
        if err != nil {
                return err
        }
+       var platform *v1.IntegrationPlatform
+       if o.OperatorID == "" {
+               platform, err = o.findIntegrationPlatorm(cmd, c)
+       } else {
+               platform, err = o.getIntegrationPlatorm(cmd, c)
+       }
+       if err != nil {
+               return err
+       } else if platform == nil {
+               return nil
+       }
+       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)
+}
+
+// getIntegrationPlatorm gives the integration plaform matching with the 
operator id in the provided namespace.
+func (o *kameletUpdateRepoCommandOptions) getIntegrationPlatorm(cmd 
*cobra.Command, c client.Client) (*v1.IntegrationPlatform, error) {
        key := client.ObjectKey{
                Namespace: o.Namespace,
                Name:      o.OperatorID,
@@ -83,19 +111,27 @@ func (o *kameletAddRepoCommandOptions) run(cmd 
*cobra.Command, args []string) er
                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 nil, nil
                }
-               return err
+               return nil, err
        }
-       for _, uri := range args {
-               if err := checkURI(uri, platform.Spec.Kamelet.Repositories); 
err != nil {
-                       return err
+       return &platform, nil
+}
+
+// findIntegrationPlatorm gives the primary integration plaform that could be 
found in the provided namespace.
+func (o *kameletUpdateRepoCommandOptions) findIntegrationPlatorm(cmd 
*cobra.Command, c client.Client) (*v1.IntegrationPlatform, error) {
+       platforms, err := platformutil.ListPrimaryPlatforms(o.Context, c, 
o.Namespace)
+       if err != nil {
+               return nil, err
+       }
+       for _, p := range platforms.Items {
+               p := p // pin
+               if platformutil.IsActive(&p) {
+                       return &p, nil
                }
-               platform.Spec.Kamelet.Repositories = 
append(platform.Spec.Kamelet.Repositories, 
v1.IntegrationPlatformKameletRepositorySpec{
-                       URI: uri,
-               })
        }
-       return c.Update(o.Context, &platform)
+       fmt.Fprintf(cmd.ErrOrStderr(), "Warning: No active primary 
IntegrationPlatform could be found in namespace %q\n", o.Namespace)
+       return nil, nil
 }
 
 func checkURI(uri string, repositories 
[]v1.IntegrationPlatformKameletRepositorySpec) error {
diff --git a/pkg/cmd/kamelet_remove_repo.go b/pkg/cmd/kamelet_remove_repo.go
new file mode 100644
index 000000000..18703681f
--- /dev/null
+++ b/pkg/cmd/kamelet_remove_repo.go
@@ -0,0 +1,98 @@
+/*
+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"
+
+       v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       "github.com/spf13/cobra"
+)
+
+func newKameletRemoveRepoCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, 
*kameletRemoveRepoCommandOptions) {
+       options := kameletRemoveRepoCommandOptions{
+               kameletUpdateRepoCommandOptions: 
&kameletUpdateRepoCommandOptions{
+                       RootCmdOptions: rootCmdOptions,
+               },
+       }
+
+       cmd := cobra.Command{
+               Use:     "remove-repo 
github:owner/repo[/path_to_kamelets_folder][@version] ...",
+               Short:   "Remove a Kamelet repository",
+               Long:    `Remove 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", "", "Id of the Operator to 
update. If not set, the active primary Integration Platform is updated.")
+
+       return &cmd, &options
+}
+
+type kameletRemoveRepoCommandOptions struct {
+       *kameletUpdateRepoCommandOptions
+}
+
+func (o *kameletRemoveRepoCommandOptions) validate(args []string) error {
+       if len(args) == 0 {
+               return errors.New("at least one Kamelet repository is expected")
+       }
+       return nil
+}
+
+func (o *kameletRemoveRepoCommandOptions) run(cmd *cobra.Command, args 
[]string) error {
+       c, err := o.GetCmdClient()
+       if err != nil {
+               return err
+       }
+       var platform *v1.IntegrationPlatform
+       if o.OperatorID == "" {
+               platform, err = o.findIntegrationPlatorm(cmd, c)
+       } else {
+               platform, err = o.getIntegrationPlatorm(cmd, c)
+       }
+       if err != nil {
+               return err
+       } else if platform == nil {
+               return nil
+       }
+       for _, uri := range args {
+               i, err := getURIIndex(uri, platform.Spec.Kamelet.Repositories)
+               if err != nil {
+                       return err
+               }
+               platform.Spec.Kamelet.Repositories[i] = 
platform.Spec.Kamelet.Repositories[len(platform.Spec.Kamelet.Repositories)-1]
+               platform.Spec.Kamelet.Repositories = 
platform.Spec.Kamelet.Repositories[:len(platform.Spec.Kamelet.Repositories)-1]
+       }
+       return c.Update(o.Context, platform)
+}
+
+func getURIIndex(uri string, repositories 
[]v1.IntegrationPlatformKameletRepositorySpec) (int, error) {
+       for i, repo := range repositories {
+               if repo.URI == uri {
+                       return i, nil
+               }
+       }
+       return 0, fmt.Errorf("non existing Kamelet repository uri %s", uri)
+}
diff --git a/pkg/cmd/kamelet_remove_repo_test.go 
b/pkg/cmd/kamelet_remove_repo_test.go
new file mode 100644
index 000000000..0d77840c5
--- /dev/null
+++ b/pkg/cmd/kamelet_remove_repo_test.go
@@ -0,0 +1,86 @@
+/*
+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 (
+       "testing"
+
+       "github.com/spf13/cobra"
+       "github.com/stretchr/testify/assert"
+
+       v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
+       "github.com/apache/camel-k/pkg/util/test"
+)
+
+const cmdKameletRemoveRepo = "remove-repo"
+
+// nolint: unparam
+func initializeKameletRemoveRepoCmdOptions(t *testing.T) 
(*kameletRemoveRepoCommandOptions, *cobra.Command, RootCmdOptions) {
+       t.Helper()
+
+       options, rootCmd := kamelTestPreAddCommandInit()
+       kameletRemoveRepoCommandOptions := 
addTestKameletRemoveRepoCmd(*options, rootCmd)
+       kamelTestPostAddCommandInit(t, rootCmd)
+
+       return kameletRemoveRepoCommandOptions, rootCmd, *options
+}
+
+func addTestKameletRemoveRepoCmd(options RootCmdOptions, rootCmd 
*cobra.Command) *kameletRemoveRepoCommandOptions {
+       // Add a testing version of kamelet remove-repo Command
+       kameletRemoveRepoCmd, kameletRemoveRepoOptions := 
newKameletRemoveRepoCmd(&options)
+       kameletRemoveRepoCmd.RunE = func(c *cobra.Command, args []string) error 
{
+               return nil
+       }
+       kameletRemoveRepoCmd.PostRunE = func(c *cobra.Command, args []string) 
error {
+               return nil
+       }
+       kameletRemoveRepoCmd.Args = test.ArbitraryArgs
+       rootCmd.AddCommand(kameletRemoveRepoCmd)
+       return kameletRemoveRepoOptions
+}
+
+func TestKameletRemoveRepoNoFlag(t *testing.T) {
+       _, rootCmd, _ := initializeKameletRemoveRepoCmdOptions(t)
+       _, err := test.ExecuteCommand(rootCmd, cmdKameletRemoveRepo, "foo")
+       assert.Nil(t, err)
+}
+
+func TestKameletRemoveRepoNonExistingFlag(t *testing.T) {
+       _, rootCmd, _ := initializeKameletRemoveRepoCmdOptions(t)
+       _, err := test.ExecuteCommand(rootCmd, cmdKameletRemoveRepo, 
"--nonExistingFlag", "foo")
+       assert.NotNil(t, err)
+}
+
+func TestKameletRemoveRepoURINotFoundEmpty(t *testing.T) {
+       repositories := []v1.IntegrationPlatformKameletRepositorySpec{}
+       _, err := getURIIndex("foo", repositories)
+       assert.NotNil(t, err)
+}
+
+func TestKameletRemoveRepoURINotFoundNotEmpty(t *testing.T) {
+       repositories := []v1.IntegrationPlatformKameletRepositorySpec{{URI: 
"github:foo/bar"}}
+       _, err := getURIIndex("foo", repositories)
+       assert.NotNil(t, err)
+}
+
+func TestKameletRemoveRepoURIFound(t *testing.T) {
+       repositories := []v1.IntegrationPlatformKameletRepositorySpec{{URI: 
"github:foo/bar1"}, {URI: "github:foo/bar2"}, {URI: "github:foo/bar3"}}
+       i, err := getURIIndex("github:foo/bar2", repositories)
+       assert.Nil(t, err)
+       assert.Equal(t, 1, i)
+}

Reply via email to