Skip to content

Commit

Permalink
fix(cli): kamel local build doesn't support same dependency notation
Browse files Browse the repository at this point in the history
This also fixes jitpack dependencies resolution.
Fix #2213.
  • Loading branch information
tadayosi committed Jul 14, 2022
1 parent c3b9c9b commit 36439e1
Show file tree
Hide file tree
Showing 17 changed files with 261 additions and 199 deletions.
2 changes: 1 addition & 1 deletion e2e/local/files/dependency.groovy
Original file line number Diff line number Diff line change
@@ -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
Expand Down
6 changes: 4 additions & 2 deletions e2e/local/local_build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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())
}
Expand All @@ -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()
Expand All @@ -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
Expand Down
25 changes: 25 additions & 0 deletions e2e/local/local_run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
25 changes: 17 additions & 8 deletions pkg/apis/camel/v1/integration_types_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions pkg/apis/camel/v1/integration_types_support_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
48 changes: 40 additions & 8 deletions pkg/cmd/local.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
48 changes: 17 additions & 31 deletions pkg/cmd/local_build.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand All @@ -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 {
Expand All @@ -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
}

Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}
Expand Down
38 changes: 31 additions & 7 deletions pkg/cmd/local_build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
})
}
Loading

0 comments on commit 36439e1

Please sign in to comment.