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

[camel-k] 01/10: Allow to configure kamel CLI with env vars and configuration files #1108

This is an automated email from the ASF dual-hosted git repository.

lburgazzoli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel-k.git

commit 24efaa0f1fd5b9b1489a324b7a512194bd45e041
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Wed Nov 27 18:22:19 2019 +0100

    Allow to configure kamel CLI with env vars and configuration files #1108
---
 go.mod                                |   2 +
 go.sum                                |  11 ++
 pkg/cmd/builder.go                    |  15 ++-
 pkg/cmd/delete.go                     |  17 +--
 pkg/cmd/describe_integration.go       |   3 +-
 pkg/cmd/describe_kit.go               |   7 +-
 pkg/cmd/describe_platform.go          |   7 +-
 pkg/cmd/get.go                        |   9 +-
 pkg/cmd/install.go                    | 237 +++++++++++++++++++---------------
 pkg/cmd/kit_create.go                 |  74 +++++------
 pkg/cmd/kit_delete.go                 |  27 ++--
 pkg/cmd/kit_get.go                    |  25 ++--
 pkg/cmd/log.go                        |  13 +-
 pkg/cmd/operator.go                   |  17 +--
 pkg/cmd/rebuild.go                    |   9 +-
 pkg/cmd/reset.go                      |  21 +--
 pkg/cmd/root.go                       |  35 ++++-
 pkg/cmd/{operator.go => root_test.go} |  27 +---
 pkg/cmd/run.go                        | 102 ++++++++-------
 pkg/cmd/util.go                       | 144 +++++++++++++++++++++
 20 files changed, 495 insertions(+), 307 deletions(-)

diff --git a/go.mod b/go.mod
index 5af83f5..3f5c829 100644
--- a/go.mod
+++ b/go.mod
@@ -8,6 +8,7 @@ require (
 	github.com/coreos/prometheus-operator v0.29.0
 	github.com/evanphx/json-patch v4.5.0+incompatible
 	github.com/fatih/structs v1.1.0
+	github.com/gertd/go-pluralize v0.1.1
 	github.com/go-logr/logr v0.1.0
 	github.com/google/go-containerregistry v0.0.0-20190206233756-dbc4da98389f // indirect
 	github.com/google/uuid v1.1.1
@@ -23,6 +24,7 @@ require (
 	github.com/sirupsen/logrus v1.4.2
 	github.com/spf13/cobra v0.0.5
 	github.com/spf13/pflag v1.0.3
+	github.com/spf13/viper v1.4.0
 	github.com/stoewer/go-strcase v1.0.2
 	github.com/stretchr/testify v1.3.0
 	go.uber.org/multierr v1.1.0
diff --git a/go.sum b/go.sum
index c55c3c8..c21e98d 100644
--- a/go.sum
+++ b/go.sum
@@ -13,6 +13,7 @@ github.com/Azure/azure-sdk-for-go v21.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9mo
 github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
 github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM=
@@ -137,6 +138,8 @@ github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
 github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
 github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/gertd/go-pluralize v0.1.1 h1:fQhql/WRRwr4TVp+TCw12s2esCacvEVBdkTUUwNqF/Q=
+github.com/gertd/go-pluralize v0.1.1/go.mod h1:t5DfHcumb6m0RqyVJDrDLEzL2AGeaiqUXIcDNwLaeAs=
 github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -276,6 +279,7 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ
 github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/hcl v0.0.0-20160711231752-d8c773c4cba1/go.mod h1:oZtUIOe8dh44I2q6ScRibXws4Ajl+d+nod3AaR9vL5w=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
 github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
 github.com/heketi/heketi v0.0.0-20181109135656-558b29266ce0/go.mod h1:bB9ly3RchcQqsQ9CpyaQwvva7RS5ytVoSoholZQON6o=
 github.com/heketi/rest v0.0.0-20180404230133-aa6a65207413/go.mod h1:BeS3M108VzVlmAue3lv2WcGuPAX94/KN63MUURzbYSI=
@@ -335,6 +339,7 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9
 github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
 github.com/lpabon/godbc v0.1.1/go.mod h1:Jo9QV0cf3U6jZABgiJ2skINAXb9j8m51r07g4KI92ZA=
 github.com/magiconair/properties v0.0.0-20160816085511-61b492c03cf4/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
 github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic=
@@ -360,6 +365,7 @@ github.com/miekg/dns v0.0.0-20160614162101-5d001d020961/go.mod h1:W1PPwlIAgtquWB
 github.com/mindprince/gonvml v0.0.0-20171110221305-fee913ce8fb2/go.mod h1:2eu9pRWp8mo84xCg6KswZ+USQHjwgRhNp06sozOdsTY=
 github.com/mistifyio/go-zfs v0.0.0-20151009155749-1b4ae6fb4e77/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
 github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
 github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
 github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
 github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
@@ -417,6 +423,7 @@ github.com/operator-framework/operator-sdk v0.12.0 h1:9eAD1L8e6pPCpFCAacBUVf2elo
 github.com/operator-framework/operator-sdk v0.12.0/go.mod h1:mW8isQxiXlLCVf2E+xqflkQAVLOTbiqjndKdkKIrR0M=
 github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
 github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/petar/GoLLRB v0.0.0-20130427215148-53be0d36a84c/go.mod h1:HUpKUBZnpzkdx0kD/+Yfuft+uD3zHGtXF/XJB14TUr4=
 github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
@@ -492,14 +499,17 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v0.0.0-20160816080757-b28a7effac97/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
 github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
 github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
 github.com/spf13/cast v0.0.0-20160730092037-e31f36ffc91a/go.mod h1:r2rcYCSwa1IExKTDiTfzaxqT2FNHs8hODu4LnUfgKEg=
+github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
 github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
 github.com/spf13/cobra v0.0.0-20180319062004-c439c4fa0937/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
 github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
 github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
 github.com/spf13/jwalterweatherman v0.0.0-20160311093646-33c24e77fb80/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
 github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
 github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
@@ -508,6 +518,7 @@ github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/viper v0.0.0-20160820190039-7fb2782df3d8/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
 github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
 github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
 github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50/go.mod h1:1pdIZTAHUz+HDKDVZ++5xg/duPlhKAIzw9qy42CWYp4=
 github.com/stoewer/go-strcase v1.0.2 h1:l3iQ2FPu8+36ars/7syO1dQAkjwMCb1IE3J+Th0ohfE=
diff --git a/pkg/cmd/builder.go b/pkg/cmd/builder.go
index adb9509..9517e7d 100644
--- a/pkg/cmd/builder.go
+++ b/pkg/cmd/builder.go
@@ -27,21 +27,22 @@ func newCmdBuilder(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		RootCmdOptions: rootCmdOptions,
 	}
 	cmd := cobra.Command{
-		Use:    "builder",
-		Short:  "Run the Camel K builder",
-		Long:   `Run the Camel K builder`,
-		Hidden: true,
-		Run:    impl.run,
+		Use:     "builder",
+		Short:   "Run the Camel K builder",
+		Long:    `Run the Camel K builder`,
+		Hidden:  true,
+		PreRunE: decode(&impl),
+		Run:     impl.run,
 	}
 
-	cmd.Flags().StringVar(&impl.BuildName, "build-name", "", "The name of the build resource")
+	cmd.Flags().String("build-name", "", "The name of the build resource")
 
 	return &cmd
 }
 
 type builderCmdOptions struct {
 	*RootCmdOptions
-	BuildName string
+	BuildName string `mapstructure:"build-name"`
 }
 
 func (o *builderCmdOptions) run(_ *cobra.Command, _ []string) {
diff --git a/pkg/cmd/delete.go b/pkg/cmd/delete.go
index 6eeda59..a3d9a55 100644
--- a/pkg/cmd/delete.go
+++ b/pkg/cmd/delete.go
@@ -36,8 +36,9 @@ func newCmdDelete(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		RootCmdOptions: rootCmdOptions,
 	}
 	cmd := cobra.Command{
-		Use:   "delete [integration1] [integration2] ...",
-		Short: "Delete integrations deployed on Kubernetes",
+		Use:     "delete [integration1] [integration2] ...",
+		Short:   "Delete integrations deployed on Kubernetes",
+		PreRunE: decode(&impl),
 		RunE: func(_ *cobra.Command, args []string) error {
 			if err := impl.validate(args); err != nil {
 				return err
@@ -50,21 +51,21 @@ func newCmdDelete(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		},
 	}
 
-	cmd.Flags().BoolVar(&impl.deleteAll, "all", false, "Delete all integrations")
+	cmd.Flags().Bool("all", false, "Delete all integrations")
 
 	return &cmd
 }
 
 type deleteCmdOptions struct {
 	*RootCmdOptions
-	deleteAll bool
+	DeleteAll bool `mapstructure:"all"`
 }
 
 func (command *deleteCmdOptions) validate(args []string) error {
-	if command.deleteAll && len(args) > 0 {
+	if command.DeleteAll && len(args) > 0 {
 		return errors.New("invalid combination: both all flag and named integrations are set")
 	}
-	if !command.deleteAll && len(args) == 0 {
+	if !command.DeleteAll && len(args) == 0 {
 		return errors.New("invalid combination: neither all flag nor named integrations are set")
 	}
 
@@ -76,7 +77,7 @@ func (command *deleteCmdOptions) run(args []string) error {
 	if err != nil {
 		return err
 	}
-	if len(args) != 0 && !command.deleteAll {
+	if len(args) != 0 && !command.DeleteAll {
 		for _, arg := range args {
 			name := kubernetes.SanitizeName(arg)
 			err := DeleteIntegration(command.Context, c, name, command.Namespace)
@@ -90,7 +91,7 @@ func (command *deleteCmdOptions) run(args []string) error {
 				fmt.Println("Integration " + name + " deleted")
 			}
 		}
-	} else if command.deleteAll {
+	} else if command.DeleteAll {
 		integrationList := v1alpha1.IntegrationList{
 			TypeMeta: metav1.TypeMeta{
 				APIVersion: v1alpha1.SchemeGroupVersion.String(),
diff --git a/pkg/cmd/describe_integration.go b/pkg/cmd/describe_integration.go
index 117868f..25882f4 100644
--- a/pkg/cmd/describe_integration.go
+++ b/pkg/cmd/describe_integration.go
@@ -41,6 +41,7 @@ func newDescribeIntegrationCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		Aliases: []string{"it"},
 		Short:   "Describe an Integration",
 		Long:    `Describe an Integration.`,
+		PreRunE: decode(&impl),
 		RunE: func(_ *cobra.Command, args []string) error {
 			if err := impl.validate(args); err != nil {
 				return err
@@ -60,7 +61,7 @@ func newDescribeIntegrationCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 
 type describeIntegrationCommand struct {
 	*RootCmdOptions
-	showSourceContent bool
+	showSourceContent bool `mapstructure:"show-source-content"`
 }
 
 func (command *describeIntegrationCommand) validate(args []string) error {
diff --git a/pkg/cmd/describe_kit.go b/pkg/cmd/describe_kit.go
index c182650..a3ce855 100644
--- a/pkg/cmd/describe_kit.go
+++ b/pkg/cmd/describe_kit.go
@@ -34,9 +34,10 @@ func newDescribeKitCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	}
 
 	cmd := cobra.Command{
-		Use:   "kit",
-		Short: "Describe an Integration Kit",
-		Long:  `Describe an Integration Kit.`,
+		Use:     "kit",
+		Short:   "Describe an Integration Kit",
+		Long:    `Describe an Integration Kit.`,
+		PreRunE: decode(impl),
 		RunE: func(_ *cobra.Command, args []string) error {
 			if err := impl.validate(args); err != nil {
 				return err
diff --git a/pkg/cmd/describe_platform.go b/pkg/cmd/describe_platform.go
index 162a7a0..17c639b 100644
--- a/pkg/cmd/describe_platform.go
+++ b/pkg/cmd/describe_platform.go
@@ -34,9 +34,10 @@ func newDescribePlatformCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	}
 
 	cmd := cobra.Command{
-		Use:   "platform",
-		Short: "Describe an Integration Platform",
-		Long:  `Describe an Integration Platform.`,
+		Use:     "platform",
+		Short:   "Describe an Integration Platform",
+		Long:    `Describe an Integration Platform.`,
+		PreRunE: decode(impl),
 		RunE: func(_ *cobra.Command, args []string) error {
 			if err := impl.validate(args); err != nil {
 				return err
diff --git a/pkg/cmd/get.go b/pkg/cmd/get.go
index 6774065..d5dea19 100644
--- a/pkg/cmd/get.go
+++ b/pkg/cmd/get.go
@@ -39,10 +39,11 @@ func newCmdGet(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		RootCmdOptions: rootCmdOptions,
 	}
 	cmd := cobra.Command{
-		Use:   "get [integration]",
-		Short: "Get integrations deployed on Kubernetes",
-		Long:  `Get the status of integrations deployed on on Kubernetes.`,
-		RunE:  options.run,
+		Use:     "get [integration]",
+		Short:   "Get integrations deployed on Kubernetes",
+		Long:    `Get the status of integrations deployed on on Kubernetes.`,
+		PreRunE: decode(&options),
+		RunE:    options.run,
 	}
 
 	return &cmd
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index 56f8c33..bc10726 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -38,6 +38,7 @@ import (
 
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
 
 	corev1 "k8s.io/api/core/v1"
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
@@ -49,45 +50,53 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	}
 	cmd := cobra.Command{
 		Use:     "install",
-		Short:   "Install Camel K on a Kubernetes cluster",
+		Short:   "Installs Camel K on a Kubernetes cluster",
 		Long:    `Installs Camel K on a Kubernetes or OpenShift cluster.`,
-		PreRunE: impl.validate,
-		RunE:    impl.install,
+		PreRunE: impl.decode,
+		RunE: func(cmd *cobra.Command, args []string) error {
+			if err := impl.validate(cmd, args); err != nil {
+				return err
+			}
+			if err := impl.install(cmd, args); err != nil {
+				return err
+			}
+			return nil
+		},
 	}
 
-	cmd.Flags().BoolVarP(&impl.wait, "wait", "w", false, "Waits for the platform to be running")
-	cmd.Flags().BoolVar(&impl.clusterSetupOnly, "cluster-setup", false, "Execute cluster-wide operations only (may require admin rights)")
-	cmd.Flags().StringVar(&impl.clusterType, "cluster-type", "", "Set explicitly the cluster type to Kubernetes or OpenShift")
-	cmd.Flags().BoolVar(&impl.skipOperatorSetup, "skip-operator-setup", false, "Do not install the operator in the namespace (in case there's a global one)")
-	cmd.Flags().BoolVar(&impl.skipClusterSetup, "skip-cluster-setup", false, "Skip the cluster-setup phase")
-	cmd.Flags().BoolVar(&impl.exampleSetup, "example", false, "Install example integration")
-	cmd.Flags().BoolVar(&impl.global, "global", false, "Configure the operator to watch all namespaces. No integration platform is created.")
-
-	cmd.Flags().StringVarP(&impl.outputFormat, "output", "o", "", "Output format. One of: json|yaml")
-	cmd.Flags().StringVar(&impl.registry.Organization, "organization", "", "A organization on the Docker registry that can be used to publish images")
-	cmd.Flags().StringVar(&impl.registry.Address, "registry", "", "A Docker registry that can be used to publish images")
-	cmd.Flags().StringVar(&impl.registry.Secret, "registry-secret", "", "A secret used to push/pull images to the Docker registry")
-	cmd.Flags().BoolVar(&impl.registry.Insecure, "registry-insecure", false, "Configure to configure registry access in insecure mode or not")
-	cmd.Flags().StringVar(&impl.registryAuth.Server, "registry-auth-server", "", "The docker registry authentication server")
-	cmd.Flags().StringVar(&impl.registryAuth.Username, "registry-auth-username", "", "The docker registry authentication username")
-	cmd.Flags().StringVar(&impl.registryAuth.Password, "registry-auth-password", "", "The docker registry authentication password")
-	cmd.Flags().StringSliceVarP(&impl.properties, "property", "p", nil, "Add a camel property")
-	cmd.Flags().StringVar(&impl.camelVersion, "camel-version", "", "Set the camel version")
-	cmd.Flags().StringVar(&impl.runtimeVersion, "runtime-version", "", "Set the camel-k runtime version")
-	cmd.Flags().StringVar(&impl.baseImage, "base-image", "", "Set the base image used to run integrations")
-	cmd.Flags().StringVar(&impl.operatorImage, "operator-image", "", "Set the operator image used for the operator deployment")
-	cmd.Flags().StringSliceVar(&impl.kits, "kit", nil, "Add an integration kit to build at startup")
-	cmd.Flags().StringVar(&impl.buildStrategy, "build-strategy", "", "Set the build strategy")
-	cmd.Flags().StringVar(&impl.buildTimeout, "build-timeout", "", "Set how long the build process can last")
-	cmd.Flags().StringVar(&impl.traitProfile, "trait-profile", "", "The profile to use for traits")
-	cmd.Flags().BoolVar(&impl.kanikoBuildCache, "kaniko-build-cache", true, "To enable or disable the Kaniko Cache in building phase")
-	cmd.Flags().StringVar(&impl.httpProxySecret, "http-proxy-secret", "", "Configure the source of the secret holding HTTP proxy server details "+
+	cmd.Flags().BoolP("wait", "w", false, "Waits for the platform to be running")
+	cmd.Flags().Bool("cluster-setup", false, "Execute cluster-wide operations only (may require admin rights)")
+	cmd.Flags().String("cluster-type", "", "Set explicitly the cluster type to Kubernetes or OpenShift")
+	cmd.Flags().Bool("skip-operator-setup", false, "Do not install the operator in the namespace (in case there's a global one)")
+	cmd.Flags().Bool("skip-cluster-setup", false, "Skip the cluster-setup phase")
+	cmd.Flags().Bool("example", false, "Install example integration")
+	cmd.Flags().Bool("global", false, "Configure the operator to watch all namespaces. No integration platform is created.")
+
+	cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml")
+	cmd.Flags().String("organization", "", "A organization on the Docker registry that can be used to publish images")
+	cmd.Flags().String("registry", "", "A Docker registry that can be used to publish images")
+	cmd.Flags().String("registry-secret", "", "A secret used to push/pull images to the Docker registry")
+	cmd.Flags().Bool("registry-insecure", false, "Configure to configure registry access in insecure mode or not")
+	cmd.Flags().String("registry-auth-server", "", "The docker registry authentication server")
+	cmd.Flags().String("registry-auth-username", "", "The docker registry authentication username")
+	cmd.Flags().String("registry-auth-password", "", "The docker registry authentication password")
+	cmd.Flags().StringArrayP("property", "p", nil, "Add a camel property")
+	cmd.Flags().String("camel-version", "", "Set the camel version")
+	cmd.Flags().String("runtime-version", "", "Set the camel-k runtime version")
+	cmd.Flags().String("base-image", "", "Set the base Image used to run integrations")
+	cmd.Flags().String("operator-image", "", "Set the operator Image used for the operator deployment")
+	cmd.Flags().StringArray("kit", nil, "Add an integration kit to build at startup")
+	cmd.Flags().String("build-strategy", "", "Set the build strategy")
+	cmd.Flags().String("build-timeout", "", "Set how long the build process can last")
+	cmd.Flags().String("trait-profile", "", "The profile to use for traits")
+	cmd.Flags().Bool("kaniko-build-cache", true, "To enable or disable the Kaniko Cache in building phase")
+	cmd.Flags().String("http-proxy-secret", "", "Configure the source of the secret holding HTTP proxy server details "+
 		"(HTTP_PROXY|HTTPS_PROXY|NO_PROXY)")
 
 	// maven settings
-	cmd.Flags().StringVar(&impl.localRepository, "local-repository", "", "Location of the local maven repository")
-	cmd.Flags().StringVar(&impl.mavenSettings, "maven-settings", "", "Configure the source of the maven settings (configmap|secret:name[/key])")
-	cmd.Flags().StringSliceVar(&impl.mavenRepositories, "maven-repository", nil, "Add a maven repository")
+	cmd.Flags().String("local-repository", "", "Location of the local maven repository")
+	cmd.Flags().String("maven-settings", "", "Configure the source of the maven settings (configmap|secret:name[/key])")
+	cmd.Flags().StringArray("maven-repository", nil, "Add a maven repository")
 
 	// completion support
 	configureBashAnnotationForFlag(
@@ -103,40 +112,41 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command {
 
 type installCmdOptions struct {
 	*RootCmdOptions
-	wait              bool
-	clusterSetupOnly  bool
-	skipOperatorSetup bool
-	skipClusterSetup  bool
-	exampleSetup      bool
-	global            bool
-	kanikoBuildCache  bool
-	clusterType       string
-	outputFormat      string
-	camelVersion      string
-	runtimeVersion    string
-	baseImage         string
-	operatorImage     string
-	localRepository   string
-	buildStrategy     string
-	buildTimeout      string
-	mavenRepositories []string
-	mavenSettings     string
-	properties        []string
-	kits              []string
-	registry          v1alpha1.IntegrationPlatformRegistrySpec
-	registryAuth      registry.Auth
-	traitProfile      string
-	httpProxySecret   string
+	Wait              bool     `mapstructure:"wait"`
+	ClusterSetupOnly  bool     `mapstructure:"cluster-setup"`
+	SkipOperatorSetup bool     `mapstructure:"skip-operator-setup"`
+	SkipClusterSetup  bool     `mapstructure:"skip-cluster-setup"`
+	ExampleSetup      bool     `mapstructure:"example"`
+	Global            bool     `mapstructure:"global"`
+	KanikoBuildCache  bool     `mapstructure:"kaniko-build-cache"`
+	ClusterType       string   `mapstructure:"cluster-type"`
+	OutputFormat      string   `mapstructure:"output"`
+	CamelVersion      string   `mapstructure:"camel-version"`
+	RuntimeVersion    string   `mapstructure:"runtime-version"`
+	BaseImage         string   `mapstructure:"base-image"`
+	OperatorImage     string   `mapstructure:"operator-image"`
+	LocalRepository   string   `mapstructure:"local-repository"`
+	BuildStrategy     string   `mapstructure:"build-strategy"`
+	BuildTimeout      string   `mapstructure:"build-timeout"`
+	MavenRepositories []string `mapstructure:"maven-repositories"`
+	MavenSettings     string   `mapstructure:"maven-settings"`
+	Properties        []string `mapstructure:"properties"`
+	Kits              []string `mapstructure:"kits"`
+	TraitProfile      string   `mapstructure:"trait-profile"`
+	HTTPProxySecret   string   `mapstructure:"http-proxy-secret"`
+
+	registry     v1alpha1.IntegrationPlatformRegistrySpec
+	registryAuth registry.Auth
 }
 
 // nolint: gocyclo
-func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
+func (o *installCmdOptions) install(_ *cobra.Command, _ []string) error {
 	var collection *kubernetes.Collection
-	if o.outputFormat != "" {
+	if o.OutputFormat != "" {
 		collection = kubernetes.NewCollection()
 	}
 
-	if !o.skipClusterSetup {
+	if !o.SkipClusterSetup {
 		// Let's use a client provider during cluster installation, to eliminate the problem of CRD object caching
 		clientProvider := client.Provider{Get: o.NewCmdClient}
 
@@ -151,7 +161,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 		}
 	}
 
-	if o.clusterSetupOnly {
+	if o.ClusterSetupOnly {
 		if collection == nil {
 			fmt.Println("Camel K cluster setup completed successfully")
 		}
@@ -163,12 +173,12 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 
 		namespace := o.Namespace
 
-		if !o.skipOperatorSetup {
+		if !o.SkipOperatorSetup {
 			cfg := install.OperatorConfiguration{
-				CustomImage: o.operatorImage,
+				CustomImage: o.OperatorImage,
 				Namespace:   namespace,
-				Global:      o.global,
-				ClusterType: o.clusterType,
+				Global:      o.Global,
+				ClusterType: o.ClusterType,
 			}
 			err = install.OperatorOrCollect(o.Context, c, cfg, collection)
 			if err != nil {
@@ -188,7 +198,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 			}
 		}
 
-		platform, err := install.PlatformOrCollect(o.Context, c, o.clusterType, namespace, o.registry, collection)
+		platform, err := install.PlatformOrCollect(o.Context, c, o.ClusterType, namespace, o.registry, collection)
 		if err != nil {
 			return err
 		}
@@ -197,10 +207,10 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 			platform.Spec.Build.Registry.Secret = generatedSecretName
 		}
 
-		if len(o.properties) > 0 {
+		if len(o.Properties) > 0 {
 			platform.Spec.Build.Properties = make(map[string]string)
 
-			for _, property := range o.properties {
+			for _, property := range o.Properties {
 				kv := strings.Split(property, "=")
 
 				if len(kv) == 2 {
@@ -208,20 +218,20 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 				}
 			}
 		}
-		if o.localRepository != "" {
-			platform.Spec.Build.Maven.LocalRepository = o.localRepository
+		if o.LocalRepository != "" {
+			platform.Spec.Build.Maven.LocalRepository = o.LocalRepository
 		}
-		if o.camelVersion != "" {
-			platform.Spec.Build.CamelVersion = o.camelVersion
+		if o.CamelVersion != "" {
+			platform.Spec.Build.CamelVersion = o.CamelVersion
 		}
-		if o.runtimeVersion != "" {
-			platform.Spec.Build.RuntimeVersion = o.runtimeVersion
+		if o.RuntimeVersion != "" {
+			platform.Spec.Build.RuntimeVersion = o.RuntimeVersion
 		}
-		if o.baseImage != "" {
-			platform.Spec.Build.BaseImage = o.baseImage
+		if o.BaseImage != "" {
+			platform.Spec.Build.BaseImage = o.BaseImage
 		}
-		if o.buildStrategy != "" {
-			switch s := o.buildStrategy; s {
+		if o.BuildStrategy != "" {
+			switch s := o.BuildStrategy; s {
 			case v1alpha1.IntegrationPlatformBuildStrategyPod:
 				platform.Spec.Build.BuildStrategy = v1alpha1.IntegrationPlatformBuildStrategyPod
 			case v1alpha1.IntegrationPlatformBuildStrategyRoutine:
@@ -230,8 +240,8 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 				return fmt.Errorf("unknown build strategy: %s", s)
 			}
 		}
-		if o.buildTimeout != "" {
-			d, err := time.ParseDuration(o.buildTimeout)
+		if o.BuildTimeout != "" {
+			d, err := time.ParseDuration(o.BuildTimeout)
 			if err != nil {
 				return err
 			}
@@ -240,54 +250,52 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 				Duration: d,
 			}
 		}
-		if o.traitProfile != "" {
-			platform.Spec.Profile = v1alpha1.TraitProfileByName(o.traitProfile)
+		if o.TraitProfile != "" {
+			platform.Spec.Profile = v1alpha1.TraitProfileByName(o.TraitProfile)
 		}
 
-		if len(o.mavenRepositories) > 0 {
-			for _, r := range o.mavenRepositories {
+		if len(o.MavenRepositories) > 0 {
+			for _, r := range o.MavenRepositories {
 				platform.AddConfiguration("repository", r)
 			}
 		}
 
-		if o.mavenSettings != "" {
-			mavenSettings, err := decodeMavenSettings(o.mavenSettings)
+		if o.MavenSettings != "" {
+			mavenSettings, err := decodeMavenSettings(o.MavenSettings)
 			if err != nil {
 				return err
 			}
 			platform.Spec.Build.Maven.Settings = mavenSettings
 		}
 
-		if o.httpProxySecret != "" {
-			platform.Spec.Build.HTTPProxySecret = o.httpProxySecret
+		if o.HTTPProxySecret != "" {
+			platform.Spec.Build.HTTPProxySecret = o.HTTPProxySecret
 		}
 
-		if o.clusterType != "" {
+		if o.ClusterType != "" {
 			for _, c := range v1alpha1.AllIntegrationPlatformClusters {
-				if strings.EqualFold(string(c), o.clusterType) {
+				if strings.EqualFold(string(c), o.ClusterType) {
 					platform.Spec.Cluster = c
 				}
 			}
 		}
 
-		kanikoBuildCacheFlag := cobraCmd.Flags().Lookup("kaniko-build-cache")
-
-		if kanikoBuildCacheFlag.Changed {
-			platform.Spec.Build.KanikoBuildCache = &o.kanikoBuildCache
+		if !o.KanikoBuildCache {
+			platform.Spec.Build.KanikoBuildCache = &o.KanikoBuildCache
 		}
 
-		platform.Spec.Resources.Kits = o.kits
+		platform.Spec.Resources.Kits = o.Kits
 
 		// Do not create an integration platform in global mode as platforms are expected
 		// to be created in other namespaces
-		if !o.global {
+		if !o.Global {
 			err = install.RuntimeObjectOrCollect(o.Context, c, namespace, collection, platform)
 			if err != nil {
 				return err
 			}
 		}
 
-		if o.exampleSetup {
+		if o.ExampleSetup {
 			err = install.ExampleOrCollect(o.Context, c, namespace, collection)
 			if err != nil {
 				return err
@@ -295,14 +303,14 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 		}
 
 		if collection == nil {
-			if o.wait {
+			if o.Wait {
 				err = o.waitForPlatformReady(platform)
 				if err != nil {
 					return err
 				}
 			}
 
-			if o.global {
+			if o.Global {
 				fmt.Println("Camel K installed in namespace", namespace, "(global mode)")
 			} else {
 				fmt.Println("Camel K installed in namespace", namespace)
@@ -319,7 +327,7 @@ func (o *installCmdOptions) install(cobraCmd *cobra.Command, _ []string) error {
 
 func (o *installCmdOptions) printOutput(collection *kubernetes.Collection) error {
 	lst := collection.AsKubernetesList()
-	switch o.outputFormat {
+	switch o.OutputFormat {
 	case "yaml":
 		data, err := kubernetes.ToYAML(lst)
 		if err != nil {
@@ -333,7 +341,7 @@ func (o *installCmdOptions) printOutput(collection *kubernetes.Collection) error
 		}
 		fmt.Print(string(data))
 	default:
-		return errors.New("unknown output format: " + o.outputFormat)
+		return errors.New("unknown output format: " + o.OutputFormat)
 	}
 	return nil
 }
@@ -360,6 +368,23 @@ func (o *installCmdOptions) waitForPlatformReady(platform *v1alpha1.IntegrationP
 	return watch.HandlePlatformStateChanges(o.Context, platform, handler)
 }
 
+func (o *installCmdOptions) decode(cmd *cobra.Command, _ []string) error {
+	path := pathToRoot(cmd)
+	if err := decodeKey(o, path); err != nil {
+		return err
+	}
+
+	o.registry.Address = viper.GetString(path + ".registry")
+	o.registry.Organization = viper.GetString(path + ".organization")
+	o.registry.Secret = viper.GetString(path + ".registry-secret")
+	o.registry.Insecure = viper.GetBool(path + ".registry-insecure")
+	o.registryAuth.Username = viper.GetString(path + ".registry-auth-username")
+	o.registryAuth.Password = viper.GetString(path + ".registry-auth-password")
+	o.registryAuth.Server = viper.GetString(path + ".registry-auth-server")
+
+	return nil
+}
+
 func (o *installCmdOptions) validate(_ *cobra.Command, _ []string) error {
 	var result error
 
@@ -369,20 +394,20 @@ func (o *installCmdOptions) validate(_ *cobra.Command, _ []string) error {
 		return err
 	}
 
-	for _, kit := range o.kits {
+	for _, kit := range o.Kits {
 		err := errorIfKitIsNotAvailable(schema, kit)
 		result = multierr.Append(result, err)
 	}
 
-	if len(o.mavenRepositories) > 0 && o.mavenSettings != "" {
+	if len(o.MavenRepositories) > 0 && o.MavenSettings != "" {
 		err := fmt.Errorf("incompatible options combinations: you cannot set both mavenRepository and mavenSettings")
 		result = multierr.Append(result, err)
 	}
 
-	if o.traitProfile != "" {
-		tp := v1alpha1.TraitProfileByName(o.traitProfile)
+	if o.TraitProfile != "" {
+		tp := v1alpha1.TraitProfileByName(o.TraitProfile)
 		if tp == v1alpha1.TraitProfile("") {
-			err := fmt.Errorf("unknown trait profile %s", o.traitProfile)
+			err := fmt.Errorf("unknown trait profile %s", o.TraitProfile)
 			result = multierr.Append(result, err)
 		}
 	}
diff --git a/pkg/cmd/kit_create.go b/pkg/cmd/kit_create.go
index f9475ef..3f66c2f 100644
--- a/pkg/cmd/kit_create.go
+++ b/pkg/cmd/kit_create.go
@@ -22,14 +22,13 @@ import (
 	"fmt"
 	"strings"
 
+	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/trait"
-
 	"github.com/apache/camel-k/pkg/util"
-
-	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/util/kubernetes"
 
 	"github.com/spf13/cobra"
+
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
@@ -40,20 +39,21 @@ func newKitCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	}
 
 	cmd := cobra.Command{
-		Use:   "create <name>",
-		Short: "Create an Integration Kit",
-		Long:  `Create an Integration Kit.`,
-		Args:  impl.validateArgs,
-		RunE:  impl.run,
-	}
-
-	cmd.Flags().StringVar(&impl.image, "image", "", "Image used to create the kit")
-	cmd.Flags().StringSliceVarP(&impl.dependencies, "dependency", "d", nil, "Add a dependency")
-	cmd.Flags().StringSliceVarP(&impl.properties, "property", "p", nil, "Add a camel property")
-	cmd.Flags().StringSliceVar(&impl.configmaps, "configmap", nil, "Add a ConfigMap")
-	cmd.Flags().StringSliceVar(&impl.secrets, "secret", nil, "Add a Secret")
-	cmd.Flags().StringSliceVar(&impl.repositories, "repository", nil, "Add a maven repository")
-	cmd.Flags().StringSliceVarP(&impl.traits, "trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"")
+		Use:     "create <name>",
+		Short:   "Create an Integration Kit",
+		Long:    `Create an Integration Kit.`,
+		Args:    impl.validateArgs,
+		PreRunE: decode(impl),
+		RunE:    impl.run,
+	}
+
+	cmd.Flags().String("image", "", "Image used to create the kit")
+	cmd.Flags().StringArrayP("dependency", "d", nil, "Add a dependency")
+	cmd.Flags().StringArrayP("property", "p", nil, "Add a camel property")
+	cmd.Flags().StringArray("configmap", nil, "Add a ConfigMap")
+	cmd.Flags().StringArray("secret", nil, "Add a Secret")
+	cmd.Flags().StringArray("repository", nil, "Add a maven repository")
+	cmd.Flags().StringArrayP("trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"")
 
 	// completion support
 	configureKnownCompletions(&cmd)
@@ -64,13 +64,13 @@ func newKitCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 type kitCreateCommand struct {
 	*RootCmdOptions
 
-	image        string
-	dependencies []string
-	properties   []string
-	configmaps   []string
-	secrets      []string
-	repositories []string
-	traits       []string
+	Image        string   `mapstructure:"image"`
+	Dependencies []string `mapstructure:"dependencies"`
+	Properties   []string `mapstructure:"properties"`
+	Configmaps   []string `mapstructure:"configmaps"`
+	Secrets      []string `mapstructure:"secrets"`
+	Repositories []string `mapstructure:"repositories"`
+	Traits       []string `mapstructure:"traits"`
 }
 
 func (command *kitCreateCommand) validateArgs(_ *cobra.Command, args []string) error {
@@ -89,7 +89,7 @@ func (command *kitCreateCommand) run(_ *cobra.Command, args []string) error {
 
 	catalog := trait.NewCatalog(command.Context, c)
 	tp := catalog.ComputeTraitsProperties()
-	for _, t := range command.traits {
+	for _, t := range command.Traits {
 		kv := strings.SplitN(t, "=", 2)
 
 		if !util.StringSliceExists(tp, kv[0]) {
@@ -118,25 +118,25 @@ func (command *kitCreateCommand) run(_ *cobra.Command, args []string) error {
 		"camel.apache.org/kit.type": v1alpha1.IntegrationKitTypeUser,
 	}
 	ctx.Spec = v1alpha1.IntegrationKitSpec{
-		Dependencies:  make([]string, 0, len(command.dependencies)),
+		Dependencies:  make([]string, 0, len(command.Dependencies)),
 		Configuration: make([]v1alpha1.ConfigurationSpec, 0),
-		Repositories:  command.repositories,
+		Repositories:  command.Repositories,
 	}
 
-	if command.image != "" {
+	if command.Image != "" {
 		//
-		// if the image is set, the kit do not require any build but
+		// if the Image is set, the kit do not require any build but
 		// is be marked as external as the information about the classpath
-		// is missing so it cannot be used as base for other kits
+		// is missing so it cannot be used as base for other Kits
 		//
 		ctx.Labels["camel.apache.org/kit.type"] = v1alpha1.IntegrationKitTypeExternal
 
 		//
-		// Set the image to be used by the kit
+		// Set the Image to be used by the kit
 		//
-		ctx.Spec.Image = command.image
+		ctx.Spec.Image = command.Image
 	}
-	for _, item := range command.dependencies {
+	for _, item := range command.Dependencies {
 		switch {
 		case strings.HasPrefix(item, "mvn:"):
 			ctx.Spec.Dependencies = append(ctx.Spec.Dependencies, item)
@@ -149,25 +149,25 @@ func (command *kitCreateCommand) run(_ *cobra.Command, args []string) error {
 		}
 	}
 
-	for _, item := range command.properties {
+	for _, item := range command.Properties {
 		ctx.Spec.Configuration = append(ctx.Spec.Configuration, v1alpha1.ConfigurationSpec{
 			Type:  "property",
 			Value: item,
 		})
 	}
-	for _, item := range command.configmaps {
+	for _, item := range command.Configmaps {
 		ctx.Spec.Configuration = append(ctx.Spec.Configuration, v1alpha1.ConfigurationSpec{
 			Type:  "configmap",
 			Value: item,
 		})
 	}
-	for _, item := range command.secrets {
+	for _, item := range command.Secrets {
 		ctx.Spec.Configuration = append(ctx.Spec.Configuration, v1alpha1.ConfigurationSpec{
 			Type:  "secret",
 			Value: item,
 		})
 	}
-	for _, item := range command.traits {
+	for _, item := range command.Traits {
 		if err := command.configureTrait(&ctx, item); err != nil {
 			return nil
 		}
diff --git a/pkg/cmd/kit_delete.go b/pkg/cmd/kit_delete.go
index 0d24172..7902fae 100644
--- a/pkg/cmd/kit_delete.go
+++ b/pkg/cmd/kit_delete.go
@@ -35,9 +35,10 @@ func newKitDeleteCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	}
 
 	cmd := cobra.Command{
-		Use:   "delete",
-		Short: "Delete an Integration Kit",
-		Long:  `Delete an Integration Kit.`,
+		Use:     "delete",
+		Short:   "Delete an Integration Kit",
+		Long:    `Delete an Integration Kit.`,
+		PreRunE: decode(&impl),
 		RunE: func(_ *cobra.Command, args []string) error {
 			if err := impl.validate(args); err != nil {
 				return err
@@ -50,22 +51,22 @@ func newKitDeleteCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		},
 	}
 
-	cmd.Flags().BoolVar(&impl.all, "all", false, "Delete all integration kits")
+	cmd.Flags().Bool("all", false, "Delete all integration Kits")
 
 	return &cmd
 }
 
 type kitDeleteCommand struct {
 	*RootCmdOptions
-	all bool
+	All bool `mapstructure:"all"`
 }
 
 func (command *kitDeleteCommand) validate(args []string) error {
-	if command.all && len(args) > 0 {
-		return errors.New("invalid combination: both all flag and named kits are set")
+	if command.All && len(args) > 0 {
+		return errors.New("invalid combination: both all flag and named Kits are set")
 	}
-	if !command.all && len(args) == 0 {
-		return errors.New("invalid combination: neither all flag nor named kits are set")
+	if !command.All && len(args) == 0 {
+		return errors.New("invalid combination: neither all flag nor named Kits are set")
 	}
 
 	return nil
@@ -79,7 +80,7 @@ func (command *kitDeleteCommand) run(args []string) error {
 		return err
 	}
 
-	if command.all {
+	if command.All {
 		kitList := v1alpha1.NewIntegrationKitList()
 		if err := c.List(command.Context, &kitList, k8sclient.InNamespace(command.Namespace)); err != nil {
 			return err
@@ -87,7 +88,7 @@ func (command *kitDeleteCommand) run(args []string) error {
 
 		names = make([]string, 0, len(kitList.Items))
 		for _, item := range kitList.Items {
-			// only include non platform kits
+			// only include non platform Kits
 			if item.Labels["camel.apache.org/kit.type"] != v1alpha1.IntegrationKitTypePlatform {
 				names = append(names, item.Name)
 			}
@@ -129,8 +130,8 @@ func (command *kitDeleteCommand) delete(name string) error {
 	// check that it is not a platform one which is supposed to be "read only"
 	// thus not managed by the end user
 	if ctx.Labels["camel.apache.org/kit.type"] == v1alpha1.IntegrationKitTypePlatform {
-		// skip platform kits while deleting all kits
-		if command.all {
+		// skip platform Kits while deleting all Kits
+		if command.All {
 			return nil
 		}
 
diff --git a/pkg/cmd/kit_get.go b/pkg/cmd/kit_get.go
index 9d7f109..a22af7b 100644
--- a/pkg/cmd/kit_get.go
+++ b/pkg/cmd/kit_get.go
@@ -34,9 +34,10 @@ func newKitGetCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	}
 
 	cmd := cobra.Command{
-		Use:   "get",
-		Short: "Get defined Integration Kit",
-		Long:  `Get defined Integration Kit.`,
+		Use:     "get",
+		Short:   "Get defined Integration Kit",
+		Long:    `Get defined Integration Kit.`,
+		PreRunE: decode(&impl),
 		RunE: func(cmd *cobra.Command, args []string) error {
 			if err := impl.validate(cmd, args); err != nil {
 				return err
@@ -49,18 +50,18 @@ func newKitGetCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		},
 	}
 
-	cmd.Flags().BoolVar(&impl.user, v1alpha1.IntegrationKitTypeUser, true, "Includes user kits")
-	cmd.Flags().BoolVar(&impl.external, v1alpha1.IntegrationKitTypeExternal, true, "Includes external kits")
-	cmd.Flags().BoolVar(&impl.platform, v1alpha1.IntegrationKitTypePlatform, true, "Includes platform kits")
+	cmd.Flags().Bool(v1alpha1.IntegrationKitTypeUser, true, "Includes user Kits")
+	cmd.Flags().Bool(v1alpha1.IntegrationKitTypeExternal, true, "Includes external Kits")
+	cmd.Flags().Bool(v1alpha1.IntegrationKitTypePlatform, true, "Includes platform Kits")
 
 	return &cmd
 }
 
 type kitGetCommand struct {
 	*RootCmdOptions
-	user     bool
-	external bool
-	platform bool
+	User     bool `mapstructure:"user"`
+	External bool `mapstructure:"external"`
+	Platform bool `mapstructure:"platform"`
 }
 
 func (command *kitGetCommand) validate(cmd *cobra.Command, args []string) error {
@@ -81,9 +82,9 @@ func (command *kitGetCommand) run(cmd *cobra.Command) error {
 	fmt.Fprintln(w, "NAME\tPHASE\tTYPE\tIMAGE")
 	for _, ctx := range kitList.Items {
 		t := ctx.Labels["camel.apache.org/kit.type"]
-		u := command.user && t == v1alpha1.IntegrationKitTypeUser
-		e := command.external && t == v1alpha1.IntegrationKitTypeExternal
-		p := command.platform && t == v1alpha1.IntegrationKitTypePlatform
+		u := command.User && t == v1alpha1.IntegrationKitTypeUser
+		e := command.External && t == v1alpha1.IntegrationKitTypeExternal
+		p := command.Platform && t == v1alpha1.IntegrationKitTypePlatform
 
 		if u || e || p {
 			fmt.Fprintf(w, "%s\t%s\t%s\t%s\n", ctx.Name, string(ctx.Status.Phase), t, ctx.Status.Image)
diff --git a/pkg/cmd/log.go b/pkg/cmd/log.go
index 151c8aa..852c9c3 100644
--- a/pkg/cmd/log.go
+++ b/pkg/cmd/log.go
@@ -33,11 +33,12 @@ func newCmdLog(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	}
 
 	cmd := cobra.Command{
-		Use:   "log integration",
-		Short: "Print the logs of an integration",
-		Long:  `Print the logs of an integration.`,
-		Args:  options.validate,
-		RunE:  options.run,
+		Use:     "log integration",
+		Short:   "Print the logs of an integration",
+		Long:    `Print the logs of an integration.`,
+		Args:    options.validate,
+		PreRunE: decode(&options),
+		RunE:    options.run,
 	}
 
 	// completion support
@@ -85,7 +86,7 @@ func (o *logCmdOptions) run(cmd *cobra.Command, args []string) error {
 		return err
 	}
 
-	// Let's add a wait point, otherwise the script terminates
+	// Let's add a Wait point, otherwise the script terminates
 	<-o.Context.Done()
 
 	return nil
diff --git a/pkg/cmd/operator.go b/pkg/cmd/operator.go
index a1a70c2..87361fd 100644
--- a/pkg/cmd/operator.go
+++ b/pkg/cmd/operator.go
@@ -22,25 +22,16 @@ import (
 	"github.com/spf13/cobra"
 )
 
-func newCmdOperator(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	impl := operatorCmdOptions{
-		RootCmdOptions: rootCmdOptions,
-	}
+func newCmdOperator() *cobra.Command {
 	cmd := cobra.Command{
 		Use:    "operator",
 		Short:  "Run the Camel K operator",
 		Long:   `Run the Camel K operator`,
 		Hidden: true,
-		Run:    impl.run,
+		Run: func(cmd *cobra.Command, args []string) {
+			operator.Run()
+		},
 	}
 
 	return &cmd
 }
-
-type operatorCmdOptions struct {
-	*RootCmdOptions
-}
-
-func (o *operatorCmdOptions) run(_ *cobra.Command, _ []string) {
-	operator.Run()
-}
diff --git a/pkg/cmd/rebuild.go b/pkg/cmd/rebuild.go
index c906b90..d88738a 100644
--- a/pkg/cmd/rebuild.go
+++ b/pkg/cmd/rebuild.go
@@ -34,10 +34,11 @@ func newCmdRebuild(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		RootCmdOptions: rootCmdOptions,
 	}
 	cmd := cobra.Command{
-		Use:   "rebuild [integration]",
-		Short: "Clear the state of integrations to rebuild them",
-		Long:  `Clear the state of one or more integrations causing a rebuild.`,
-		RunE:  options.rebuild,
+		Use:     "rebuild [integration]",
+		Short:   "Clear the state of integrations to rebuild them",
+		Long:    `Clear the state of one or more integrations causing a rebuild.`,
+		PreRunE: decode(&options),
+		RunE:    options.rebuild,
 	}
 
 	return &cmd
diff --git a/pkg/cmd/reset.go b/pkg/cmd/reset.go
index ff9c86d..02bd058 100644
--- a/pkg/cmd/reset.go
+++ b/pkg/cmd/reset.go
@@ -34,22 +34,23 @@ func newCmdReset(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		RootCmdOptions: rootCmdOptions,
 	}
 	cmd := cobra.Command{
-		Use:   "reset",
-		Short: "Reset the Camel K installation",
-		Long:  `Reset the Camel K installation by deleting everything except current platform configuration.`,
-		Run:   options.reset,
+		Use:     "reset",
+		Short:   "Reset the Camel K installation",
+		Long:    `Reset the Camel K installation by deleting everything except current platform configuration.`,
+		PreRunE: decode(&options),
+		Run:     options.reset,
 	}
 
-	cmd.Flags().BoolVar(&options.SkipKits, "skip-kits", false, "Do not delete the integration kits")
-	cmd.Flags().BoolVar(&options.SkipIntegrations, "skip-integrations", false, "Do not delete the integrations")
+	cmd.Flags().Bool("skip-kits", false, "Do not delete the integration kits")
+	cmd.Flags().Bool("skip-integrations", false, "Do not delete the integrations")
 
 	return &cmd
 }
 
 type resetCmdOptions struct {
 	*RootCmdOptions
-	SkipKits         bool
-	SkipIntegrations bool
+	SkipKits         bool `mapstructure:"skip-kits"`
+	SkipIntegrations bool `mapstructure:"skip-integrations"`
 }
 
 func (o *resetCmdOptions) reset(_ *cobra.Command, _ []string) {
@@ -73,7 +74,7 @@ func (o *resetCmdOptions) reset(_ *cobra.Command, _ []string) {
 			fmt.Print(err)
 			return
 		}
-		fmt.Printf("%d integration kits deleted from namespace %s\n", n, o.Namespace)
+		fmt.Printf("%d integration Kits deleted from namespace %s\n", n, o.Namespace)
 	}
 
 	if err = o.resetIntegrationPlatform(c); err != nil {
@@ -101,7 +102,7 @@ func (o *resetCmdOptions) deleteAllIntegrations(c client.Client) (int, error) {
 func (o *resetCmdOptions) deleteAllIntegrationKits(c client.Client) (int, error) {
 	list := v1alpha1.NewIntegrationKitList()
 	if err := c.List(o.Context, &list, k8sclient.InNamespace(o.Namespace)); err != nil {
-		return 0, errors.Wrap(err, fmt.Sprintf("could not retrieve integration kits from namespace %s", o.Namespace))
+		return 0, errors.Wrap(err, fmt.Sprintf("could not retrieve integration Kits from namespace %s", o.Namespace))
 	}
 	for _, i := range list.Items {
 		kit := i
diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go
index c5b9168..bbf7acc 100644
--- a/pkg/cmd/root.go
+++ b/pkg/cmd/root.go
@@ -20,6 +20,9 @@ package cmd
 import (
 	"context"
 	"os"
+	"strings"
+
+	"github.com/spf13/viper"
 
 	"github.com/apache/camel-k/pkg/client"
 	"github.com/pkg/errors"
@@ -32,10 +35,10 @@ superpowers.
 
 // RootCmdOptions --
 type RootCmdOptions struct {
-	Context    context.Context
-	_client    client.Client
-	KubeConfig string
-	Namespace  string
+	Context    context.Context `mapstructure:"-"`
+	_client    client.Client   `mapstructure:"-"`
+	KubeConfig string          `mapstructure:"kube-config"`
+	Namespace  string          `mapstructure:"namespace"`
 }
 
 // NewKamelCommand --
@@ -65,9 +68,31 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, error) {
 	cmd.AddCommand(newCmdReset(&options))
 	cmd.AddCommand(newCmdDescribe(&options))
 	cmd.AddCommand(newCmdRebuild(&options))
-	cmd.AddCommand(newCmdOperator(&options))
+	cmd.AddCommand(newCmdOperator())
 	cmd.AddCommand(newCmdBuilder(&options))
 
+	bindPFlagsHierarchy(&cmd)
+
+	configName := os.Getenv("KAMEL_CONFIG_NAME")
+	if configName != "" {
+		configName = "config"
+	}
+
+	viper.SetConfigName(configName)
+	viper.AddConfigPath(".kamel")
+	viper.AddConfigPath("$HOME/.kamel")
+	viper.AutomaticEnv()
+	viper.SetEnvKeyReplacer(strings.NewReplacer(
+		".", "_",
+		"-", "_",
+	))
+
+	if err := viper.ReadInConfig(); err != nil {
+		if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
+			return nil, err
+		}
+	}
+
 	return &cmd, nil
 }
 
diff --git a/pkg/cmd/operator.go b/pkg/cmd/root_test.go
similarity index 59%
copy from pkg/cmd/operator.go
copy to pkg/cmd/root_test.go
index a1a70c2..57f6621 100644
--- a/pkg/cmd/operator.go
+++ b/pkg/cmd/root_test.go
@@ -17,30 +17,7 @@ limitations under the License.
 
 package cmd
 
-import (
-	"github.com/apache/camel-k/pkg/cmd/operator"
-	"github.com/spf13/cobra"
-)
+import "testing"
 
-func newCmdOperator(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	impl := operatorCmdOptions{
-		RootCmdOptions: rootCmdOptions,
-	}
-	cmd := cobra.Command{
-		Use:    "operator",
-		Short:  "Run the Camel K operator",
-		Long:   `Run the Camel K operator`,
-		Hidden: true,
-		Run:    impl.run,
-	}
-
-	return &cmd
-}
-
-type operatorCmdOptions struct {
-	*RootCmdOptions
-}
-
-func (o *operatorCmdOptions) run(_ *cobra.Command, _ []string) {
-	operator.Run()
+func TestDecodeRoot(t *testing.T) {
 }
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index 31b411c..4c41081 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -40,8 +40,10 @@ import (
 	k8slog "github.com/apache/camel-k/pkg/util/kubernetes/log"
 	"github.com/apache/camel-k/pkg/util/sync"
 	"github.com/apache/camel-k/pkg/util/watch"
+
 	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
+
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -57,34 +59,34 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	}
 
 	cmd := cobra.Command{
-		Use:   "run [file to run]",
-		Short: "Run a integration on Kubernetes",
-		Long:  `Deploys and execute a integration pod on Kubernetes.`,
-		Args:  options.validateArgs,
-		RunE:  options.run,
-	}
-
-	cmd.Flags().StringVar(&options.IntegrationName, "name", "", "The integration name")
-	cmd.Flags().StringSliceVarP(&options.Dependencies, "dependency", "d", nil, "The integration dependency")
-	cmd.Flags().BoolVarP(&options.Wait, "wait", "w", false, "Waits for the integration to be running")
-	cmd.Flags().StringVarP(&options.IntegrationKit, "kit", "k", "", "The kit used to run the integration")
-	cmd.Flags().StringArrayVarP(&options.Properties, "property", "p", nil, "Add a camel property")
-	cmd.Flags().StringSliceVar(&options.ConfigMaps, "configmap", nil, "Add a ConfigMap")
-	cmd.Flags().StringSliceVar(&options.Secrets, "secret", nil, "Add a Secret")
-	cmd.Flags().StringSliceVar(&options.Repositories, "repository", nil, "Add a maven repository")
-	cmd.Flags().BoolVar(&options.Logs, "logs", false, "Print integration logs")
-	cmd.Flags().BoolVar(&options.Sync, "sync", false, "Synchronize the local source file with the cluster, republishing at each change")
-	cmd.Flags().BoolVar(&options.Dev, "dev", false, "Enable Dev mode (equivalent to \"-w --logs --sync\")")
-	cmd.Flags().StringVar(&options.Profile, "profile", "", "Trait profile used for deployment")
-	cmd.Flags().StringSliceVarP(&options.Traits, "trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"")
-	cmd.Flags().StringSliceVar(&options.LoggingLevels, "logging-level", nil, "Configure the logging level. "+
-		"E.g. \"--logging-level org.apache.camel=DEBUG\"")
-	cmd.Flags().StringVarP(&options.OutputFormat, "output", "o", "", "Output format. One of: json|yaml")
-	cmd.Flags().BoolVar(&options.Compression, "compression", false, "Enable store source as a compressed binary blob")
-	cmd.Flags().StringSliceVar(&options.Resources, "resource", nil, "Add a resource")
-	cmd.Flags().StringSliceVar(&options.OpenAPIs, "open-api", nil, "Add an OpenAPI v2 spec")
-	cmd.Flags().StringSliceVarP(&options.Volumes, "volume", "v", nil, "Mount a volume into the integration container. E.g \"-v pvcname:/container/path\"")
-	cmd.Flags().StringSliceVarP(&options.EnvVars, "env", "e", nil, "Set an environment variable in the integration container. E.g \"-e MY_VAR=my-value\"")
+		Use:     "run [file to run]",
+		Short:   "Run a integration on Kubernetes",
+		Long:    `Deploys and execute a integration pod on Kubernetes.`,
+		Args:    options.validateArgs,
+		PreRunE: decode(&options),
+		RunE:    options.run,
+	}
+
+	cmd.Flags().String("name", "", "The integration name")
+	cmd.Flags().StringArrayP("dependency", "d", nil, "The integration dependency")
+	cmd.Flags().BoolP("wait", "w", false, "Waits 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 camel property")
+	cmd.Flags().StringArray("configmap", nil, "Add a ConfigMap")
+	cmd.Flags().StringArray("secret", nil, "Add a Secret")
+	cmd.Flags().StringArray("maven-repository", nil, "Add a maven repository")
+	cmd.Flags().Bool("logs", false, "Print integration logs")
+	cmd.Flags().Bool("sync", false, "Synchronize the local source file with the cluster, republishing at each change")
+	cmd.Flags().Bool("dev", false, "Enable Dev mode (equivalent to \"-w --logs --sync\")")
+	cmd.Flags().String("profile", "", "Trait profile used for deployment")
+	cmd.Flags().StringArrayP("trait", "t", nil, "Configure a trait. E.g. \"-t service.enabled=false\"")
+	cmd.Flags().StringArray("logging-level", nil, "Configure the logging level. e.g. \"--logging-level org.apache.camel=DEBUG\"")
+	cmd.Flags().StringP("output", "o", "", "Output format. One of: json|yaml")
+	cmd.Flags().Bool("compression", false, "Enable store source as a compressed binary blob")
+	cmd.Flags().StringArray("resource", nil, "Add a resource")
+	cmd.Flags().StringArray("open-api", nil, "Add an OpenAPI v2 spec")
+	cmd.Flags().StringArrayP("volume", "v", nil, "Mount a volume into the integration container. E.g \"-v pvcname:/container/path\"")
+	cmd.Flags().StringArrayP("env", "e", nil, "Set an environment variable in the integration container. E.g \"-e MY_VAR=my-value\"")
 
 	// completion support
 	configureKnownCompletions(&cmd)
@@ -94,26 +96,26 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
 
 type runCmdOptions struct {
 	*RootCmdOptions
-	Compression     bool
-	Wait            bool
-	Logs            bool
-	Sync            bool
-	Dev             bool
-	IntegrationKit  string
-	IntegrationName string
-	Profile         string
-	OutputFormat    string
-	Resources       []string
-	OpenAPIs        []string
-	Dependencies    []string
-	Properties      []string
-	ConfigMaps      []string
-	Secrets         []string
-	Repositories    []string
-	Traits          []string
-	LoggingLevels   []string
-	Volumes         []string
-	EnvVars         []string
+	Compression     bool     `mapstructure:"compression"`
+	Wait            bool     `mapstructure:"wait"`
+	Logs            bool     `mapstructure:"logs"`
+	Sync            bool     `mapstructure:"sync"`
+	Dev             bool     `mapstructure:"dev"`
+	IntegrationKit  string   `mapstructure:"kit"`
+	IntegrationName string   `mapstructure:"name"`
+	Profile         string   `mapstructure:"profile"`
+	OutputFormat    string   `mapstructure:"output"`
+	Resources       []string `mapstructure:"resources"`
+	OpenAPIs        []string `mapstructure:"open-apis"`
+	Dependencies    []string `mapstructure:"dependencies"`
+	Properties      []string `mapstructure:"properties"`
+	ConfigMaps      []string `mapstructure:"configmaps"`
+	Secrets         []string `mapstructure:"secrets"`
+	Repositories    []string `mapstructure:"maven-repositories"`
+	Traits          []string `mapstructure:"traits"`
+	LoggingLevels   []string `mapstructure:"logging-levels"`
+	Volumes         []string `mapstructure:"volumes"`
+	EnvVars         []string `mapstructure:"envs"`
 }
 
 func (o *runCmdOptions) validateArgs(_ *cobra.Command, args []string) error {
@@ -232,7 +234,7 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args []string) error {
 	}
 
 	if o.Sync && !o.Logs && !o.Dev {
-		// Let's add a wait point, otherwise the script terminates
+		// Let's add a Wait point, otherwise the script terminates
 		<-o.Context.Done()
 	}
 	return nil
@@ -241,7 +243,7 @@ func (o *runCmdOptions) run(cmd *cobra.Command, args []string) error {
 func (o *runCmdOptions) waitForIntegrationReady(integration *v1alpha1.Integration) (*v1alpha1.IntegrationPhase, error) {
 	handler := func(i *v1alpha1.Integration) bool {
 		//
-		// TODO when we add health checks, we should wait until they are passed
+		// TODO when we add health checks, we should Wait until they are passed
 		//
 		if i.Status.Phase != "" {
 			fmt.Println("integration \""+integration.Name+"\" in phase", i.Status.Phase)
diff --git a/pkg/cmd/util.go b/pkg/cmd/util.go
index d6cb4ee..a32dcce 100644
--- a/pkg/cmd/util.go
+++ b/pkg/cmd/util.go
@@ -19,9 +19,21 @@ package cmd
 
 import (
 	"context"
+	"encoding/csv"
+	"fmt"
+	"log"
+	"reflect"
+	"strings"
+
+	"github.com/mitchellh/mapstructure"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 	"github.com/apache/camel-k/pkg/client"
+	"github.com/spf13/cobra"
+	"github.com/spf13/pflag"
+	"github.com/spf13/viper"
+
+	p "github.com/gertd/go-pluralize"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
@@ -39,3 +51,135 @@ func DeleteIntegration(ctx context.Context, c client.Client, name string, namesp
 	}
 	return c.Delete(ctx, &integration)
 }
+
+func bindPFlagsHierarchy(cmd *cobra.Command) error {
+	for _, c := range cmd.Commands() {
+		if err := bindPFlags(c); err != nil {
+			return err
+		}
+
+		if err := bindPFlagsHierarchy(c); err != nil {
+			return err
+		}
+	}
+
+	return nil
+}
+
+func bindPFlags(cmd *cobra.Command) error {
+	prefix := pathToRoot(cmd)
+	pl := p.NewClient()
+
+	cmd.Flags().VisitAll(func(flag *pflag.Flag) {
+		name := flag.Name
+		name = strings.ReplaceAll(name, "_", "-")
+		name = strings.ReplaceAll(name, ".", "-")
+
+		if err := viper.BindPFlag(prefix+"."+name, flag); err != nil {
+			log.Printf("error binding flag %s with prefix %s to viper: %v", flag.Name, prefix, err)
+		}
+
+		// this is a little bit of an hack to register plural version of properties
+		// based on the naming conventions used by the flag type because it is not
+		// possible to know what is the type of a flag
+		flagType := strings.ToUpper(flag.Value.Type())
+		if strings.Contains(flagType, "SLICE") || strings.Contains(flagType, "ARRAY") {
+			if err := viper.BindPFlag(prefix+"."+pl.Plural(name), flag); err != nil {
+				log.Printf("error binding plural flag %s with prefix %s to viper: %v", flag.Name, prefix, err)
+			}
+		}
+	})
+
+	return nil
+}
+
+func pathToRoot(cmd *cobra.Command) string {
+	path := cmd.Name()
+
+	for current := cmd.Parent(); current != nil; current = current.Parent() {
+		name := current.Name()
+		name = strings.ReplaceAll(name, "_", "-")
+		name = strings.ReplaceAll(name, ".", "-")
+		path = name + "." + path
+	}
+
+	return path
+}
+
+func decodeKey(target interface{}, key string) error {
+	nodes := strings.Split(key, ".")
+	settings := viper.AllSettings()
+
+	for _, node := range nodes {
+		v := settings[node]
+
+		if v == nil {
+			return nil
+		}
+
+		if m, ok := v.(map[string]interface{}); ok {
+			settings = m
+		} else {
+			return fmt.Errorf("unable to find node %s", node)
+		}
+	}
+
+	c := mapstructure.DecoderConfig{
+		Result:           target,
+		WeaklyTypedInput: true,
+		DecodeHook: mapstructure.ComposeDecodeHookFunc(
+			mapstructure.StringToIPNetHookFunc(),
+			mapstructure.StringToTimeDurationHookFunc(),
+			stringToSliceHookFunc(','),
+		),
+	}
+
+	decoder, err := mapstructure.NewDecoder(&c)
+	if err != nil {
+		return err
+	}
+
+	err = decoder.Decode(settings)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func decode(target interface{}) func(*cobra.Command, []string) error {
+	return func(cmd *cobra.Command, args []string) error {
+		path := pathToRoot(cmd)
+		if err := decodeKey(target, path); err != nil {
+			return err
+		}
+
+		return nil
+	}
+}
+
+func stringToSliceHookFunc(comma rune) mapstructure.DecodeHookFunc {
+	return func(
+		f reflect.Kind,
+		t reflect.Kind,
+		data interface{}) (interface{}, error) {
+		if f != reflect.String || t != reflect.Slice {
+			return data, nil
+		}
+
+		s := data.(string)
+		s = strings.TrimPrefix(s, "[")
+		s = strings.TrimSuffix(s, "]")
+
+		if s == "" {
+			return []string{}, nil
+		}
+
+		stringReader := strings.NewReader(s)
+		csvReader := csv.NewReader(stringReader)
+		csvReader.Comma = comma
+		csvReader.LazyQuotes = true
+
+		return csvReader.Read()
+	}
+}