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 36439e167 fix(cli): `kamel local build` doesn't support same 
dependency notation
36439e167 is described below

commit 36439e167964489ad45e6348031d317f1b72003d
Author: Tadayoshi Sato <sato.tadayo...@gmail.com>
AuthorDate: Wed Jul 13 14:40:54 2022 +0900

    fix(cli): `kamel local build` doesn't support same dependency notation
    
    This also fixes jitpack dependencies resolution.
    Fix #2213.
---
 e2e/local/files/dependency.groovy                  |  2 +-
 e2e/local/local_build_test.go                      |  6 +-
 e2e/local/local_run_test.go                        | 25 ++++++++
 pkg/apis/camel/v1/integration_types_support.go     | 25 +++++---
 .../camel/v1/integration_types_support_test.go     |  7 +++
 pkg/cmd/local.go                                   | 48 +++++++++++++---
 pkg/cmd/local_build.go                             | 48 ++++++----------
 pkg/cmd/local_build_test.go                        | 38 ++++++++++---
 pkg/cmd/local_inspect.go                           | 35 ++++--------
 pkg/cmd/local_inspect_test.go                      | 40 ++++++++++---
 pkg/cmd/local_run.go                               | 57 +++++++------------
 pkg/cmd/local_run_test.go                          | 66 +++++++++++-----------
 pkg/cmd/{util_dependencies.go => local_util.go}    | 45 ++++++---------
 ...til_dependencies_test.go => local_util_test.go} |  0
 pkg/cmd/root.go                                    |  5 +-
 pkg/cmd/run.go                                     |  4 +-
 pkg/util/camel/camel_dependencies.go               |  9 +--
 17 files changed, 261 insertions(+), 199 deletions(-)

diff --git a/e2e/local/files/dependency.groovy 
b/e2e/local/files/dependency.groovy
index d686acb8a..b5d56df17 100644
--- a/e2e/local/files/dependency.groovy
+++ b/e2e/local/files/dependency.groovy
@@ -1,4 +1,4 @@
-// camel-k: language=groovy dependency=camel:twitter 
dependency=mvn:com.google.guava:guava:31.1-jre 
dependency=github:squakez/samplejp:v1.0
+// camel-k: language=groovy dependency=camel-twitter 
dependency=mvn:com.google.guava:guava:31.1-jre 
dependency=github:squakez/samplejp:v1.0
 
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
diff --git a/e2e/local/local_build_test.go b/e2e/local/local_build_test.go
index ab3440b4b..2ea34f91b 100644
--- a/e2e/local/local_build_test.go
+++ b/e2e/local/local_build_test.go
@@ -195,7 +195,7 @@ func TestLocalBuildDependenciesOnly(t *testing.T) {
        file := testutil.MakeTempCopy(t, "files/yaml.yaml")
        dir := testutil.MakeTempDir(t)
 
-       kamelBuild := KamelWithContext(ctx, "local", "build", file, 
"--integration-directory", dir, "--dependencies-only")
+       kamelBuild := KamelWithContext(ctx, "local", "build", file, 
"--integration-directory", dir, "--dependencies-only", "-d", "camel-amqp")
 
        go func() {
                err := kamelBuild.Execute()
@@ -206,6 +206,7 @@ func TestLocalBuildDependenciesOnly(t *testing.T) {
        Eventually(dir+"/dependencies", TestTimeoutShort).Should(BeADirectory())
        Eventually(dependency(dir, "org.apache.camel.camel-timer-%s.jar", 
camelVersion), TestTimeoutShort).Should(BeAnExistingFile())
        Eventually(dependency(dir, "org.apache.camel.camel-log-%s.jar", 
camelVersion), TestTimeoutShort).Should(BeAnExistingFile())
+       Eventually(dependency(dir, "org.apache.camel.camel-amqp-%s.jar", 
camelVersion), TestTimeoutShort).Should(BeAnExistingFile())
        Expect(dir + "/properties").ShouldNot(BeADirectory())
        Expect(dir + "/routes/yaml.yaml").ShouldNot(BeAnExistingFile())
 }
@@ -219,7 +220,7 @@ func TestLocalBuildModelineDependencies(t *testing.T) {
        file := testutil.MakeTempCopy(t, "files/dependency.groovy")
        dir := testutil.MakeTempDir(t)
 
-       kamelBuild := KamelWithContext(ctx, "local", "build", file, 
"--integration-directory", dir)
+       kamelBuild := KamelWithContext(ctx, "local", "build", file, 
"--integration-directory", dir, "-d", "camel-amqp")
 
        go func() {
                err := kamelBuild.Execute()
@@ -229,6 +230,7 @@ func TestLocalBuildModelineDependencies(t *testing.T) {
        Eventually(dir+"/dependencies", TestTimeoutShort).Should(BeADirectory())
        Eventually(dependency(dir, "org.apache.camel.camel-timer-%s.jar", 
camelVersion), TestTimeoutShort).Should(BeAnExistingFile())
        Eventually(dependency(dir, "org.apache.camel.camel-log-%s.jar", 
camelVersion), TestTimeoutShort).Should(BeAnExistingFile())
+       Eventually(dependency(dir, "org.apache.camel.camel-amqp-%s.jar", 
camelVersion), TestTimeoutShort).Should(BeAnExistingFile())
        // camel dependency
        Eventually(dependency(dir, "org.apache.camel.camel-twitter-%s.jar", 
camelVersion), TestTimeoutMedium).Should(BeAnExistingFile())
        // mvn dependency
diff --git a/e2e/local/local_run_test.go b/e2e/local/local_run_test.go
index e016b0119..c703e3825 100644
--- a/e2e/local/local_run_test.go
+++ b/e2e/local/local_run_test.go
@@ -60,6 +60,31 @@ func TestLocalRun(t *testing.T) {
        Eventually(logScanner.IsFound("Magicstring!"), 
TestTimeoutMedium).Should(BeTrue())
 }
 
+func TestLocalRunWithDependencies(t *testing.T) {
+       RegisterTestingT(t)
+
+       ctx, cancel := context.WithCancel(TestContext)
+       defer cancel()
+       piper, pipew := io.Pipe()
+       defer pipew.Close()
+       defer piper.Close()
+
+       file := testutil.MakeTempCopy(t, "files/dependency.groovy")
+
+       kamelRun := KamelWithContext(ctx, "local", "run", file, "-d", 
"camel-amqp")
+       kamelRun.SetOut(pipew)
+
+       logScanner := testutil.NewLogScanner(ctx, piper, "Magicstring!")
+
+       go func() {
+               err := kamelRun.Execute()
+               assert.NoError(t, err)
+               cancel()
+       }()
+
+       Eventually(logScanner.IsFound("Magicstring!"), 
TestTimeoutMedium).Should(BeTrue())
+}
+
 func TestLocalRunContainerize(t *testing.T) {
        RegisterTestingT(t)
 
diff --git a/pkg/apis/camel/v1/integration_types_support.go 
b/pkg/apis/camel/v1/integration_types_support.go
index 5b6fd9130..50316a081 100644
--- a/pkg/apis/camel/v1/integration_types_support.go
+++ b/pkg/apis/camel/v1/integration_types_support.go
@@ -105,14 +105,7 @@ func (in *IntegrationSpec) AddDependency(dependency 
string) {
        if in.Dependencies == nil {
                in.Dependencies = make([]string, 0)
        }
-       newDep := dependency
-       if strings.HasPrefix(newDep, "camel-quarkus-") {
-               newDep = "camel:" + strings.TrimPrefix(dependency, 
"camel-quarkus-")
-       } else if strings.HasPrefix(newDep, "camel-quarkus:") {
-               newDep = "camel:" + strings.TrimPrefix(dependency, 
"camel-quarkus:")
-       } else if strings.HasPrefix(newDep, "camel-") {
-               newDep = "camel:" + strings.TrimPrefix(dependency, "camel-")
-       }
+       newDep := NormalizeDependency(dependency)
        for _, d := range in.Dependencies {
                if d == newDep {
                        return
@@ -121,6 +114,22 @@ func (in *IntegrationSpec) AddDependency(dependency 
string) {
        in.Dependencies = append(in.Dependencies, newDep)
 }
 
+// NormalizeDependency converts different forms of camel dependencies
+// -- `camel-xxx`, `camel-quarkus-xxx`, and `camel-quarkus:xxx` --
+// into the unified form `camel:xxx`.
+func NormalizeDependency(dependency string) string {
+       newDep := dependency
+       switch {
+       case strings.HasPrefix(newDep, "camel-quarkus-"):
+               newDep = "camel:" + strings.TrimPrefix(dependency, 
"camel-quarkus-")
+       case strings.HasPrefix(newDep, "camel-quarkus:"):
+               newDep = "camel:" + strings.TrimPrefix(dependency, 
"camel-quarkus:")
+       case strings.HasPrefix(newDep, "camel-"):
+               newDep = "camel:" + strings.TrimPrefix(dependency, "camel-")
+       }
+       return newDep
+}
+
 // GetConfigurationProperty returns a configuration property
 func (in *IntegrationSpec) GetConfigurationProperty(property string) string {
        for _, confSpec := range in.Configuration {
diff --git a/pkg/apis/camel/v1/integration_types_support_test.go 
b/pkg/apis/camel/v1/integration_types_support_test.go
index 6f4d4827c..7a5e81d86 100644
--- a/pkg/apis/camel/v1/integration_types_support_test.go
+++ b/pkg/apis/camel/v1/integration_types_support_test.go
@@ -74,6 +74,13 @@ func TestAddDependency(t *testing.T) {
        assert.Equal(t, integration.Dependencies, []string{"file:dep"})
 }
 
+func TestNormalizeDependency(t *testing.T) {
+       assert.Equal(t, "camel:file", NormalizeDependency("camel-file"))
+       assert.Equal(t, "camel:file", NormalizeDependency("camel:file"))
+       assert.Equal(t, "camel:file", NormalizeDependency("camel-quarkus-file"))
+       assert.Equal(t, "camel:file", NormalizeDependency("camel-quarkus:file"))
+}
+
 func TestGetConfigurationProperty(t *testing.T) {
        integration := IntegrationSpec{}
        integration.AddConfiguration("property", "key1=value1")
diff --git a/pkg/cmd/local.go b/pkg/cmd/local.go
index cac6e51d5..1a480490f 100644
--- a/pkg/cmd/local.go
+++ b/pkg/cmd/local.go
@@ -20,25 +20,57 @@ package cmd
 import (
        "fmt"
 
+       v1 "github.com/apache/camel-k/pkg/apis/camel/v1"
        "github.com/spf13/cobra"
 )
 
 // newCmdLocal -- Add local kamel subcommand with several other subcommands of 
its own.
-func newCmdLocal(rootCmdOptions *RootCmdOptions) *cobra.Command {
+func newCmdLocal(rootCmdOptions *RootCmdOptions) (*cobra.Command, 
*LocalCmdOptions) {
+       options := LocalCmdOptions{
+               RootCmdOptions: rootCmdOptions,
+       }
+
        cmd := cobra.Command{
-               Use:   "local [sub-command]",
-               Short: "Perform integration actions locally.",
-               Long:  `Perform integration actions locally given a set of 
input integration files.`,
+               Use:               "local [sub-command]",
+               Short:             "Perform integration actions locally.",
+               Long:              `Perform integration actions locally given a 
set of input integration files.`,
+               PersistentPreRunE: options.persistentPreRun,
                Annotations: map[string]string{
                        offlineCommandLabel: "true",
                },
        }
 
-       cmd.AddCommand(cmdOnly(newCmdLocalBuild(rootCmdOptions)))
-       cmd.AddCommand(cmdOnly(newCmdLocalInspect(rootCmdOptions)))
-       cmd.AddCommand(cmdOnly(newCmdLocalRun(rootCmdOptions)))
+       cmd.PersistentFlags().StringArrayVarP(&options.Dependencies, 
"dependency", "d", nil, usageDependency)
+
+       // hidden flags for compatibility with kamel run
+       cmd.PersistentFlags().StringArrayVarP(&options.Traits, "trait", "t", 
nil, "")
+       if err := cmd.PersistentFlags().MarkHidden("trait"); err != nil {
+               fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
+       }
+
+       cmd.AddCommand(cmdOnly(newCmdLocalBuild(&options)))
+       cmd.AddCommand(cmdOnly(newCmdLocalInspect(&options)))
+       cmd.AddCommand(cmdOnly(newCmdLocalRun(&options)))
+
+       return &cmd, &options
+}
+
+type LocalCmdOptions struct {
+       *RootCmdOptions
+       Dependencies []string `mapstructure:"dependencies"`
+       Traits       []string `mapstructure:"traits"`
+}
+
+func (o *LocalCmdOptions) persistentPreRun(cmd *cobra.Command, args []string) 
error {
+       // pre-process dependencies
+       for i, dependency := range o.Dependencies {
+               o.Dependencies[i] = v1.NormalizeDependency(dependency)
+       }
+
+       // validate traits
+       warnTraitUsages(cmd, o.Traits)
 
-       return &cmd
+       return nil
 }
 
 func warnTraitUsages(cmd *cobra.Command, traits []string) {
diff --git a/pkg/cmd/local_build.go b/pkg/cmd/local_build.go
index 222c510de..5c0d72cd4 100644
--- a/pkg/cmd/local_build.go
+++ b/pkg/cmd/local_build.go
@@ -26,9 +26,9 @@ import (
        "github.com/apache/camel-k/pkg/util"
 )
 
-func newCmdLocalBuild(rootCmdOptions *RootCmdOptions) (*cobra.Command, 
*localBuildCmdOptions) {
+func newCmdLocalBuild(localCmdOptions *LocalCmdOptions) (*cobra.Command, 
*localBuildCmdOptions) {
        options := localBuildCmdOptions{
-               RootCmdOptions: rootCmdOptions,
+               LocalCmdOptions: localCmdOptions,
        }
 
        cmd := cobra.Command{
@@ -37,7 +37,7 @@ func newCmdLocalBuild(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *localBui
                Long:    `Build integration images locally for containerized 
integrations.`,
                PreRunE: decode(&options),
                RunE: func(cmd *cobra.Command, args []string) error {
-                       if err := options.validate(cmd, args); err != nil {
+                       if err := options.validate(args); err != nil {
                                return err
                        }
                        if err := options.init(args); err != nil {
@@ -64,50 +64,38 @@ func newCmdLocalBuild(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *localBui
        cmd.Flags().String("integration-directory", "", "Directory to hold 
local integration files.")
        cmd.Flags().StringArray("property-file", nil, "Add a property file to 
the integration.")
        cmd.Flags().StringArrayP("property", "p", nil, "Add a Camel property to 
the integration.")
-       cmd.Flags().StringArrayP("dependency", "d", nil, "Add an additional 
dependency")
        cmd.Flags().StringArray("maven-repository", nil, "Use a maven 
repository")
 
-       // hidden flags for compatibility with kamel run
-       cmd.Flags().StringArrayP("trait", "t", nil, "")
-       if err := cmd.Flags().MarkHidden("trait"); err != nil {
-               fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
-       }
-
        return &cmd, &options
 }
 
 type localBuildCmdOptions struct {
-       *RootCmdOptions
-       BaseImage              bool     `mapstructure:"base-image"`
-       DependenciesOnly       bool     `mapstructure:"dependencies-only"`
-       ContainerRegistry      string   `mapstructure:"container-registry"`
-       Image                  string   `mapstructure:"image"`
-       IntegrationDirectory   string   `mapstructure:"integration-directory"`
-       AdditionalDependencies []string `mapstructure:"dependencies"`
-       Properties             []string `mapstructure:"properties"`
-       PropertyFiles          []string `mapstructure:"property-files"`
-       MavenRepositories      []string `mapstructure:"maven-repositories"`
-       Traits                 []string `mapstructure:"traits"`
+       *LocalCmdOptions
+       BaseImage            bool     `mapstructure:"base-image"`
+       DependenciesOnly     bool     `mapstructure:"dependencies-only"`
+       ContainerRegistry    string   `mapstructure:"container-registry"`
+       Image                string   `mapstructure:"image"`
+       IntegrationDirectory string   `mapstructure:"integration-directory"`
+       Properties           []string `mapstructure:"properties"`
+       PropertyFiles        []string `mapstructure:"property-files"`
+       MavenRepositories    []string `mapstructure:"maven-repositories"`
 }
 
-func (command *localBuildCmdOptions) validate(cmd *cobra.Command, args 
[]string) error {
+func (command *localBuildCmdOptions) validate(args []string) error {
        // Validate integration files.
        if len(args) > 0 {
-               err := validateIntegrationFiles(args)
-               if err != nil {
+               if err := validateIntegrationFiles(args); err != nil {
                        return err
                }
        }
 
        // Validate additional dependencies specified by the user.
-       err := validateAdditionalDependencies(command.AdditionalDependencies)
-       if err != nil {
+       if err := validateDependencies(command.Dependencies); err != nil {
                return err
        }
 
        // Validate properties file.
-       err = validateFiles(command.PropertyFiles)
-       if err != nil {
+       if err := validateFiles(command.PropertyFiles); err != nil {
                return err
        }
 
@@ -136,8 +124,6 @@ func (command *localBuildCmdOptions) validate(cmd 
*cobra.Command, args []string)
                return errors.New("to output dependencies the integration 
directory flag must be set")
        }
 
-       warnTraitUsages(cmd, command.Traits)
-
        return nil
 }
 
@@ -176,7 +162,7 @@ func (command *localBuildCmdOptions) run(cmd 
*cobra.Command, args []string) erro
        var dependenciesList, propertyFilesList []string
        routeFiles := args
        if !command.BaseImage {
-               dependencies, err := getDependencies(command.Context, args, 
command.AdditionalDependencies, command.MavenRepositories, true)
+               dependencies, err := GetDependencies(command.Context, args, 
command.Dependencies, command.MavenRepositories, true)
                if err != nil {
                        return err
                }
diff --git a/pkg/cmd/local_build_test.go b/pkg/cmd/local_build_test.go
index 8519bd1a4..5c9db5ff2 100644
--- a/pkg/cmd/local_build_test.go
+++ b/pkg/cmd/local_build_test.go
@@ -22,28 +22,52 @@ import (
 
        "github.com/apache/camel-k/pkg/util/test"
        "github.com/spf13/cobra"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
 )
 
 func addTestLocalBuildCmd(rootCmdOptions *RootCmdOptions, rootCmd 
*cobra.Command) *localBuildCmdOptions {
+       localCmd, localCmdOptions := newCmdLocal(rootCmdOptions)
+       // remove predefined sub commands
+       localCmd.RemoveCommand(localCmd.Commands()...)
        // add a testing version of build Command
-       localBuildCmd, localBuildCmdOptions := newCmdLocalBuild(rootCmdOptions)
+       localBuildCmd, localBuildCmdOptions := newCmdLocalBuild(localCmdOptions)
        localBuildCmd.RunE = func(c *cobra.Command, args []string) error {
                return nil
        }
        localBuildCmd.Args = test.ArbitraryArgs
-       rootCmd.AddCommand(localBuildCmd)
+       localCmd.AddCommand(localBuildCmd)
+       rootCmd.AddCommand(localCmd)
        return localBuildCmdOptions
 }
 
 func TestLocalBuildAcceptsTraits(t *testing.T) {
        options, rootCmd := kamelTestPreAddCommandInit()
-
        addTestLocalBuildCmd(options, rootCmd)
+       kamelTestPostAddCommandInit(t, rootCmd)
+
+       _, err := test.ExecuteCommand(rootCmd, "local", "build", "route.java",
+               "-t", "jolokia.enabled=true",
+               "--trait", "prometheus.enabled=true")
+
+       require.NoError(t, err)
+}
 
+func TestLocalBuildWithDependencies(t *testing.T) {
+       options, rootCmd := kamelTestPreAddCommandInit()
+       localBuildCmdOptions := addTestLocalBuildCmd(options, rootCmd)
        kamelTestPostAddCommandInit(t, rootCmd)
 
-       _, err := test.ExecuteCommand(rootCmd, "build", "route.java", "-t", 
"jolokia.enabled=true", "--trait", "prometheus.enabled=true")
-       if err != nil {
-               t.Fatalf("Unexpected error: %v", err)
-       }
+       _, err := test.ExecuteCommand(rootCmd, "local", "build", "route.java",
+               "-d", "camel-amqp",
+               "-d", "camel:bean",
+               "-d", "camel-quarkus-controlbus",
+               "-d", "camel-quarkus:directvm",
+               "--dependency", "mvn:test:component:1.0.0")
+
+       require.NoError(t, err)
+       assert.Len(t, localBuildCmdOptions.Dependencies, 5)
+       assert.ElementsMatch(t, localBuildCmdOptions.Dependencies, []string{
+               "camel:amqp", "camel:bean", "camel:controlbus", 
"camel:directvm", "mvn:test:component:1.0.0",
+       })
 }
diff --git a/pkg/cmd/local_inspect.go b/pkg/cmd/local_inspect.go
index e4e6c95cf..54fca9862 100644
--- a/pkg/cmd/local_inspect.go
+++ b/pkg/cmd/local_inspect.go
@@ -23,9 +23,9 @@ import (
        "github.com/spf13/cobra"
 )
 
-func newCmdLocalInspect(rootCmdOptions *RootCmdOptions) (*cobra.Command, 
*localInspectCmdOptions) {
+func newCmdLocalInspect(localCmdOptions *LocalCmdOptions) (*cobra.Command, 
*localInspectCmdOptions) {
        options := localInspectCmdOptions{
-               RootCmdOptions: rootCmdOptions,
+               LocalCmdOptions: localCmdOptions,
        }
 
        cmd := cobra.Command{
@@ -36,7 +36,7 @@ top level dependencies only. When --all-dependencies is 
enabled, the transitive
 will be generated by calling Maven and then printed in the selected output 
format.`,
                PreRunE: decode(&options),
                RunE: func(cmd *cobra.Command, args []string) error {
-                       if err := options.validate(cmd, args); err != nil {
+                       if err := options.validate(args); err != nil {
                                return err
                        }
                        if err := options.init(); err != nil {
@@ -57,41 +57,28 @@ will be generated by calling Maven and then printed in the 
selected output forma
        }
 
        cmd.Flags().Bool("all-dependencies", false, "Enable computation of 
transitive dependencies.")
-       cmd.Flags().StringArrayP("dependency", "d", nil, 
additionalDependencyUsageMessage)
        cmd.Flags().StringP("output", "o", "", "Output format. One of: 
json|yaml")
        cmd.Flags().StringArray("maven-repository", nil, "Use a maven 
repository")
 
-       // hidden flags for compatibility with kamel run
-       cmd.Flags().StringArrayP("trait", "t", nil, "")
-       if err := cmd.Flags().MarkHidden("trait"); err != nil {
-               fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
-       }
-
        return &cmd, &options
 }
 
 type localInspectCmdOptions struct {
-       *RootCmdOptions
-       AllDependencies        bool     `mapstructure:"all-dependencies"`
-       OutputFormat           string   `mapstructure:"output"`
-       AdditionalDependencies []string `mapstructure:"dependencies"`
-       MavenRepositories      []string `mapstructure:"maven-repositories"`
-       Traits                 []string `mapstructure:"traits"`
+       *LocalCmdOptions
+       AllDependencies   bool     `mapstructure:"all-dependencies"`
+       OutputFormat      string   `mapstructure:"output"`
+       MavenRepositories []string `mapstructure:"maven-repositories"`
 }
 
-func (command *localInspectCmdOptions) validate(cmd *cobra.Command, args 
[]string) error {
-       err := validateIntegrationFiles(args)
-       if err != nil {
+func (command *localInspectCmdOptions) validate(args []string) error {
+       if err := validateIntegrationFiles(args); err != nil {
                return err
        }
 
-       err = validateAdditionalDependencies(command.AdditionalDependencies)
-       if err != nil {
+       if err := validateDependencies(command.Dependencies); err != nil {
                return err
        }
 
-       warnTraitUsages(cmd, command.Traits)
-
        return nil
 }
 
@@ -100,7 +87,7 @@ func (command *localInspectCmdOptions) init() error {
 }
 
 func (command *localInspectCmdOptions) run(cmd *cobra.Command, args []string) 
error {
-       dependencies, err := getDependencies(command.Context, args, 
command.AdditionalDependencies, command.MavenRepositories, 
command.AllDependencies)
+       dependencies, err := GetDependencies(command.Context, args, 
command.Dependencies, command.MavenRepositories, command.AllDependencies)
        if err != nil {
                return err
        }
diff --git a/pkg/cmd/local_inspect_test.go b/pkg/cmd/local_inspect_test.go
index 993ea88b9..92fad62be 100644
--- a/pkg/cmd/local_inspect_test.go
+++ b/pkg/cmd/local_inspect_test.go
@@ -22,28 +22,52 @@ import (
 
        "github.com/apache/camel-k/pkg/util/test"
        "github.com/spf13/cobra"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
 )
 
 func addTestLocalInspectCmd(rootCmdOptions *RootCmdOptions, rootCmd 
*cobra.Command) *localInspectCmdOptions {
+       localCmd, localCmdOptions := newCmdLocal(rootCmdOptions)
+       // remove predefined sub commands
+       localCmd.RemoveCommand(localCmd.Commands()...)
        // add a testing version of inspect Command
-       localInspectCmd, localInspectCmdOptions := 
newCmdLocalInspect(rootCmdOptions)
+       localInspectCmd, localInspectCmdOptions := 
newCmdLocalInspect(localCmdOptions)
        localInspectCmd.RunE = func(c *cobra.Command, args []string) error {
                return nil
        }
        localInspectCmd.Args = test.ArbitraryArgs
-       rootCmd.AddCommand(localInspectCmd)
+       localCmd.AddCommand(localInspectCmd)
+       rootCmd.AddCommand(localCmd)
        return localInspectCmdOptions
 }
 
 func TestLocalInspectAcceptsTraits(t *testing.T) {
-       options, rootCmd := kamelTestPreAddCommandInit()
+       rootOptions, rootCmd := kamelTestPreAddCommandInit()
+       addTestLocalInspectCmd(rootOptions, rootCmd)
+       kamelTestPostAddCommandInit(t, rootCmd)
+
+       _, err := test.ExecuteCommand(rootCmd, "local", "inspect", "route.java",
+               "-t", "jolokia.enabled=true",
+               "--trait", "prometheus.enabled=true")
 
-       addTestLocalInspectCmd(options, rootCmd)
+       require.NoError(t, err)
+}
 
+func TestLocalInspectWithDependencies(t *testing.T) {
+       rootOptions, rootCmd := kamelTestPreAddCommandInit()
+       options := addTestLocalInspectCmd(rootOptions, rootCmd)
        kamelTestPostAddCommandInit(t, rootCmd)
 
-       _, err := test.ExecuteCommand(rootCmd, "inspect", "route.java", "-t", 
"jolokia.enabled=true", "--trait", "prometheus.enabled=true")
-       if err != nil {
-               t.Fatalf("Unexpected error: %v", err)
-       }
+       _, err := test.ExecuteCommand(rootCmd, "local", "inspect", "route.java",
+               "-d", "camel-amqp",
+               "-d", "camel:bean",
+               "-d", "camel-quarkus-controlbus",
+               "-d", "camel-quarkus:directvm",
+               "--dependency", "mvn:test:component:1.0.0")
+
+       require.NoError(t, err)
+       assert.Len(t, options.Dependencies, 5)
+       assert.ElementsMatch(t, options.Dependencies, []string{
+               "camel:amqp", "camel:bean", "camel:controlbus", 
"camel:directvm", "mvn:test:component:1.0.0",
+       })
 }
diff --git a/pkg/cmd/local_run.go b/pkg/cmd/local_run.go
index 1e347608c..ec021ed0d 100644
--- a/pkg/cmd/local_run.go
+++ b/pkg/cmd/local_run.go
@@ -29,9 +29,9 @@ import (
        "github.com/apache/camel-k/pkg/util"
 )
 
-func newCmdLocalRun(rootCmdOptions *RootCmdOptions) (*cobra.Command, 
*localRunCmdOptions) {
+func newCmdLocalRun(localCmdOptions *LocalCmdOptions) (*cobra.Command, 
*localRunCmdOptions) {
        options := localRunCmdOptions{
-               RootCmdOptions: rootCmdOptions,
+               LocalCmdOptions: localCmdOptions,
        }
 
        cmd := cobra.Command{
@@ -40,7 +40,7 @@ func newCmdLocalRun(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *localRunCm
                Long:    `Run integration locally using the input integration 
files.`,
                PreRunE: decode(&options),
                RunE: func(cmd *cobra.Command, args []string) error {
-                       if err := options.validate(cmd, args); err != nil {
+                       if err := options.validate(args); err != nil {
                                return err
                        }
                        if err := options.init(); err != nil {
@@ -80,51 +80,39 @@ func newCmdLocalRun(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *localRunCm
        cmd.Flags().StringArrayP("env", "e", nil, "Flag to specify an 
environment variable [--env VARIABLE=value].")
        cmd.Flags().StringArray("property-file", nil, "Add a property file to 
the integration.")
        cmd.Flags().StringArrayP("property", "p", nil, "Add a Camel property to 
the integration.")
-       cmd.Flags().StringArrayP("dependency", "d", nil, 
additionalDependencyUsageMessage)
        cmd.Flags().StringArray("maven-repository", nil, "Use a maven 
repository")
 
-       // hidden flags for compatibility with kamel run
-       cmd.Flags().StringArrayP("trait", "t", nil, "")
-       if err := cmd.Flags().MarkHidden("trait"); err != nil {
-               fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
-       }
-
        return &cmd, &options
 }
 
 type localRunCmdOptions struct {
-       *RootCmdOptions
-       Containerize           bool     `mapstructure:"containerize"`
-       Image                  string   `mapstructure:"image"`
-       Network                string   `mapstructure:"network"`
-       IntegrationDirectory   string   `mapstructure:"integration-directory"`
-       EnvironmentVariables   []string `mapstructure:"envs"`
-       PropertyFiles          []string `mapstructure:"property-files"`
-       Properties             []string `mapstructure:"properties"`
-       AdditionalDependencies []string `mapstructure:"dependencies"`
-       MavenRepositories      []string `mapstructure:"maven-repositories"`
-       Traits                 []string `mapstructure:"traits"`
+       *LocalCmdOptions
+       Containerize         bool     `mapstructure:"containerize"`
+       Image                string   `mapstructure:"image"`
+       Network              string   `mapstructure:"network"`
+       IntegrationDirectory string   `mapstructure:"integration-directory"`
+       EnvironmentVariables []string `mapstructure:"envs"`
+       PropertyFiles        []string `mapstructure:"property-files"`
+       Properties           []string `mapstructure:"properties"`
+       MavenRepositories    []string `mapstructure:"maven-repositories"`
 }
 
-func (command *localRunCmdOptions) validate(cmd *cobra.Command, args []string) 
error {
+func (command *localRunCmdOptions) validate(args []string) error {
        // Validate integration files when no image is provided and we are
        // not running an already locally-built integration.
        if command.Image == "" && command.IntegrationDirectory == "" {
-               err := validateIntegrationFiles(args)
-               if err != nil {
+               if err := validateIntegrationFiles(args); err != nil {
                        return err
                }
        }
 
        // Validate additional dependencies specified by the user.
-       err := validateAdditionalDependencies(command.AdditionalDependencies)
-       if err != nil {
+       if err := validateDependencies(command.Dependencies); err != nil {
                return err
        }
 
        // Validate properties file.
-       err = validatePropertyFiles(command.PropertyFiles)
-       if err != nil {
+       if err := validatePropertyFiles(command.PropertyFiles); err != nil {
                return err
        }
 
@@ -133,20 +121,16 @@ func (command *localRunCmdOptions) validate(cmd 
*cobra.Command, args []string) e
                return errors.New("containerization is active but no image name 
has been provided")
        }
 
-       warnTraitUsages(cmd, command.Traits)
-
        return nil
 }
 
 func (command *localRunCmdOptions) init() error {
        if command.Containerize {
-               err := createDockerBaseWorkingDirectory()
-               if err != nil {
+               if err := createDockerBaseWorkingDirectory(); err != nil {
                        return err
                }
 
-               err = createDockerWorkingDirectory()
-               if err != nil {
+               if err := createDockerWorkingDirectory(); err != nil {
                        return err
                }
        }
@@ -162,8 +146,7 @@ func (command *localRunCmdOptions) run(cmd *cobra.Command, 
args []string) error
        // If local run is provided with an image name, it will just run the 
image locally and exit.
        if command.Image != "" && !command.Containerize {
                // Run image locally.
-               err := runIntegrationImage(command.Context, command.Image, 
cmd.OutOrStdout(), cmd.ErrOrStderr())
-               if err != nil {
+               if err := runIntegrationImage(command.Context, command.Image, 
cmd.OutOrStdout(), cmd.ErrOrStderr()); err != nil {
                        return err
                }
 
@@ -209,7 +192,7 @@ func (command *localRunCmdOptions) run(cmd *cobra.Command, 
args []string) error
                        return err
                }
        } else {
-               computedDependencies, err := getDependencies(command.Context, 
args, command.AdditionalDependencies, command.MavenRepositories, true)
+               computedDependencies, err := GetDependencies(command.Context, 
args, command.Dependencies, command.MavenRepositories, true)
                if err != nil {
                        return err
                }
diff --git a/pkg/cmd/local_run_test.go b/pkg/cmd/local_run_test.go
index 1e4c08093..d6bdab05e 100644
--- a/pkg/cmd/local_run_test.go
+++ b/pkg/cmd/local_run_test.go
@@ -22,31 +22,35 @@ import (
 
        "github.com/apache/camel-k/pkg/util/test"
        "github.com/spf13/cobra"
+       "github.com/stretchr/testify/assert"
+       "github.com/stretchr/testify/require"
 )
 
 func addTestLocalRunCmd(rootCmdOptions *RootCmdOptions, rootCmd 
*cobra.Command) *localRunCmdOptions {
+       localCmd, localCmdOptions := newCmdLocal(rootCmdOptions)
+       // remove predefined sub commands
+       localCmd.RemoveCommand(localCmd.Commands()...)
        // add a testing version of run Command
-       localRunCmd, localRunCmdOptions := newCmdLocalRun(rootCmdOptions)
+       localRunCmd, localRunCmdOptions := newCmdLocalRun(localCmdOptions)
        localRunCmd.RunE = func(c *cobra.Command, args []string) error {
                return nil
        }
        localRunCmd.Args = test.ArbitraryArgs
-       rootCmd.AddCommand(localRunCmd)
+       localCmd.AddCommand(localRunCmd)
+       rootCmd.AddCommand(localCmd)
        return localRunCmdOptions
 }
 
 func TestLocalRunPropertyFileFlag(t *testing.T) {
        options, rootCmd := kamelTestPreAddCommandInit()
-
        localRunCmdOptions := addTestLocalRunCmd(options, rootCmd)
-
        kamelTestPostAddCommandInit(t, rootCmd)
 
-       _, err := test.ExecuteCommand(rootCmd, "run", "route.java", 
"--property-file", "file1.properties", "--property-file", "file2.properties")
-       if err != nil {
-               t.Fatalf("Unexpected error: %v", err)
-       }
+       _, err := test.ExecuteCommand(rootCmd, "local", "run", "route.java",
+               "--property-file", "file1.properties",
+               "--property-file", "file2.properties")
 
+       require.NoError(t, err)
        if len(localRunCmdOptions.PropertyFiles) != 2 {
                t.Fatalf("Property files expected to contain: \n %v 
elements\nGot:\n %v elements\n", 2, len(localRunCmdOptions.PropertyFiles))
        }
@@ -57,16 +61,14 @@ func TestLocalRunPropertyFileFlag(t *testing.T) {
 
 func TestLocalRunPropertiesFlag(t *testing.T) {
        options, rootCmd := kamelTestPreAddCommandInit()
-
        localRunCmdOptions := addTestLocalRunCmd(options, rootCmd)
-
        kamelTestPostAddCommandInit(t, rootCmd)
 
-       _, err := test.ExecuteCommand(rootCmd, "run", "route.java", "-p", 
"prop1=value1", "-p", "prop2=value2")
-       if err != nil {
-               t.Fatalf("Unexpected error: %v", err)
-       }
+       _, err := test.ExecuteCommand(rootCmd, "local", "run", "route.java",
+               "-p", "prop1=value1",
+               "-p", "prop2=value2")
 
+       require.NoError(t, err)
        if len(localRunCmdOptions.Properties) != 2 {
                t.Fatalf("Additional dependencies expected to contain: \n %v 
elements\nGot:\n %v elements\n", 2, len(localRunCmdOptions.Properties))
        }
@@ -77,33 +79,31 @@ func TestLocalRunPropertiesFlag(t *testing.T) {
 
 func TestLocalRunAdditionalDependenciesFlag(t *testing.T) {
        options, rootCmd := kamelTestPreAddCommandInit()
-
        localRunCmdOptions := addTestLocalRunCmd(options, rootCmd)
-
        kamelTestPostAddCommandInit(t, rootCmd)
 
-       _, err := test.ExecuteCommand(rootCmd, "run", "route.java", "-d", 
"mvn:camel-component-1", "-d", "mvn:camel-component-2")
-       if err != nil {
-               t.Fatalf("Unexpected error: %v", err)
-       }
-
-       if len(localRunCmdOptions.AdditionalDependencies) != 2 {
-               t.Fatalf("Additional dependencies expected to contain: \n %v 
elements\nGot:\n %v elements\n", 2, 
len(localRunCmdOptions.AdditionalDependencies))
-       }
-       if localRunCmdOptions.AdditionalDependencies[0] != 
"mvn:camel-component-1" || localRunCmdOptions.AdditionalDependencies[1] != 
"mvn:camel-component-2" {
-               t.Fatalf("Additional dependencies expected to be: \n %v\nGot:\n 
%v\n", "[mvn:camel-component-1, mvn:camel-component-2]", 
localRunCmdOptions.AdditionalDependencies)
-       }
+       _, err := test.ExecuteCommand(rootCmd, "local", "run", "route.java",
+               "-d", "camel-amqp",
+               "-d", "camel:bean",
+               "-d", "camel-quarkus-controlbus",
+               "-d", "camel-quarkus:directvm",
+               "--dependency", "mvn:test:component:1.0.0")
+
+       require.NoError(t, err)
+       assert.Len(t, localRunCmdOptions.Dependencies, 5)
+       assert.ElementsMatch(t, localRunCmdOptions.Dependencies, []string{
+               "camel:amqp", "camel:bean", "camel:controlbus", 
"camel:directvm", "mvn:test:component:1.0.0",
+       })
 }
 
 func TestLocalRunAcceptsTraits(t *testing.T) {
        options, rootCmd := kamelTestPreAddCommandInit()
-
        addTestLocalRunCmd(options, rootCmd)
-
        kamelTestPostAddCommandInit(t, rootCmd)
 
-       _, err := test.ExecuteCommand(rootCmd, "run", "route.java", "-t", 
"jolokia.enabled=true", "--trait", "prometheus.enabled=true")
-       if err != nil {
-               t.Fatalf("Unexpected error: %v", err)
-       }
+       _, err := test.ExecuteCommand(rootCmd, "local", "run", "route.java",
+               "-t", "jolokia.enabled=true",
+               "--trait", "prometheus.enabled=true")
+
+       require.NoError(t, err)
 }
diff --git a/pkg/cmd/util_dependencies.go b/pkg/cmd/local_util.go
similarity index 91%
rename from pkg/cmd/util_dependencies.go
rename to pkg/cmd/local_util.go
index e8f609d3f..c9b04feda 100644
--- a/pkg/cmd/util_dependencies.go
+++ b/pkg/cmd/local_util.go
@@ -38,13 +38,14 @@ import (
        "github.com/apache/camel-k/pkg/util/maven"
 )
 
-var acceptedDependencyTypes = []string{"bom", "camel", "camel-k", 
"camel-quarkus", "mvn", "github"}
-
-var additionalDependencyUsageMessage = `Additional top-level dependencies are 
specified with the format:
-<type>:<dependency-name>
-where <type> is one of {` + strings.Join(acceptedDependencyTypes, "|") + `}.`
+var acceptedDependencyTypes = []string{
+       "bom", "camel", "camel-k", "camel-quarkus", "mvn",
+       // jitpack
+       "github", "gitlab", "bitbucket", "gitee", "azure",
+}
 
-func getDependencies(ctx context.Context, args []string, 
additionalDependencies []string, repositories []string, allDependencies bool) 
([]string, error) {
+// GetDependencies resolves and gets the list of dependencies from catalog and 
sources.
+func GetDependencies(ctx context.Context, args []string, 
additionalDependencies []string, repositories []string, allDependencies bool) 
([]string, error) {
        // Fetch existing catalog or create new one if one does not already 
exist
        catalog, err := createCamelCatalog(ctx)
        if err != nil {
@@ -109,8 +110,7 @@ func getTransitiveDependencies(ctx context.Context, catalog 
*camel.RuntimeCatalo
                catalog.CamelCatalogSpec.Runtime.Metadata["quarkus.version"],
        )
 
-       err := camel.ManageIntegrationDependencies(&project, dependencies, 
catalog)
-       if err != nil {
+       if err := camel.ManageIntegrationDependencies(&project, dependencies, 
catalog); err != nil {
                return nil, err
        }
 
@@ -132,8 +132,7 @@ func getTransitiveDependencies(ctx context.Context, catalog 
*camel.RuntimeCatalo
        // Make maven command less verbose
        mc.AdditionalArguments = append(mc.AdditionalArguments, "-q")
 
-       err = builder.BuildQuarkusRunnerCommon(ctx, mc, project)
-       if err != nil {
+       if err := builder.BuildQuarkusRunnerCommon(ctx, mc, project); err != 
nil {
                return nil, err
        }
 
@@ -293,31 +292,19 @@ func validateFiles(args []string) error {
        return nil
 }
 
-func validateAdditionalDependencies(additionalDependencies []string) error {
-       // Validate list of additional dependencies i.e. make sure that each 
dependency has a valid type
-       for _, additionalDependency := range additionalDependencies {
-               isValid := validateDependency(additionalDependency)
-               if !isValid {
-                       return errors.New("Unexpected type for user-provided 
dependency: " + additionalDependency + ". " + additionalDependencyUsageMessage)
+// validateDependencies validates list of additional dependencies i.e. makes 
sure
+// that each dependency has a valid type.
+func validateDependencies(dependencies []string) error {
+       for _, dependency := range dependencies {
+               depType := strings.Split(dependency, ":")[0]
+               if !util.StringSliceExists(acceptedDependencyTypes, depType) {
+                       return fmt.Errorf("dependency is not valid: %s", 
dependency)
                }
        }
 
        return nil
 }
 
-func validateDependency(additionalDependency string) bool {
-       dependencyComponents := strings.Split(additionalDependency, ":")
-
-       TypeIsValid := false
-       for _, dependencyType := range acceptedDependencyTypes {
-               if dependencyType == dependencyComponents[0] {
-                       TypeIsValid = true
-               }
-       }
-
-       return TypeIsValid
-}
-
 func validateIntegrationFiles(args []string) error {
        // If no source files have been provided there is nothing to inspect.
        if len(args) == 0 {
diff --git a/pkg/cmd/util_dependencies_test.go b/pkg/cmd/local_util_test.go
similarity index 100%
rename from pkg/cmd/util_dependencies_test.go
rename to pkg/cmd/local_util_test.go
diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go
index abdde0747..c32a187e1 100644
--- a/pkg/cmd/root.go
+++ b/pkg/cmd/root.go
@@ -59,7 +59,6 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, 
error) {
                ContextCancel: childCancel,
        }
 
-       var err error
        cmd := kamelPreAddCommandInit(&options)
        addKamelSubcommands(cmd, &options)
 
@@ -67,7 +66,7 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, 
error) {
                return cmd, err
        }
 
-       err = kamelPostAddCommandInit(cmd)
+       err := kamelPostAddCommandInit(cmd)
 
        return cmd, err
 }
@@ -148,7 +147,7 @@ func addKamelSubcommands(cmd *cobra.Command, options 
*RootCmdOptions) {
        cmd.AddCommand(cmdOnly(newCmdInit(options)))
        cmd.AddCommand(cmdOnly(newCmdDebug(options)))
        cmd.AddCommand(cmdOnly(newCmdDump(options)))
-       cmd.AddCommand(newCmdLocal(options))
+       cmd.AddCommand(cmdOnly(newCmdLocal(options)))
        cmd.AddCommand(cmdOnly(newCmdBind(options)))
        cmd.AddCommand(cmdOnly(newCmdPromote(options)))
        cmd.AddCommand(newCmdKamelet(options))
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index 27df5e167..9a02f5064 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -75,6 +75,8 @@ import (
        "github.com/apache/camel-k/pkg/util/watch"
 )
 
+const usageDependency = `A dependency that should be included, e.g., "-d 
camel-mail" for a Camel component, "-d mvn:org.my:app:1.0" for a Maven 
dependency or 
"file://localPath[?targetPath=<path>&registry=<registry_URL>&skipChecksums=<true>&skipPOM=<true>]"
 for local files (experimental)`
+
 func newCmdRun(rootCmdOptions *RootCmdOptions) (*cobra.Command, 
*runCmdOptions) {
        options := runCmdOptions{
                RootCmdOptions: rootCmdOptions,
@@ -94,7 +96,7 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) 
(*cobra.Command, *runCmdOptions)
 
        cmd.Flags().String("name", "", "The integration name")
        cmd.Flags().StringArrayP("connect", "c", nil, "A Service that the 
integration should bind to, specified as 
[[apigroup/]version:]kind:[namespace/]name")
-       cmd.Flags().StringArrayP("dependency", "d", nil, "A dependency that 
should be included, e.g., \"-d camel-mail\" for a Camel component, \"-d 
mvn:org.my:app:1.0\" for a Maven dependency or 
\"file://localPath[?targetPath=<path>&registry=<registry 
URL>&skipChecksums=<true>&skipPOM=<true>]\" for local files (experimental)")
+       cmd.Flags().StringArrayP("dependency", "d", nil, usageDependency)
        cmd.Flags().BoolP("wait", "w", false, "Wait for the integration to be 
running")
        cmd.Flags().StringP("kit", "k", "", "The kit used to run the 
integration")
        cmd.Flags().StringArrayP("property", "p", nil, "Add a runtime property 
or properties file (syntax: 
[my-key=my-value|file:/path/to/my-conf.properties])")
diff --git a/pkg/util/camel/camel_dependencies.go 
b/pkg/util/camel/camel_dependencies.go
index ae43f9c7f..e6055f596 100644
--- a/pkg/util/camel/camel_dependencies.go
+++ b/pkg/util/camel/camel_dependencies.go
@@ -30,14 +30,9 @@ import (
 )
 
 // ManageIntegrationDependencies --.
-func ManageIntegrationDependencies(
-       project *maven.Project,
-       dependencies []string,
-       catalog *RuntimeCatalog) error {
-
+func ManageIntegrationDependencies(project *maven.Project, dependencies 
[]string, catalog *RuntimeCatalog) error {
        // Add dependencies from build
-       err := addDependencies(project, dependencies, catalog)
-       if err != nil {
+       if err := addDependencies(project, dependencies, catalog); err != nil {
                return err
        }
        // Add dependencies from catalog

Reply via email to