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

nfilotto pushed a commit to branch 3667/make-add-repo-support-global-operator
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit f0d7ff37d6267e5feb8ab8efbd361933a505e92b
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   | 29 ++++++++---
 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 ++++++++++++++++++++++++++++++++
 5 files changed, 258 insertions(+), 22 deletions(-)

diff --git a/e2e/global/common/kamelet_test.go 
b/e2e/global/common/kamelet_test.go
index e6b8834fb..d22d2fab2 100644
--- a/e2e/global/common/kamelet_test.go
+++ b/e2e/global/common/kamelet_test.go
@@ -37,9 +37,6 @@ import (
  * 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"
@@ -62,14 +59,14 @@ 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) {
-
+                       globalTest := os.Getenv("CAMEL_K_FORCE_GLOBAL_TEST") == 
"true"
+                       if globalTest {
+                               t.Skip("Not compatible with global operator 
mode")
+                       }
                        // 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())
 
@@ -77,6 +74,24 @@ func TestKameletClasspathLoading(t *testing.T) {
                        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, "-x", 
operatorID).Execute()).To(Succeed())
+               })
+
+               // Custom repo without operator ID
+               t.Run("test custom Kamelet repository without operator ID", 
func(t *testing.T) {
+
+                       // Add the custom repository
+                       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/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