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) +}