Repository: apache/camel-k
Pull request #4423 (2023-05-30 06:45:17)

Removed coverage badge 3rd party dependency
<!-- Description -->
Removed 3rd party dependencies from coverage badge workflow.
Added option to run the workflow manually.




<!--
Enter your extended release note in the below block. If the PR requires
additional action from users switching to the new release, include the string
"action required". If no release note is required, write "NONE". 

You can (optionally) mark this PR with labels "kind/bug" or "kind/feature" to make sure
the text is added to the right section of the release notes. 
-->

**Release Note**
```release-note
NONE
```



Patch:
diff --git a/.github/actions/coverage-badge/action.yml b/.github/actions/coverage-badge/action.yml
new file mode 100644
index 000000000..a2bc02168
--- /dev/null
+++ b/.github/actions/coverage-badge/action.yml
@@ -0,0 +1,48 @@
+# ---------------------------------------------------------------------------
+# 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.
+# ---------------------------------------------------------------------------
+
+name: Go Coverage Badge
+description: Generate coverage badge for go projects
+inputs:
+  filename:
+    description: 'File containing the tests output'
+    required: true
+    default: coverage.out
+  target:
+    description: 'Target file (default "README.md")'
+    required: false
+
+runs:
+  using: 'composite'
+  steps:
+    - run: |
+        EXTRA_ARGS=""
+
+        if [[ -n '${{ inputs.target }}'  ]]; then
+          EXTRA_ARGS+="-target=${{ inputs.target }}"
+        fi
+        
+        TEMP_DIR=$(mktemp -d)
+        curl -sf https://gobinaries.com/github.com/AlexBeauchemin/gobadge@v0.2.0 | PREFIX=$TEMP_DIR sh
+        $TEMP_DIR/gobadge -filename=${{ inputs.filename }} $EXTRA_ARGS
+        rm -rf $TEMP_DIR
+      id: coverage-badge-go
+      shell: bash
+
+branding:
+  icon: check-circle
+  color: white
\ No newline at end of file
diff --git a/.github/workflows/nightly-coverage.yml b/.github/workflows/nightly-coverage.yml
index 801312566..bda72b846 100644
--- a/.github/workflows/nightly-coverage.yml
+++ b/.github/workflows/nightly-coverage.yml
@@ -55,7 +55,7 @@ jobs:
 
       - name: Go Coverage Badge
 
-        uses: tj-actions/coverage-badge-go@v2
+        uses: ./.github/actions/coverage-badge
         with:
           filename: coverage.out
           target: badge.out
@@ -65,13 +65,6 @@ jobs:
           replacement=$(grep -o 'https://[^)]*' badge.out)
           target="(?:https:\/\/img\.shields\.io\/badge\/Coverage).*?(?=\.svg)"
           perl -i -pe "s|${target}|${replacement}|g" README.adoc
-          
-          
-      - name: Verify Changed files
-        uses: tj-actions/verify-changed-files@v12
-        id: verify-changed-files
-        with:
-          files: README.adoc
 
       - name: Commit changes
         shell: bash
diff --git a/go.mod b/go.mod
index 4f700feb5..7df6c2fcc 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,6 @@ require (
 	github.com/apache/camel-k/v2/pkg/kamelet/repository v0.0.0
 	github.com/container-tools/spectrum v0.6.17
 	github.com/evanphx/json-patch v5.6.0+incompatible
-	github.com/fatih/structs v1.1.0
 	github.com/gertd/go-pluralize v0.2.1
 	github.com/go-logr/logr v1.2.4
 	github.com/google/go-containerregistry v0.13.0
@@ -109,7 +108,6 @@ require (
 	github.com/google/go-cmp v0.5.9 // indirect
 	github.com/google/go-querystring v1.0.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
-	github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
 	github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
diff --git a/go.sum b/go.sum
index c9807a623..87378b39e 100644
--- a/go.sum
+++ b/go.sum
@@ -378,8 +378,6 @@ github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL
 github.com/fatih/color v1.12.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
 github.com/fatih/set v0.2.1 h1:nn2CaJyknWE/6txyUDGwysr3G5QC6xWB/PtVjPBbeaA=
 github.com/fatih/set v0.2.1/go.mod h1:+RKtMCH+favT2+3YecHGxcc0b4KyVWA1QWWJUs4E0CI=
-github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
-github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
 github.com/flowstack/go-jsonschema v0.1.1/go.mod h1:yL7fNggx1o8rm9RlgXv7hTBWxdBM0rVwpMwimd3F3N0=
 github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
@@ -574,8 +572,6 @@ github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY
 github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
-github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
diff --git a/pkg/cmd/bind.go b/pkg/cmd/bind.go
index a4b9235ae..e2ae045a2 100644
--- a/pkg/cmd/bind.go
+++ b/pkg/cmd/bind.go
@@ -169,7 +169,7 @@ func (o *bindCmdOptions) validate(cmd *cobra.Command, args []string) error {
 	}
 	catalog := trait.NewCatalog(client)
 
-	return validateTraits(catalog, o.Traits)
+	return validateTraits(catalog, extractTraitNames(o.Traits))
 }
 
 func (o *bindCmdOptions) run(cmd *cobra.Command, args []string) error {
diff --git a/pkg/cmd/completion_bash.go b/pkg/cmd/completion_bash.go
index a33231651..5f6ab1051 100644
--- a/pkg/cmd/completion_bash.go
+++ b/pkg/cmd/completion_bash.go
@@ -25,7 +25,6 @@ import (
 	"github.com/spf13/cobra"
 
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
-	"github.com/apache/camel-k/v2/pkg/trait"
 	"github.com/apache/camel-k/v2/pkg/util/camel"
 )
 
@@ -70,12 +69,6 @@ __kamel_dependency_type() {
     esac
 }
 
-__kamel_traits() {
-    local type_list="` + strings.Join(trait.NewCatalog(nil).ComputeTraitsProperties(), " ") + `"
-    COMPREPLY=( $( compgen -W "${type_list}" -- "$cur") )
-    compopt -o nospace
-}
-
 __kamel_languages() {
     local type_list="js groovy kotlin java xml"
     COMPREPLY=( $( compgen -W "${type_list}" -- "$cur") )
diff --git a/pkg/cmd/kit_create.go b/pkg/cmd/kit_create.go
index 51650a355..1d893022f 100644
--- a/pkg/cmd/kit_create.go
+++ b/pkg/cmd/kit_create.go
@@ -30,7 +30,6 @@ import (
 
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/v2/pkg/trait"
-	"github.com/apache/camel-k/v2/pkg/util"
 	"github.com/apache/camel-k/v2/pkg/util/kubernetes"
 )
 
@@ -89,18 +88,7 @@ func (command *kitCreateCommandOptions) run(cmd *cobra.Command, args []string) e
 	if err != nil {
 		return err
 	}
-
 	catalog := trait.NewCatalog(c)
-	tp := catalog.ComputeTraitsProperties()
-	for _, t := range command.Traits {
-		kv := strings.SplitN(t, "=", 2)
-
-		if !util.StringSliceExists(tp, kv[0]) {
-			fmt.Fprintln(cmd.OutOrStdout(), "Error:", t, "is not a valid trait property")
-			return nil
-		}
-	}
-
 	kit := v1.NewIntegrationKit(command.Namespace, args[0])
 	key := ctrl.ObjectKey{
 		Namespace: command.Namespace,
diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go
index d20b1b30c..a43e5a349 100644
--- a/pkg/cmd/root.go
+++ b/pkg/cmd/root.go
@@ -63,7 +63,7 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, error) {
 	cmd := kamelPreAddCommandInit(&options)
 	addKamelSubcommands(cmd, &options)
 
-	if err := addHelpSubCommands(cmd, &options); err != nil {
+	if err := addHelpSubCommands(cmd); err != nil {
 		return cmd, err
 	}
 
@@ -153,7 +153,7 @@ func addKamelSubcommands(cmd *cobra.Command, options *RootCmdOptions) {
 	cmd.AddCommand(cmdOnly(newCmdConfig(options)))
 }
 
-func addHelpSubCommands(cmd *cobra.Command, options *RootCmdOptions) error {
+func addHelpSubCommands(cmd *cobra.Command) error {
 	cmd.InitDefaultHelpCmd()
 
 	var helpCmd *cobra.Command
@@ -169,8 +169,6 @@ func addHelpSubCommands(cmd *cobra.Command, options *RootCmdOptions) error {
 	}
 	helpCmd.Annotations = map[string]string{offlineCommandLabel: "true"}
 
-	helpCmd.AddCommand(cmdOnly(newTraitHelpCmd(options)))
-
 	return nil
 }
 
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index c2da4f6ad..091eee8cd 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -298,7 +298,7 @@ func (o *runCmdOptions) validate() error {
 	}
 	catalog := trait.NewCatalog(client)
 
-	return validateTraits(catalog, o.Traits)
+	return validateTraits(catalog, extractTraitNames(o.Traits))
 }
 
 func filterBuildPropertyFiles(maybePropertyFiles []string) []string {
diff --git a/pkg/cmd/run_support.go b/pkg/cmd/run_support.go
index 048834243..e4bb8063b 100644
--- a/pkg/cmd/run_support.go
+++ b/pkg/cmd/run_support.go
@@ -218,3 +218,12 @@ func generateCatalog(ctx context.Context) (*camel.RuntimeCatalog, error) {
 
 	return catalog, nil
 }
+
+func extractTraitNames(traitProps []string) []string {
+	traitNameProps := make([]string, len(traitProps))
+	for i, tp := range traitProps {
+		splits := strings.Split(tp, ".")
+		traitNameProps[i] = splits[0]
+	}
+	return traitNameProps
+}
diff --git a/pkg/cmd/trait_help.go b/pkg/cmd/trait_help.go
deleted file mode 100644
index a91e4b1e3..000000000
--- a/pkg/cmd/trait_help.go
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
-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 (
-	"encoding/json"
-	"errors"
-	"fmt"
-	"io"
-	"reflect"
-	"strings"
-
-	"github.com/fatih/structs"
-	"github.com/spf13/cobra"
-	"gopkg.in/yaml.v2"
-
-	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
-	"github.com/apache/camel-k/v2/pkg/resources"
-	"github.com/apache/camel-k/v2/pkg/trait"
-	"github.com/apache/camel-k/v2/pkg/util/indentedwriter"
-)
-
-func newTraitHelpCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, *traitHelpCommandOptions) {
-	options := traitHelpCommandOptions{
-		RootCmdOptions: rootCmdOptions,
-	}
-
-	cmd := cobra.Command{
-		Use:     "trait",
-		Short:   "Trait help information",
-		Long:    `Displays help information for traits in a specified output format.`,
-		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)
-		},
-		Annotations: map[string]string{
-			offlineCommandLabel: "true",
-		},
-	}
-
-	cmd.Flags().Bool("all", false, "Include all traits")
-	cmd.Flags().StringP("output", "o", "", "Output format. One of json, yaml")
-
-	return &cmd, &options
-}
-
-type traitHelpCommandOptions struct {
-	*RootCmdOptions
-	IncludeAll   bool   `mapstructure:"all"`
-	OutputFormat string `mapstructure:"output"`
-}
-
-type traitDescription struct {
-	Name        trait.ID                   `json:"name" yaml:"name"`
-	Platform    bool                       `json:"platform" yaml:"platform"`
-	Profiles    []string                   `json:"profiles" yaml:"profiles"`
-	Properties  []traitPropertyDescription `json:"properties" yaml:"properties"`
-	Description string                     `json:"description" yaml:"description"`
-}
-
-type traitPropertyDescription struct {
-	Name         string      `json:"name" yaml:"name"`
-	TypeName     string      `json:"type" yaml:"type"`
-	DefaultValue interface{} `json:"defaultValue,omitempty" yaml:"defaultValue,omitempty"`
-	Description  string      `json:"description" yaml:"description"`
-}
-
-type traitMetaData struct {
-	Traits []traitDescription `yaml:"traits"`
-}
-
-func (command *traitHelpCommandOptions) validate(args []string) error {
-	if command.IncludeAll && len(args) > 0 {
-		return errors.New("invalid combination: --all flag is set and a trait name is provided")
-	}
-	if !command.IncludeAll && len(args) == 0 {
-		return errors.New("invalid combination: provide a trait name or set --all flag for all traits")
-	}
-	return nil
-}
-
-func (command *traitHelpCommandOptions) run(cmd *cobra.Command, args []string) error {
-	var traitDescriptions []*traitDescription
-	catalog := trait.NewCatalog(nil)
-
-	content, err := resources.Resource("/traits.yaml")
-	if err != nil {
-		return err
-	}
-
-	traitMetaData := traitMetaData{}
-	err = yaml.Unmarshal(content, &traitMetaData)
-	if err != nil {
-		return err
-	}
-
-	for _, tp := range v1.AllTraitProfiles {
-		traits := catalog.TraitsForProfile(tp)
-		for _, t := range traits {
-			if len(args) == 1 && trait.ID(args[0]) != t.ID() {
-				continue
-			}
-
-			td := findTraitDescription(t.ID(), traitDescriptions)
-			if td == nil {
-				td = &traitDescription{
-					Name:     t.ID(),
-					Platform: t.IsPlatformTrait(),
-					Profiles: make([]string, 0),
-				}
-
-				var targetTrait *traitDescription
-				for _, item := range traitMetaData.Traits {
-					item := item
-					if item.Name == t.ID() {
-						targetTrait = &item
-						td.Description = item.Description
-						break
-					}
-				}
-				computeTraitProperties(structs.Fields(t), &td.Properties, targetTrait)
-				traitDescriptions = append(traitDescriptions, td)
-			}
-			td.addProfile(string(tp))
-		}
-	}
-
-	if len(args) == 1 && len(traitDescriptions) == 0 {
-		return fmt.Errorf("no trait named '%s' exists", args[0])
-	}
-
-	switch strings.ToUpper(command.OutputFormat) {
-	case "JSON":
-		res, err := json.Marshal(traitDescriptions)
-		if err != nil {
-			return err
-		}
-		fmt.Fprintln(cmd.OutOrStdout(), string(res))
-	case "YAML":
-		res, err := yaml.Marshal(traitDescriptions)
-		if err != nil {
-			return err
-		}
-		fmt.Fprintln(cmd.OutOrStdout(), string(res))
-	default:
-		res, err := outputTraits(traitDescriptions)
-		if err != nil {
-			return err
-		}
-		fmt.Fprintln(cmd.OutOrStdout(), res)
-	}
-
-	return nil
-}
-
-func (td *traitDescription) addProfile(tp string) {
-	for _, p := range td.Profiles {
-		if p == tp {
-			return
-		}
-	}
-	td.Profiles = append(td.Profiles, tp)
-}
-
-func findTraitDescription(id trait.ID, traitDescriptions []*traitDescription) *traitDescription {
-	for _, td := range traitDescriptions {
-		if td.Name == id {
-			return td
-		}
-	}
-	return nil
-}
-
-func computeTraitProperties(fields []*structs.Field, properties *[]traitPropertyDescription, targetTrait *traitDescription) {
-	for _, f := range fields {
-		if f.IsEmbedded() && f.IsExported() && f.Kind() == reflect.Struct {
-			computeTraitProperties(f.Fields(), properties, targetTrait)
-		}
-
-		if !f.IsExported() || f.IsEmbedded() {
-			continue
-		}
-
-		property := f.Tag("property")
-		if property == "" {
-			continue
-		}
-
-		tp := traitPropertyDescription{}
-		tp.Name = property
-
-		switch f.Kind() {
-		case reflect.Ptr:
-			tp.TypeName = reflect.TypeOf(f.Value()).Elem().String()
-		case reflect.Slice:
-			tp.TypeName = fmt.Sprintf("slice:%s", reflect.TypeOf(f.Value()).Elem().String())
-		default:
-			tp.TypeName = f.Kind().String()
-		}
-
-		if f.IsZero() {
-			if tp.TypeName == "bool" {
-				tp.DefaultValue = false
-			} else {
-				tp.DefaultValue = nil
-			}
-		} else {
-			tp.DefaultValue = f.Value()
-		}
-
-		// apply the description from metadata
-		if targetTrait != nil {
-			for _, item := range targetTrait.Properties {
-				if item.Name == tp.Name {
-					tp.Description = item.Description
-				}
-			}
-		}
-
-		*properties = append(*properties, tp)
-	}
-}
-
-func outputTraits(descriptions []*traitDescription) (string, error) {
-	return indentedwriter.IndentedString(func(out io.Writer) error {
-		w := indentedwriter.NewWriter(out)
-
-		for _, td := range descriptions {
-			w.Writef(0, "Name:\t%s\n", td.Name)
-			w.Writef(0, "Profiles:\t%s\n", strings.Join(td.Profiles, ","))
-			w.Writef(0, "Platform:\t%t\n", td.Platform)
-			w.Writef(0, "Properties:\n")
-			for _, p := range td.Properties {
-				w.Writef(1, "%s:\n", p.Name)
-				w.Writef(2, "Type:\t%s\n", p.TypeName)
-				if p.DefaultValue != nil {
-					w.Writef(2, "Default Value:\t%v\n", p.DefaultValue)
-				}
-			}
-			w.Writelnf(0, "")
-		}
-
-		return nil
-	})
-}
diff --git a/pkg/cmd/trait_support.go b/pkg/cmd/trait_support.go
index f861247f8..5ae94a1a4 100644
--- a/pkg/cmd/trait_support.go
+++ b/pkg/cmd/trait_support.go
@@ -39,39 +39,16 @@ var knownAddons = []string{"keda", "master", "strimzi", "3scale", "tracing"}
 var traitConfigRegexp = regexp.MustCompile(`^([a-z0-9-]+)((?:\.[a-z0-9-]+)(?:\[[0-9]+\]|\..+)*)=(.*)$`)
 
 func validateTraits(catalog *trait.Catalog, traits []string) error {
-	tp := catalog.ComputeTraitsProperties()
 	for _, t := range traits {
-		kv := strings.SplitN(t, "=", 2)
-		prefix := kv[0]
-		if strings.Contains(prefix, "[") {
-			prefix = prefix[0:strings.Index(prefix, "[")]
-		}
-		if valid, err := validateTrait(tp, prefix); err != nil {
-			return err
-		} else if !valid {
-			return fmt.Errorf("%s is not a valid trait property", t)
+		tr := catalog.GetTrait(t)
+		if tr == nil {
+			return fmt.Errorf("trait %s does not exist in catalog", t)
 		}
 	}
 
 	return nil
 }
 
-func validateTrait(properties []string, item string) (bool, error) {
-	for i := 0; i < len(properties); i++ {
-		if strings.HasSuffix(properties[i], ".*") {
-			if match, err := regexp.MatchString(properties[i], item); err != nil {
-				return false, err
-			} else if match {
-				return true, nil
-			}
-		} else if properties[i] == item {
-			return true, nil
-		}
-	}
-
-	return false, nil
-}
-
 func configureTraits(options []string, traits interface{}, catalog trait.Finder) error {
 	config, err := optionsToMap(options)
 	if err != nil {
diff --git a/pkg/kamelet/repository/github_repository.go b/pkg/kamelet/repository/github_repository.go
index 816f708ab..f9ce74403 100644
--- a/pkg/kamelet/repository/github_repository.go
+++ b/pkg/kamelet/repository/github_repository.go
@@ -32,8 +32,6 @@ import (
 	"golang.org/x/oauth2"
 
 	"k8s.io/apimachinery/pkg/util/yaml"
-
-	"github.com/gregjones/httpcache"
 )
 
 type githubKameletRepository struct {
@@ -45,7 +43,7 @@ type githubKameletRepository struct {
 }
 
 func newGithubKameletRepository(owner, repo, path, ref string) KameletRepository {
-	httpClient := httpcache.NewMemoryCacheTransport().Client()
+	httpClient := &http.Client{}
 	if token, ok := os.LookupEnv("GITHUB_TOKEN"); ok {
 		ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
 		ctx := context.WithValue(context.Background(), oauth2.HTTPClient, httpClient)
diff --git a/pkg/kamelet/repository/go.mod b/pkg/kamelet/repository/go.mod
index bb3f6fa1a..6ec4cf5e8 100644
--- a/pkg/kamelet/repository/go.mod
+++ b/pkg/kamelet/repository/go.mod
@@ -6,7 +6,6 @@ require (
 	github.com/apache/camel-k/v2/pkg/apis/camel v0.0.0
 	github.com/apache/camel-k/v2/pkg/client/camel v0.0.0
 	github.com/google/go-github/v32 v32.1.0
-	github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7
 	github.com/stretchr/testify v1.8.0
 	golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
 	k8s.io/apimachinery v0.25.6
diff --git a/pkg/kamelet/repository/go.sum b/pkg/kamelet/repository/go.sum
index d8522d9a8..723004484 100644
--- a/pkg/kamelet/repository/go.sum
+++ b/pkg/kamelet/repository/go.sum
@@ -132,8 +132,6 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
 github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
-github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
diff --git a/pkg/resources/resources.go b/pkg/resources/resources.go
index 2f527639b..183fb64cb 100644
--- a/pkg/resources/resources.go
+++ b/pkg/resources/resources.go
@@ -174,6 +174,18 @@ var assets = func() http.FileSystem {
 			name:    "manager",
 			modTime: time.Time{},
 		},
+		"/manager/bundle": &vfsgen۰DirInfo{
+			name:    "bundle",
+			modTime: time.Time{},
+		},
+		"/manager/bundle/manifests": &vfsgen۰DirInfo{
+			name:    "manifests",
+			modTime: time.Time{},
+		},
+		"/manager/bundle/metadata": &vfsgen۰DirInfo{
+			name:    "metadata",
+			modTime: time.Time{},
+		},
 		"/manager/operator-deployment.yaml": &vfsgen۰CompressedFileInfo{
 			name:             "operator-deployment.yaml",
 			modTime:          time.Time{},
@@ -686,6 +698,7 @@ var assets = func() http.FileSystem {
 		fs["/crd/bases/camel.apache.org_pipes.yaml"].(os.FileInfo),
 	}
 	fs["/manager"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
+		fs["/manager/bundle"].(os.FileInfo),
 		fs["/manager/operator-deployment.yaml"].(os.FileInfo),
 		fs["/manager/operator-pvc.yaml"].(os.FileInfo),
 		fs["/manager/operator-service-account.yaml"].(os.FileInfo),
@@ -699,6 +712,10 @@ var assets = func() http.FileSystem {
 		fs["/manager/patch-toleration.yaml"].(os.FileInfo),
 		fs["/manager/patch-watch-namespace-global.yaml"].(os.FileInfo),
 	}
+	fs["/manager/bundle"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
+		fs["/manager/bundle/manifests"].(os.FileInfo),
+		fs["/manager/bundle/metadata"].(os.FileInfo),
+	}
 	fs["/prometheus"].(*vfsgen۰DirInfo).entries = []os.FileInfo{
 		fs["/prometheus/operator-pod-monitor.yaml"].(os.FileInfo),
 		fs["/prometheus/operator-prometheus-rule.yaml"].(os.FileInfo),
diff --git a/pkg/trait/trait_catalog.go b/pkg/trait/trait_catalog.go
index 0c9697337..b8ec893d1 100644
--- a/pkg/trait/trait_catalog.go
+++ b/pkg/trait/trait_catalog.go
@@ -20,12 +20,9 @@ package trait
 import (
 	"errors"
 	"fmt"
-	"reflect"
 	"sort"
 	"strings"
 
-	"github.com/fatih/structs"
-
 	v1 "github.com/apache/camel-k/v2/pkg/apis/camel/v1"
 	"github.com/apache/camel-k/v2/pkg/client"
 	"github.com/apache/camel-k/v2/pkg/util/log"
@@ -156,42 +153,6 @@ func (c *Catalog) GetTrait(id string) Trait {
 	return nil
 }
 
-// ComputeTraitsProperties returns all key/value configuration properties that can be used to configure traits.
-func (c *Catalog) ComputeTraitsProperties() []string {
-	results := make([]string, 0)
-	for _, trait := range c.AllTraits() {
-		trait := trait // pin
-		c.processFields(structs.Fields(trait), func(name string) {
-			results = append(results, string(trait.ID())+"."+name)
-		})
-	}
-
-	return results
-}
-
-func (c *Catalog) processFields(fields []*structs.Field, processor func(string)) {
-	for _, f := range fields {
-		if f.IsEmbedded() && f.IsExported() && f.Kind() == reflect.Struct {
-			c.processFields(f.Fields(), processor)
-		}
-
-		if f.IsEmbedded() {
-			continue
-		}
-
-		property := f.Tag("property")
-
-		if property != "" {
-			items := strings.Split(property, ",")
-			if f.Kind() == reflect.Map {
-				processor(items[0] + ".*")
-			} else {
-				processor(items[0])
-			}
-		}
-	}
-}
-
 type Finder interface {
 	GetTrait(id string) Trait
 }


Test patch:
diff --git a/e2e/common/cli/offline_commands_test.go b/e2e/common/cli/offline_commands_test.go
index e990cb509..0027e8b7d 100644
--- a/e2e/common/cli/offline_commands_test.go
+++ b/e2e/common/cli/offline_commands_test.go
@@ -38,14 +38,6 @@ func TestKamelVersionWorksOffline(t *testing.T) {
 	assert.Nil(t, Kamel("version", "--kube-config", "non-existent-kubeconfig-file").Execute())
 }
 
-func TestKamelHelpTraitWorksOffline(t *testing.T) {
-	RegisterTestingT(t)
-
-	traitCmd := Kamel("help", "trait", "--all", "--kube-config", "non-existent-kubeconfig-file")
-	traitCmd.SetOut(io.Discard)
-	assert.Nil(t, traitCmd.Execute())
-}
-
 func TestKamelHelpOptionWorksOffline(t *testing.T) {
 	RegisterTestingT(t)
 
diff --git a/pkg/cmd/run_support_test.go b/pkg/cmd/run_support_test.go
index 15ff0d93f..45e424998 100644
--- a/pkg/cmd/run_support_test.go
+++ b/pkg/cmd/run_support_test.go
@@ -78,3 +78,11 @@ func TestDownloadDependencyWithoutFileName(t *testing.T) {
 	_, err = os.Stat(path)
 	assert.Nil(t, err)
 }
+
+func TestExtractTraitNames(t *testing.T) {
+	traitProps := []string{"container.enabled=true", "no-trait.noval=1", "nothing"}
+	tn := extractTraitNames(traitProps)
+	assert.Equal(t, "container", tn[0])
+	assert.Equal(t, "no-trait", tn[1])
+	assert.Equal(t, "nothing", tn[2])
+}
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/run_test.go
index 1efbfd112..7a009e01c 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/run_test.go
@@ -426,7 +426,7 @@ func TestRunMissingTraitFlag(t *testing.T) {
 		"--trait", "bogus.missing",
 		integrationSource)
 	assert.NotNil(t, err)
-	assert.Equal(t, "bogus.missing is not a valid trait property", err.Error())
+	assert.Equal(t, "trait bogus does not exist in catalog", err.Error())
 	assert.Len(t, runCmdOptions.Traits, 1)
 	assert.Equal(t, "bogus.missing", runCmdOptions.Traits[0])
 }
@@ -668,7 +668,7 @@ func TestMissingTrait(t *testing.T) {
 	runCmdOptions, runCmd, _ := initializeRunCmdOptionsWithOutput(t)
 	output, err := test.ExecuteCommand(runCmd, cmdRun, tmpFile.Name(), "-o", "yaml", "-t", "bogus.fail=i-must-fail")
 	assert.Equal(t, "yaml", runCmdOptions.OutputFormat)
-	assert.Equal(t, "Error: bogus.fail=i-must-fail is not a valid trait property\n", output)
+	assert.Equal(t, "Error: trait bogus does not exist in catalog\n", output)
 	assert.NotNil(t, err)
 }
 
diff --git a/pkg/cmd/trait_help_test.go b/pkg/cmd/trait_help_test.go
deleted file mode 100644
index ff03882a1..000000000
--- a/pkg/cmd/trait_help_test.go
+++ /dev/null
@@ -1,40 +0,0 @@
-//go:build common
-// +build common
-
-/*
-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/apache/camel-k/v2/pkg/util/test"
-)
-
-func TestHelpForNonExistentTrait(t *testing.T) {
-	options, rootCommand := kamelTestPreAddCommandInit()
-	traitHelpCommand, _ := newTraitHelpCmd(options)
-	rootCommand.AddCommand(traitHelpCommand)
-
-	kamelTestPostAddCommandInit(t, rootCommand)
-
-	_, err := test.ExecuteCommand(rootCommand, "trait", "foobar")
-	if err == nil {
-		t.Fatalf("Expected error result for invalid trait 'foobar'")
-	}
-}