You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by nf...@apache.org on 2022/10/10 10:59:18 UTC

[camel-k] 01/01: feat(cli): Make add-repo and remove-repo compatible with a global operator

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 e080b969b5a39d99916f4cd1c5af26103cff30a8
Author: Nicolas Filotto <nf...@talend.com>
AuthorDate: Mon Oct 10 12:58:53 2022 +0200

    feat(cli): Make add-repo and remove-repo compatible with a global operator
---
 e2e/global/common/kamelet_test.go   | 34 +++++++++----
 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, 261 insertions(+), 24 deletions(-)

diff --git a/e2e/global/common/kamelet_test.go b/e2e/global/common/kamelet_test.go
index e6b8834fb..ee15e1543 100644
--- a/e2e/global/common/kamelet_test.go
+++ b/e2e/global/common/kamelet_test.go
@@ -37,13 +37,11 @@ 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"
-		Expect(KamelInstallWithID(operatorID, ns).Execute()).To(Succeed())
+		ns = "4tests"
+		operatorID := "camel-k-4test"
+		//Expect(KamelInstallWithID(operatorID, ns).Execute()).To(Succeed())
 
 		kameletName := "timer-source"
 		removeKamelet(kameletName, ns)
@@ -62,14 +60,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 +75,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..804c400ff 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.")
 
 	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..b0a97347d
--- /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.")
+
+	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)
+}