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:00 UTC

[camel-k] branch master updated (bc08a41 -> f217ed0)

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

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


    from bc08a41  goimports - fix build issue import order
     new 24efaa0  Allow to configure kamel CLI with env vars and configuration files #1108
     new 99af3a9  chore(lint): fix findings
     new 5a8dcb9  chore(actions): use custom golangci-lint script
     new acbb0bc  Refactoring to allow testability of cobra/viper commands and commands flags loading.
     new ac5919d  Added run_test.go to test runCmd flags and blueprinted other major commands tests.
     new da3def2  Added viper load from env vars and file tests.
     new e223276  fixed linter reported issues.
     new 5b496c8  Fixed test failures if .kube/config is missing.
     new 4691623  Fixed a not configured k8s client being used in commands preRun preventing testability and possibly causing some unwanted effects in some scenarios like loading commands configs/flags from env vars and config files
     new f217ed0  Fixed a reference to command options not being propagated correctly.

The 10 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .github/workflows/pr-validate.yml                |   8 +-
 go.mod                                           |   2 +
 go.sum                                           |  11 +
 pkg/client/client.go                             |   5 +
 pkg/cmd/builder.go                               |  21 +-
 pkg/cmd/{operator.go => builder_test.go}         |  31 +--
 pkg/cmd/delete.go                                |  27 +--
 pkg/cmd/{version.go => delete_test.go}           |  24 +--
 pkg/cmd/describe.go                              |   6 +-
 pkg/cmd/describe_integration.go                  |  23 ++-
 pkg/cmd/describe_kit.go                          |  25 +--
 pkg/cmd/describe_platform.go                     |  25 +--
 pkg/cmd/get.go                                   |  13 +-
 pkg/cmd/install.go                               | 243 +++++++++++++----------
 pkg/cmd/install_test.go                          |  17 ++
 pkg/cmd/kit.go                                   |   6 +-
 pkg/cmd/kit_create.go                            |  88 ++++----
 pkg/cmd/{kit.go => kit_create_test.go}           |  25 ++-
 pkg/cmd/kit_delete.go                            |  45 +++--
 pkg/cmd/kit_get.go                               |  41 ++--
 pkg/{controller/add_build.go => cmd/kit_test.go} |  15 +-
 pkg/cmd/log.go                                   |  17 +-
 pkg/cmd/operator.go                              |  17 +-
 pkg/cmd/rebuild.go                               |  13 +-
 pkg/cmd/reset.go                                 |  25 +--
 pkg/cmd/root.go                                  |  87 ++++++--
 pkg/cmd/root_test.go                             | 170 ++++++++++++++++
 pkg/cmd/run.go                                   | 106 +++++-----
 pkg/cmd/run_test.go                              |  56 ++++++
 pkg/cmd/util.go                                  | 148 ++++++++++++++
 pkg/util/test/client.go                          |   4 +
 pkg/{cmd/operator.go => util/test/cmd.go}        |  38 ++--
 32 files changed, 937 insertions(+), 445 deletions(-)
 copy pkg/cmd/{operator.go => builder_test.go} (62%)
 copy pkg/cmd/{version.go => delete_test.go} (62%)
 copy pkg/cmd/{kit.go => kit_create_test.go} (58%)
 copy pkg/{controller/add_build.go => cmd/kit_test.go} (76%)
 create mode 100644 pkg/cmd/root_test.go
 create mode 100644 pkg/cmd/run_test.go
 copy pkg/{cmd/operator.go => util/test/cmd.go} (60%)


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

Posted by lb...@apache.org.
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()
+	}
+}


[camel-k] 03/10: chore(actions): use custom golangci-lint script

Posted by lb...@apache.org.
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 5a8dcb9d3822c7a684cb4d966cbe693531b665bd
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Wed Dec 11 10:50:17 2019 +0100

    chore(actions): use custom golangci-lint script
---
 .github/workflows/pr-validate.yml | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/.github/workflows/pr-validate.yml b/.github/workflows/pr-validate.yml
index 8b2ec34..f18c051 100644
--- a/.github/workflows/pr-validate.yml
+++ b/.github/workflows/pr-validate.yml
@@ -35,6 +35,8 @@ jobs:
           restore-keys: |
             ${{ runner.os }}-go-
       - name: Lint
-        uses: reviewdog/action-golangci-lint@v1
-        with:
-          github_token: ${{ secrets.github_token }}
+        run: |
+          curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b . v1.20.1
+          ./golangci-lint config path
+          ./golangci-lint --version
+          GOGC=20 ./golangci-lint run --verbose --deadline 10m --config .golangci.yml
\ No newline at end of file


[camel-k] 08/10: Fixed test failures if .kube/config is missing.

Posted by lb...@apache.org.
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 5b496c8ee1e1ae0342cd51596cdd1fd214b13188
Author: Andrea Tarocchi <an...@gmail.com>
AuthorDate: Mon Dec 16 16:56:35 2019 +0100

    Fixed test failures if .kube/config is missing.
---
 pkg/cmd/root_test.go | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/pkg/cmd/root_test.go b/pkg/cmd/root_test.go
index 50e0293..1bf886b 100644
--- a/pkg/cmd/root_test.go
+++ b/pkg/cmd/root_test.go
@@ -34,8 +34,10 @@ func kamelTestPostAddCommandInit(rootCmd *cobra.Command) *cobra.Command {
 }
 
 func kamelTestPreAddCommandInit() (RootCmdOptions, *cobra.Command) {
+	fakeClient, _ := test.NewFakeClient()
 	options := RootCmdOptions{
 		Context: context.Background(),
+		_client: fakeClient,
 	}
 	rootCmd := kamelPreAddCommandInit(options)
 	rootCmd.Run = test.EmptyRun


[camel-k] 05/10: Added run_test.go to test runCmd flags and blueprinted other major commands tests.

Posted by lb...@apache.org.
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 ac5919d467c72ca2161a9632cf6544974bbf628e
Author: Andrea Tarocchi <an...@gmail.com>
AuthorDate: Mon Dec 16 01:34:26 2019 +0100

    Added run_test.go to test runCmd flags and blueprinted other major commands tests.
---
 pkg/cmd/{run_test.go => builder_test.go}    | 16 +++++++++-------
 pkg/cmd/{run_test.go => delete_test.go}     | 16 +++++++++-------
 pkg/cmd/install_test.go                     | 15 +++++++++++++++
 pkg/cmd/{run_test.go => kit_create_test.go} | 18 +++++++++++-------
 pkg/cmd/{run_test.go => kit_test.go}        | 16 ++++++----------
 pkg/cmd/run_test.go                         | 21 +++++++++++++++++++++
 6 files changed, 71 insertions(+), 31 deletions(-)

diff --git a/pkg/cmd/run_test.go b/pkg/cmd/builder_test.go
similarity index 67%
copy from pkg/cmd/run_test.go
copy to pkg/cmd/builder_test.go
index bd32ed4..080f565 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/builder_test.go
@@ -22,13 +22,15 @@ import (
 	"github.com/spf13/cobra"
 )
 
-func addTestRunCmd(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOptions {
-	//add a testing version of run Command
-	runCmd, runCmdOptions := newCmdRun(&options)
-	runCmd.RunE = func(c *cobra.Command, args []string) error {
+func addTestBuilderCmd(options RootCmdOptions, rootCmd *cobra.Command) *builderCmdOptions {
+	//add a testing version of builder Command
+	builderCmd, builderCmdOptions := newCmdBuilder(&options)
+	builderCmd.RunE = func(c *cobra.Command, args []string) error {
 		return nil
 	}
-	runCmd.Args = test.ArbitraryArgs
-	rootCmd.AddCommand(runCmd)
-	return runCmdOptions
+	builderCmd.Args = test.ArbitraryArgs
+	rootCmd.AddCommand(builderCmd)
+	return builderCmdOptions
 }
+
+//TODO: add a proper test, take inspiration by run_test.go
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/delete_test.go
similarity index 68%
copy from pkg/cmd/run_test.go
copy to pkg/cmd/delete_test.go
index bd32ed4..0c8e317 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/delete_test.go
@@ -22,13 +22,15 @@ import (
 	"github.com/spf13/cobra"
 )
 
-func addTestRunCmd(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOptions {
-	//add a testing version of run Command
-	runCmd, runCmdOptions := newCmdRun(&options)
-	runCmd.RunE = func(c *cobra.Command, args []string) error {
+func addTestDeleteCmd(options RootCmdOptions, rootCmd *cobra.Command) *deleteCmdOptions {
+	//add a testing version of delete Command
+	deleteCmd, deleteCmdOptions := newCmdDelete(&options)
+	deleteCmd.RunE = func(c *cobra.Command, args []string) error {
 		return nil
 	}
-	runCmd.Args = test.ArbitraryArgs
-	rootCmd.AddCommand(runCmd)
-	return runCmdOptions
+	deleteCmd.Args = test.ArbitraryArgs
+	rootCmd.AddCommand(deleteCmd)
+	return deleteCmdOptions
 }
+
+//TODO: add a proper test, take inspiration by run_test.go
diff --git a/pkg/cmd/install_test.go b/pkg/cmd/install_test.go
index 27a8473..8136a59 100644
--- a/pkg/cmd/install_test.go
+++ b/pkg/cmd/install_test.go
@@ -18,6 +18,8 @@ limitations under the License.
 package cmd
 
 import (
+	"github.com/apache/camel-k/pkg/util/test"
+	"github.com/spf13/cobra"
 	"testing"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
@@ -25,6 +27,19 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+func addTestInstallCmd(options RootCmdOptions, rootCmd *cobra.Command) *installCmdOptions {
+	//add a testing version of install Command
+	installCmd, installOptions := newCmdInstall(&options)
+	installCmd.RunE = func(c *cobra.Command, args []string) error {
+		return nil
+	}
+	installCmd.Args = test.ArbitraryArgs
+	rootCmd.AddCommand(installCmd)
+	return installOptions
+}
+
+//TODO: add a proper command flags test, take inspiration by run_test.go
+
 func TestDecodeMavenSettings(t *testing.T) {
 	var err error
 	var val v1alpha1.ValueSource
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/kit_create_test.go
similarity index 63%
copy from pkg/cmd/run_test.go
copy to pkg/cmd/kit_create_test.go
index bd32ed4..88686f3 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/kit_create_test.go
@@ -22,13 +22,17 @@ import (
 	"github.com/spf13/cobra"
 )
 
-func addTestRunCmd(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOptions {
-	//add a testing version of run Command
-	runCmd, runCmdOptions := newCmdRun(&options)
-	runCmd.RunE = func(c *cobra.Command, args []string) error {
+func addTestKitCreateCmd(options RootCmdOptions, rootCmd *cobra.Command) *kitCreateCommandOptions {
+	//add a testing version of kitCreate Command
+	kitCreateCmd, kitCreateCmdOptions := newKitCreateCmd(&options)
+	kitCreateCmd.RunE = func(c *cobra.Command, args []string) error {
 		return nil
 	}
-	runCmd.Args = test.ArbitraryArgs
-	rootCmd.AddCommand(runCmd)
-	return runCmdOptions
+	kitCreateCmd.Args = test.ArbitraryArgs
+	kitCmd := newTestCmdKit(&options)
+	kitCmd.AddCommand(kitCreateCmd)
+	rootCmd.AddCommand(kitCmd)
+	return kitCreateCmdOptions
 }
+
+//TODO: add a proper test, take inspiration by run_test.go
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/kit_test.go
similarity index 68%
copy from pkg/cmd/run_test.go
copy to pkg/cmd/kit_test.go
index bd32ed4..c1367f7 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/kit_test.go
@@ -18,17 +18,13 @@ limitations under the License.
 package cmd
 
 import (
-	"github.com/apache/camel-k/pkg/util/test"
 	"github.com/spf13/cobra"
 )
 
-func addTestRunCmd(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOptions {
-	//add a testing version of run Command
-	runCmd, runCmdOptions := newCmdRun(&options)
-	runCmd.RunE = func(c *cobra.Command, args []string) error {
-		return nil
-	}
-	runCmd.Args = test.ArbitraryArgs
-	rootCmd.AddCommand(runCmd)
-	return runCmdOptions
+func newTestCmdKit(options *RootCmdOptions) *cobra.Command {
+	//add a testing version of kit Command
+	kitCmd := newCmdKit(options)
+	kitCmd.ResetCommands()
+
+	return kitCmd
 }
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/run_test.go
index bd32ed4..4509006 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/run_test.go
@@ -20,6 +20,7 @@ package cmd
 import (
 	"github.com/apache/camel-k/pkg/util/test"
 	"github.com/spf13/cobra"
+	"testing"
 )
 
 func addTestRunCmd(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOptions {
@@ -32,3 +33,23 @@ func addTestRunCmd(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOption
 	rootCmd.AddCommand(runCmd)
 	return runCmdOptions
 }
+
+func TestRunPropertyFlag(t *testing.T) {
+	options, rootCmd := kamelTestPreAddCommandInit()
+
+	runCmdOptions := addTestRunCmd(options, rootCmd)
+
+	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+
+	_, err := test.ExecuteCommand(rootCmd, "run", "route.java", "--property", "key1=value,othervalue", "--property", "key2=value2")
+	if err != nil {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+
+	if len(runCmdOptions.Properties) != 2 {
+		t.Fatalf("Properties expected to contain: \n %v elements\nGot:\n %v elemtns\n", 2, len(runCmdOptions.Properties))
+	}
+	if runCmdOptions.Properties[0] != "key1=value,othervalue" || runCmdOptions.Properties[1] != "key2=value2" {
+		t.Fatalf("Properties expected to be: \n %v\nGot:\n %v\n", "[key1=value,othervalue key2=value2]", runCmdOptions.Properties)
+	}
+}


[camel-k] 02/10: chore(lint): fix findings

Posted by lb...@apache.org.
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 99af3a9d06f10f6e277fe67b53fbbdb084a34837
Author: lburgazzoli <lb...@gmail.com>
AuthorDate: Wed Dec 11 10:49:18 2019 +0100

    chore(lint): fix findings
---
 pkg/cmd/root.go | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go
index bbf7acc..c553c2a 100644
--- a/pkg/cmd/root.go
+++ b/pkg/cmd/root.go
@@ -71,7 +71,9 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, error) {
 	cmd.AddCommand(newCmdOperator())
 	cmd.AddCommand(newCmdBuilder(&options))
 
-	bindPFlagsHierarchy(&cmd)
+	if err := bindPFlagsHierarchy(&cmd); err != nil {
+		return nil, err
+	}
 
 	configName := os.Getenv("KAMEL_CONFIG_NAME")
 	if configName != "" {


[camel-k] 07/10: fixed linter reported issues.

Posted by lb...@apache.org.
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 e223276c1158a517f284fb8644763e22d7b5463f
Author: Andrea Tarocchi <an...@gmail.com>
AuthorDate: Mon Dec 16 12:08:17 2019 +0100

    fixed linter reported issues.
---
 pkg/cmd/builder_test.go    |  1 +
 pkg/cmd/delete_test.go     |  1 +
 pkg/cmd/install_test.go    |  4 +++-
 pkg/cmd/kit_create_test.go |  1 +
 pkg/cmd/kit_test.go        |  1 +
 pkg/cmd/root_test.go       | 23 ++++++++++++++++-------
 pkg/cmd/run_test.go        |  3 ++-
 pkg/util/test/cmd.go       |  1 +
 8 files changed, 26 insertions(+), 9 deletions(-)

diff --git a/pkg/cmd/builder_test.go b/pkg/cmd/builder_test.go
index 080f565..a757dbf 100644
--- a/pkg/cmd/builder_test.go
+++ b/pkg/cmd/builder_test.go
@@ -22,6 +22,7 @@ import (
 	"github.com/spf13/cobra"
 )
 
+//nolint:deadcode,unused
 func addTestBuilderCmd(options RootCmdOptions, rootCmd *cobra.Command) *builderCmdOptions {
 	//add a testing version of builder Command
 	builderCmd, builderCmdOptions := newCmdBuilder(&options)
diff --git a/pkg/cmd/delete_test.go b/pkg/cmd/delete_test.go
index 0c8e317..b66604c 100644
--- a/pkg/cmd/delete_test.go
+++ b/pkg/cmd/delete_test.go
@@ -22,6 +22,7 @@ import (
 	"github.com/spf13/cobra"
 )
 
+//nolint:deadcode,unused
 func addTestDeleteCmd(options RootCmdOptions, rootCmd *cobra.Command) *deleteCmdOptions {
 	//add a testing version of delete Command
 	deleteCmd, deleteCmdOptions := newCmdDelete(&options)
diff --git a/pkg/cmd/install_test.go b/pkg/cmd/install_test.go
index 8136a59..bf8b58d 100644
--- a/pkg/cmd/install_test.go
+++ b/pkg/cmd/install_test.go
@@ -18,15 +18,17 @@ limitations under the License.
 package cmd
 
 import (
+	"testing"
+
 	"github.com/apache/camel-k/pkg/util/test"
 	"github.com/spf13/cobra"
-	"testing"
 
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 
 	"github.com/stretchr/testify/assert"
 )
 
+//nolint:deadcode,unused
 func addTestInstallCmd(options RootCmdOptions, rootCmd *cobra.Command) *installCmdOptions {
 	//add a testing version of install Command
 	installCmd, installOptions := newCmdInstall(&options)
diff --git a/pkg/cmd/kit_create_test.go b/pkg/cmd/kit_create_test.go
index 88686f3..baa965f 100644
--- a/pkg/cmd/kit_create_test.go
+++ b/pkg/cmd/kit_create_test.go
@@ -22,6 +22,7 @@ import (
 	"github.com/spf13/cobra"
 )
 
+//nolint:deadcode,unused
 func addTestKitCreateCmd(options RootCmdOptions, rootCmd *cobra.Command) *kitCreateCommandOptions {
 	//add a testing version of kitCreate Command
 	kitCreateCmd, kitCreateCmdOptions := newKitCreateCmd(&options)
diff --git a/pkg/cmd/kit_test.go b/pkg/cmd/kit_test.go
index c1367f7..ee4d61f 100644
--- a/pkg/cmd/kit_test.go
+++ b/pkg/cmd/kit_test.go
@@ -21,6 +21,7 @@ import (
 	"github.com/spf13/cobra"
 )
 
+//nolint:deadcode,unused
 func newTestCmdKit(options *RootCmdOptions) *cobra.Command {
 	//add a testing version of kit Command
 	kitCmd := newCmdKit(options)
diff --git a/pkg/cmd/root_test.go b/pkg/cmd/root_test.go
index 0bbad46..50e0293 100644
--- a/pkg/cmd/root_test.go
+++ b/pkg/cmd/root_test.go
@@ -20,11 +20,12 @@ package cmd
 import (
 	"bytes"
 	"context"
+	"os"
+	"testing"
+
 	"github.com/apache/camel-k/pkg/util/test"
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
-	"os"
-	"testing"
 )
 
 func kamelTestPostAddCommandInit(rootCmd *cobra.Command) *cobra.Command {
@@ -48,7 +49,8 @@ func TestLoadFromCommandLine(t *testing.T) {
 
 	rootCmd = kamelTestPostAddCommandInit(rootCmd)
 
-	_, err := test.ExecuteCommand(rootCmd, "run", "route.java", "--env", "VAR1=value,othervalue", "--env", "VAR2=value2")
+	const VAR2 = "VAR2=value2"
+	_, err := test.ExecuteCommand(rootCmd, "run", "route.java", "--env", "VAR1=value,othervalue", "--env", VAR2)
 	if err != nil {
 		t.Fatalf("Unexpected error: %v", err)
 	}
@@ -56,7 +58,7 @@ func TestLoadFromCommandLine(t *testing.T) {
 	if len(runCmdOptions.EnvVars) != 2 {
 		t.Errorf("Properties expected to contain: \n %v elements\nGot:\n %v elemtns\n", 2, len(runCmdOptions.EnvVars))
 	}
-	if runCmdOptions.EnvVars[0] != "VAR1=value,othervalue" || runCmdOptions.EnvVars[1] != "VAR2=value2" {
+	if runCmdOptions.EnvVars[0] != "VAR1=value,othervalue" || runCmdOptions.EnvVars[1] != VAR2 {
 		t.Errorf("EnvVars expected to be: \n %v\nGot:\n %v\n", "[VAR1=value,othervalue VAR=value2]", runCmdOptions.EnvVars)
 	}
 }
@@ -88,7 +90,7 @@ func TestLoadFromFile(t *testing.T) {
 	//shows how to include a "," character inside a property value see VAR1 value
 	var propertiesFile = []byte(`kamel.run.envs: "VAR1=value,""othervalue""",VAR2=value2`)
 	viper.SetConfigType("properties")
-	viper.ReadConfig(bytes.NewReader(propertiesFile))
+	readViperConfigFromBytes(propertiesFile, t)
 	options, rootCmd := kamelTestPreAddCommandInit()
 
 	runCmdOptions := addTestRunCmd(options, rootCmd)
@@ -112,7 +114,7 @@ func TestPrecedenceEnvVarOverFile(t *testing.T) {
 	os.Setenv("KAMEL_RUN_ENVS", "VAR1=envVar")
 	var propertiesFile = []byte(`kamel.run.envs: VAR2=file`)
 	viper.SetConfigType("properties")
-	viper.ReadConfig(bytes.NewReader(propertiesFile))
+	readViperConfigFromBytes(propertiesFile, t)
 	options, rootCmd := kamelTestPreAddCommandInit()
 
 	runCmdOptions := addTestRunCmd(options, rootCmd)
@@ -136,7 +138,7 @@ func TestPrecedenceCommandLineOverEverythingElse(t *testing.T) {
 	os.Setenv("KAMEL_RUN_ENVS", "VAR1=envVar")
 	var propertiesFile = []byte(`kamel.run.envs: VAR2=file`)
 	viper.SetConfigType("properties")
-	viper.ReadConfig(bytes.NewReader(propertiesFile))
+	readViperConfigFromBytes(propertiesFile, t)
 	options, rootCmd := kamelTestPreAddCommandInit()
 
 	runCmdOptions := addTestRunCmd(options, rootCmd)
@@ -155,3 +157,10 @@ func TestPrecedenceCommandLineOverEverythingElse(t *testing.T) {
 		t.Fatalf("EnvVars expected to be: \n %v\nGot:\n %v\n", "VAR3=commandLine", runCmdOptions.EnvVars)
 	}
 }
+
+func readViperConfigFromBytes(propertiesFile []byte, t *testing.T) {
+	unexpectedErr := viper.ReadConfig(bytes.NewReader(propertiesFile))
+	if unexpectedErr != nil {
+		t.Fatalf("Unexpected error: %v", unexpectedErr)
+	}
+}
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/run_test.go
index 4509006..f33fbee 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/run_test.go
@@ -18,9 +18,10 @@ limitations under the License.
 package cmd
 
 import (
+	"testing"
+
 	"github.com/apache/camel-k/pkg/util/test"
 	"github.com/spf13/cobra"
-	"testing"
 )
 
 func addTestRunCmd(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOptions {
diff --git a/pkg/util/test/cmd.go b/pkg/util/test/cmd.go
index 4988d78..7d7f003 100644
--- a/pkg/util/test/cmd.go
+++ b/pkg/util/test/cmd.go
@@ -19,6 +19,7 @@ package test
 
 import (
 	"bytes"
+
 	"github.com/spf13/cobra"
 )
 


[camel-k] 04/10: Refactoring to allow testability of cobra/viper commands and commands flags loading.

Posted by lb...@apache.org.
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 acbb0bc6b756b736e964ce76854e83ff397cf3b8
Author: Andrea Tarocchi <an...@gmail.com>
AuthorDate: Thu Dec 12 23:32:25 2019 +0100

    Refactoring to allow testability of cobra/viper commands and commands flags loading.
---
 pkg/cmd/builder.go                   | 10 +++---
 pkg/cmd/delete.go                    | 12 +++----
 pkg/cmd/describe.go                  |  6 ++--
 pkg/cmd/describe_integration.go      | 22 ++++++-------
 pkg/cmd/describe_kit.go              | 20 +++++------
 pkg/cmd/describe_platform.go         | 20 +++++------
 pkg/cmd/get.go                       |  4 +--
 pkg/cmd/install.go                   | 12 +++----
 pkg/cmd/kit.go                       |  6 ++--
 pkg/cmd/kit_create.go                | 20 +++++------
 pkg/cmd/kit_delete.go                | 20 +++++------
 pkg/cmd/kit_get.go                   | 18 +++++-----
 pkg/cmd/log.go                       |  4 +--
 pkg/cmd/rebuild.go                   |  4 +--
 pkg/cmd/reset.go                     |  4 +--
 pkg/cmd/root.go                      | 45 +++++++++++++++++--------
 pkg/cmd/root_test.go                 | 64 ++++++++++++++++++++++++++++++++++--
 pkg/cmd/run.go                       |  4 +--
 pkg/cmd/{kit.go => run_test.go}      | 20 +++++------
 pkg/cmd/util.go                      |  4 +++
 pkg/{cmd/kit.go => util/test/cmd.go} | 31 ++++++++++-------
 21 files changed, 220 insertions(+), 130 deletions(-)

diff --git a/pkg/cmd/builder.go b/pkg/cmd/builder.go
index 9517e7d..5c541f7 100644
--- a/pkg/cmd/builder.go
+++ b/pkg/cmd/builder.go
@@ -22,8 +22,8 @@ import (
 	"github.com/spf13/cobra"
 )
 
-func newCmdBuilder(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	impl := builderCmdOptions{
+func newCmdBuilder(rootCmdOptions *RootCmdOptions) (*cobra.Command, *builderCmdOptions) {
+	options := builderCmdOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
 	cmd := cobra.Command{
@@ -31,13 +31,13 @@ func newCmdBuilder(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		Short:   "Run the Camel K builder",
 		Long:    `Run the Camel K builder`,
 		Hidden:  true,
-		PreRunE: decode(&impl),
-		Run:     impl.run,
+		PreRunE: decode(&options),
+		Run:     options.run,
 	}
 
 	cmd.Flags().String("build-name", "", "The name of the build resource")
 
-	return &cmd
+	return &cmd, &options
 }
 
 type builderCmdOptions struct {
diff --git a/pkg/cmd/delete.go b/pkg/cmd/delete.go
index a3d9a55..aaf9863 100644
--- a/pkg/cmd/delete.go
+++ b/pkg/cmd/delete.go
@@ -31,19 +31,19 @@ import (
 )
 
 // newCmdDelete --
-func newCmdDelete(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	impl := deleteCmdOptions{
+func newCmdDelete(rootCmdOptions *RootCmdOptions) (*cobra.Command, *deleteCmdOptions) {
+	options := deleteCmdOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
 	cmd := cobra.Command{
 		Use:     "delete [integration1] [integration2] ...",
 		Short:   "Delete integrations deployed on Kubernetes",
-		PreRunE: decode(&impl),
+		PreRunE: decode(&options),
 		RunE: func(_ *cobra.Command, args []string) error {
-			if err := impl.validate(args); err != nil {
+			if err := options.validate(args); err != nil {
 				return err
 			}
-			if err := impl.run(args); err != nil {
+			if err := options.run(args); err != nil {
 				fmt.Println(err.Error())
 			}
 
@@ -53,7 +53,7 @@ func newCmdDelete(rootCmdOptions *RootCmdOptions) *cobra.Command {
 
 	cmd.Flags().Bool("all", false, "Delete all integrations")
 
-	return &cmd
+	return &cmd, &options
 }
 
 type deleteCmdOptions struct {
diff --git a/pkg/cmd/describe.go b/pkg/cmd/describe.go
index aa0ae52..13ed541 100644
--- a/pkg/cmd/describe.go
+++ b/pkg/cmd/describe.go
@@ -71,9 +71,9 @@ func newCmdDescribe(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		Long:  `Describe a Camel K resource.`,
 	}
 
-	cmd.AddCommand(newDescribeKitCmd(rootCmdOptions))
-	cmd.AddCommand(newDescribeIntegrationCmd(rootCmdOptions))
-	cmd.AddCommand(newDescribePlatformCmd(rootCmdOptions))
+	cmd.AddCommand(cmdOnly(newDescribeKitCmd(rootCmdOptions)))
+	cmd.AddCommand(cmdOnly(newDescribeIntegrationCmd(rootCmdOptions)))
+	cmd.AddCommand(cmdOnly(newDescribePlatformCmd(rootCmdOptions)))
 
 	return &cmd
 }
diff --git a/pkg/cmd/describe_integration.go b/pkg/cmd/describe_integration.go
index 25882f4..bd4647c 100644
--- a/pkg/cmd/describe_integration.go
+++ b/pkg/cmd/describe_integration.go
@@ -30,9 +30,9 @@ import (
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-func newDescribeIntegrationCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
+func newDescribeIntegrationCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, *describeIntegrationCommandOptions) {
 
-	impl := &describeIntegrationCommand{
+	options := describeIntegrationCommandOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
 
@@ -41,12 +41,12 @@ func newDescribeIntegrationCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		Aliases: []string{"it"},
 		Short:   "Describe an Integration",
 		Long:    `Describe an Integration.`,
-		PreRunE: decode(&impl),
+		PreRunE: decode(&options),
 		RunE: func(_ *cobra.Command, args []string) error {
-			if err := impl.validate(args); err != nil {
+			if err := options.validate(args); err != nil {
 				return err
 			}
-			if err := impl.run(args); err != nil {
+			if err := options.run(args); err != nil {
 				fmt.Println(err.Error())
 			}
 
@@ -54,24 +54,24 @@ func newDescribeIntegrationCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		},
 	}
 
-	cmd.Flags().BoolVar(&impl.showSourceContent, "show-source-content", false, "Print source content")
+	cmd.Flags().BoolVar(&options.showSourceContent, "show-source-content", false, "Print source content")
 
-	return &cmd
+	return &cmd, &options
 }
 
-type describeIntegrationCommand struct {
+type describeIntegrationCommandOptions struct {
 	*RootCmdOptions
 	showSourceContent bool `mapstructure:"show-source-content"`
 }
 
-func (command *describeIntegrationCommand) validate(args []string) error {
+func (command *describeIntegrationCommandOptions) validate(args []string) error {
 	if len(args) != 1 {
 		return fmt.Errorf("accepts at least 1 arg, received %d", len(args))
 	}
 	return nil
 }
 
-func (command *describeIntegrationCommand) run(args []string) error {
+func (command *describeIntegrationCommandOptions) run(args []string) error {
 	c, err := command.GetCmdClient()
 	if err != nil {
 		return err
@@ -92,7 +92,7 @@ func (command *describeIntegrationCommand) run(args []string) error {
 	return nil
 }
 
-func (command *describeIntegrationCommand) describeIntegration(i v1alpha1.Integration) string {
+func (command *describeIntegrationCommandOptions) describeIntegration(i v1alpha1.Integration) string {
 	return indentedwriter.IndentedString(func(out io.Writer) {
 		w := indentedwriter.NewWriter(out)
 
diff --git a/pkg/cmd/describe_kit.go b/pkg/cmd/describe_kit.go
index a3ce855..c0d42f6 100644
--- a/pkg/cmd/describe_kit.go
+++ b/pkg/cmd/describe_kit.go
@@ -28,8 +28,8 @@ import (
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-func newDescribeKitCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	impl := &describeKitCommand{
+func newDescribeKitCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, *describeKitCommandOptions) {
+	options := describeKitCommandOptions{
 		rootCmdOptions,
 	}
 
@@ -37,12 +37,12 @@ func newDescribeKitCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		Use:     "kit",
 		Short:   "Describe an Integration Kit",
 		Long:    `Describe an Integration Kit.`,
-		PreRunE: decode(impl),
+		PreRunE: decode(options),
 		RunE: func(_ *cobra.Command, args []string) error {
-			if err := impl.validate(args); err != nil {
+			if err := options.validate(args); err != nil {
 				return err
 			}
-			if err := impl.run(args); err != nil {
+			if err := options.run(args); err != nil {
 				fmt.Println(err.Error())
 			}
 
@@ -50,21 +50,21 @@ func newDescribeKitCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		},
 	}
 
-	return &cmd
+	return &cmd, &options
 }
 
-type describeKitCommand struct {
+type describeKitCommandOptions struct {
 	*RootCmdOptions
 }
 
-func (command *describeKitCommand) validate(args []string) error {
+func (command *describeKitCommandOptions) validate(args []string) error {
 	if len(args) != 1 {
 		return fmt.Errorf("accepts at least 1 arg, received %d", len(args))
 	}
 	return nil
 }
 
-func (command *describeKitCommand) run(args []string) error {
+func (command *describeKitCommandOptions) run(args []string) error {
 	c, err := command.GetCmdClient()
 	if err != nil {
 		return err
@@ -85,7 +85,7 @@ func (command *describeKitCommand) run(args []string) error {
 	return nil
 }
 
-func (command *describeKitCommand) describeIntegrationKit(kit v1alpha1.IntegrationKit) string {
+func (command *describeKitCommandOptions) describeIntegrationKit(kit v1alpha1.IntegrationKit) string {
 	return indentedwriter.IndentedString(func(out io.Writer) {
 		w := indentedwriter.NewWriter(out)
 
diff --git a/pkg/cmd/describe_platform.go b/pkg/cmd/describe_platform.go
index 17c639b..ddcb799 100644
--- a/pkg/cmd/describe_platform.go
+++ b/pkg/cmd/describe_platform.go
@@ -28,8 +28,8 @@ import (
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-func newDescribePlatformCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	impl := &describePlatformCommand{
+func newDescribePlatformCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, *describePlatformCommandOptions) {
+	options := describePlatformCommandOptions{
 		rootCmdOptions,
 	}
 
@@ -37,12 +37,12 @@ func newDescribePlatformCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		Use:     "platform",
 		Short:   "Describe an Integration Platform",
 		Long:    `Describe an Integration Platform.`,
-		PreRunE: decode(impl),
+		PreRunE: decode(options),
 		RunE: func(_ *cobra.Command, args []string) error {
-			if err := impl.validate(args); err != nil {
+			if err := options.validate(args); err != nil {
 				return err
 			}
-			if err := impl.run(args); err != nil {
+			if err := options.run(args); err != nil {
 				fmt.Println(err.Error())
 			}
 
@@ -50,21 +50,21 @@ func newDescribePlatformCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		},
 	}
 
-	return &cmd
+	return &cmd, &options
 }
 
-type describePlatformCommand struct {
+type describePlatformCommandOptions struct {
 	*RootCmdOptions
 }
 
-func (command *describePlatformCommand) validate(args []string) error {
+func (command *describePlatformCommandOptions) validate(args []string) error {
 	if len(args) != 1 {
 		return fmt.Errorf("accepts at least 1 arg, received %d", len(args))
 	}
 	return nil
 }
 
-func (command *describePlatformCommand) run(args []string) error {
+func (command *describePlatformCommandOptions) run(args []string) error {
 	c, err := command.GetCmdClient()
 	if err != nil {
 		return err
@@ -85,7 +85,7 @@ func (command *describePlatformCommand) run(args []string) error {
 	return nil
 }
 
-func (command *describePlatformCommand) describeIntegrationPlatform(platform v1alpha1.IntegrationPlatform) string {
+func (command *describePlatformCommandOptions) describeIntegrationPlatform(platform v1alpha1.IntegrationPlatform) string {
 	return indentedwriter.IndentedString(func(out io.Writer) {
 		w := indentedwriter.NewWriter(out)
 		describeObjectMeta(w, platform.ObjectMeta)
diff --git a/pkg/cmd/get.go b/pkg/cmd/get.go
index d5dea19..3e10f96 100644
--- a/pkg/cmd/get.go
+++ b/pkg/cmd/get.go
@@ -34,7 +34,7 @@ type getCmdOptions struct {
 	*RootCmdOptions
 }
 
-func newCmdGet(rootCmdOptions *RootCmdOptions) *cobra.Command {
+func newCmdGet(rootCmdOptions *RootCmdOptions) (*cobra.Command, *getCmdOptions) {
 	options := getCmdOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
@@ -46,7 +46,7 @@ func newCmdGet(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		RunE:    options.run,
 	}
 
-	return &cmd
+	return &cmd, &options
 }
 
 func (o *getCmdOptions) run(cmd *cobra.Command, args []string) error {
diff --git a/pkg/cmd/install.go b/pkg/cmd/install.go
index bc10726..96289da 100644
--- a/pkg/cmd/install.go
+++ b/pkg/cmd/install.go
@@ -44,20 +44,20 @@ import (
 	k8serrors "k8s.io/apimachinery/pkg/api/errors"
 )
 
-func newCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	impl := installCmdOptions{
+func newCmdInstall(rootCmdOptions *RootCmdOptions) (*cobra.Command, *installCmdOptions) {
+	options := installCmdOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
 	cmd := cobra.Command{
 		Use:     "install",
 		Short:   "Installs Camel K on a Kubernetes cluster",
 		Long:    `Installs Camel K on a Kubernetes or OpenShift cluster.`,
-		PreRunE: impl.decode,
+		PreRunE: options.decode,
 		RunE: func(cmd *cobra.Command, args []string) error {
-			if err := impl.validate(cmd, args); err != nil {
+			if err := options.validate(cmd, args); err != nil {
 				return err
 			}
-			if err := impl.install(cmd, args); err != nil {
+			if err := options.install(cmd, args); err != nil {
 				return err
 			}
 			return nil
@@ -107,7 +107,7 @@ func newCmdInstall(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		},
 	)
 
-	return &cmd
+	return &cmd, &options
 }
 
 type installCmdOptions struct {
diff --git a/pkg/cmd/kit.go b/pkg/cmd/kit.go
index 67d7ef1..726f09d 100644
--- a/pkg/cmd/kit.go
+++ b/pkg/cmd/kit.go
@@ -28,9 +28,9 @@ func newCmdKit(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		Long:  `Configure an Integration Kit.`,
 	}
 
-	cmd.AddCommand(newKitCreateCmd(rootCmdOptions))
-	cmd.AddCommand(newKitDeleteCmd(rootCmdOptions))
-	cmd.AddCommand(newKitGetCmd(rootCmdOptions))
+	cmd.AddCommand(cmdOnly(newKitCreateCmd(rootCmdOptions)))
+	cmd.AddCommand(cmdOnly(newKitDeleteCmd(rootCmdOptions)))
+	cmd.AddCommand(cmdOnly(newKitGetCmd(rootCmdOptions)))
 
 	return &cmd
 }
diff --git a/pkg/cmd/kit_create.go b/pkg/cmd/kit_create.go
index 3f66c2f..a29c4b3 100644
--- a/pkg/cmd/kit_create.go
+++ b/pkg/cmd/kit_create.go
@@ -33,8 +33,8 @@ import (
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-func newKitCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	impl := &kitCreateCommand{
+func newKitCreateCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, *kitCreateCommandOptions) {
+	options := kitCreateCommandOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
 
@@ -42,9 +42,9 @@ func newKitCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		Use:     "create <name>",
 		Short:   "Create an Integration Kit",
 		Long:    `Create an Integration Kit.`,
-		Args:    impl.validateArgs,
-		PreRunE: decode(impl),
-		RunE:    impl.run,
+		Args:    options.validateArgs,
+		PreRunE: decode(options),
+		RunE:    options.run,
 	}
 
 	cmd.Flags().String("image", "", "Image used to create the kit")
@@ -58,10 +58,10 @@ func newKitCreateCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	// completion support
 	configureKnownCompletions(&cmd)
 
-	return &cmd
+	return &cmd, &options
 }
 
-type kitCreateCommand struct {
+type kitCreateCommandOptions struct {
 	*RootCmdOptions
 
 	Image        string   `mapstructure:"image"`
@@ -73,7 +73,7 @@ type kitCreateCommand struct {
 	Traits       []string `mapstructure:"traits"`
 }
 
-func (command *kitCreateCommand) validateArgs(_ *cobra.Command, args []string) error {
+func (command *kitCreateCommandOptions) validateArgs(_ *cobra.Command, args []string) error {
 	if len(args) != 1 {
 		return errors.New("create expects a single name argument")
 	}
@@ -81,7 +81,7 @@ func (command *kitCreateCommand) validateArgs(_ *cobra.Command, args []string) e
 	return nil
 }
 
-func (command *kitCreateCommand) run(_ *cobra.Command, args []string) error {
+func (command *kitCreateCommandOptions) run(_ *cobra.Command, args []string) error {
 	c, err := command.GetCmdClient()
 	if err != nil {
 		return err
@@ -201,7 +201,7 @@ func (command *kitCreateCommand) run(_ *cobra.Command, args []string) error {
 	return nil
 }
 
-func (*kitCreateCommand) configureTrait(ctx *v1alpha1.IntegrationKit, config string) error {
+func (*kitCreateCommandOptions) configureTrait(ctx *v1alpha1.IntegrationKit, config string) error {
 	if ctx.Spec.Traits == nil {
 		ctx.Spec.Traits = make(map[string]v1alpha1.TraitSpec)
 	}
diff --git a/pkg/cmd/kit_delete.go b/pkg/cmd/kit_delete.go
index 7902fae..3d02d03 100644
--- a/pkg/cmd/kit_delete.go
+++ b/pkg/cmd/kit_delete.go
@@ -29,8 +29,8 @@ import (
 	k8errors "k8s.io/apimachinery/pkg/api/errors"
 )
 
-func newKitDeleteCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	impl := kitDeleteCommand{
+func newKitDeleteCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, *kitDeleteCommandOptions) {
+	options := kitDeleteCommandOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
 
@@ -38,12 +38,12 @@ func newKitDeleteCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		Use:     "delete",
 		Short:   "Delete an Integration Kit",
 		Long:    `Delete an Integration Kit.`,
-		PreRunE: decode(&impl),
+		PreRunE: decode(&options),
 		RunE: func(_ *cobra.Command, args []string) error {
-			if err := impl.validate(args); err != nil {
+			if err := options.validate(args); err != nil {
 				return err
 			}
-			if err := impl.run(args); err != nil {
+			if err := options.run(args); err != nil {
 				fmt.Println(err.Error())
 			}
 
@@ -53,15 +53,15 @@ func newKitDeleteCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 
 	cmd.Flags().Bool("all", false, "Delete all integration Kits")
 
-	return &cmd
+	return &cmd, &options
 }
 
-type kitDeleteCommand struct {
+type kitDeleteCommandOptions struct {
 	*RootCmdOptions
 	All bool `mapstructure:"all"`
 }
 
-func (command *kitDeleteCommand) validate(args []string) error {
+func (command *kitDeleteCommandOptions) validate(args []string) error {
 	if command.All && len(args) > 0 {
 		return errors.New("invalid combination: both all flag and named Kits are set")
 	}
@@ -72,7 +72,7 @@ func (command *kitDeleteCommand) validate(args []string) error {
 	return nil
 }
 
-func (command *kitDeleteCommand) run(args []string) error {
+func (command *kitDeleteCommandOptions) run(args []string) error {
 	names := args
 
 	c, err := command.GetCmdClient()
@@ -104,7 +104,7 @@ func (command *kitDeleteCommand) run(args []string) error {
 	return nil
 }
 
-func (command *kitDeleteCommand) delete(name string) error {
+func (command *kitDeleteCommandOptions) delete(name string) error {
 	ctx := v1alpha1.NewIntegrationKit(command.Namespace, name)
 	key := k8sclient.ObjectKey{
 		Namespace: command.Namespace,
diff --git a/pkg/cmd/kit_get.go b/pkg/cmd/kit_get.go
index a22af7b..b20489f 100644
--- a/pkg/cmd/kit_get.go
+++ b/pkg/cmd/kit_get.go
@@ -28,8 +28,8 @@ import (
 	"github.com/apache/camel-k/pkg/apis/camel/v1alpha1"
 )
 
-func newKitGetCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	impl := kitGetCommand{
+func newKitGetCmd(rootCmdOptions *RootCmdOptions) (*cobra.Command, *kitGetCommandOptions) {
+	options := kitGetCommandOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
 
@@ -37,12 +37,12 @@ func newKitGetCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		Use:     "get",
 		Short:   "Get defined Integration Kit",
 		Long:    `Get defined Integration Kit.`,
-		PreRunE: decode(&impl),
+		PreRunE: decode(&options),
 		RunE: func(cmd *cobra.Command, args []string) error {
-			if err := impl.validate(cmd, args); err != nil {
+			if err := options.validate(cmd, args); err != nil {
 				return err
 			}
-			if err := impl.run(cmd); err != nil {
+			if err := options.run(cmd); err != nil {
 				fmt.Println(err.Error())
 			}
 
@@ -54,21 +54,21 @@ func newKitGetCmd(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	cmd.Flags().Bool(v1alpha1.IntegrationKitTypeExternal, true, "Includes external Kits")
 	cmd.Flags().Bool(v1alpha1.IntegrationKitTypePlatform, true, "Includes platform Kits")
 
-	return &cmd
+	return &cmd, &options
 }
 
-type kitGetCommand struct {
+type kitGetCommandOptions struct {
 	*RootCmdOptions
 	User     bool `mapstructure:"user"`
 	External bool `mapstructure:"external"`
 	Platform bool `mapstructure:"platform"`
 }
 
-func (command *kitGetCommand) validate(cmd *cobra.Command, args []string) error {
+func (command *kitGetCommandOptions) validate(cmd *cobra.Command, args []string) error {
 	return nil
 }
 
-func (command *kitGetCommand) run(cmd *cobra.Command) error {
+func (command *kitGetCommandOptions) run(cmd *cobra.Command) error {
 	kitList := v1alpha1.NewIntegrationKitList()
 	c, err := command.GetCmdClient()
 	if err != nil {
diff --git a/pkg/cmd/log.go b/pkg/cmd/log.go
index 852c9c3..de6d0db 100644
--- a/pkg/cmd/log.go
+++ b/pkg/cmd/log.go
@@ -27,7 +27,7 @@ import (
 	k8sclient "sigs.k8s.io/controller-runtime/pkg/client"
 )
 
-func newCmdLog(rootCmdOptions *RootCmdOptions) *cobra.Command {
+func newCmdLog(rootCmdOptions *RootCmdOptions) (*cobra.Command, *logCmdOptions) {
 	options := logCmdOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
@@ -44,7 +44,7 @@ func newCmdLog(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	// completion support
 	configureKnownCompletions(&cmd)
 
-	return &cmd
+	return &cmd, &options
 }
 
 type logCmdOptions struct {
diff --git a/pkg/cmd/rebuild.go b/pkg/cmd/rebuild.go
index d88738a..82e845c 100644
--- a/pkg/cmd/rebuild.go
+++ b/pkg/cmd/rebuild.go
@@ -29,7 +29,7 @@ import (
 	"github.com/apache/camel-k/pkg/client"
 )
 
-func newCmdRebuild(rootCmdOptions *RootCmdOptions) *cobra.Command {
+func newCmdRebuild(rootCmdOptions *RootCmdOptions) (*cobra.Command, *rebuildCmdOptions) {
 	options := rebuildCmdOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
@@ -41,7 +41,7 @@ func newCmdRebuild(rootCmdOptions *RootCmdOptions) *cobra.Command {
 		RunE:    options.rebuild,
 	}
 
-	return &cmd
+	return &cmd, &options
 }
 
 type rebuildCmdOptions struct {
diff --git a/pkg/cmd/reset.go b/pkg/cmd/reset.go
index 02bd058..0275493 100644
--- a/pkg/cmd/reset.go
+++ b/pkg/cmd/reset.go
@@ -29,7 +29,7 @@ import (
 	"github.com/apache/camel-k/pkg/client"
 )
 
-func newCmdReset(rootCmdOptions *RootCmdOptions) *cobra.Command {
+func newCmdReset(rootCmdOptions *RootCmdOptions) (*cobra.Command, *resetCmdOptions) {
 	options := resetCmdOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
@@ -44,7 +44,7 @@ func newCmdReset(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	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
+	return &cmd, &options
 }
 
 type resetCmdOptions struct {
diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go
index c553c2a..cc8473d 100644
--- a/pkg/cmd/root.go
+++ b/pkg/cmd/root.go
@@ -46,6 +46,17 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, error) {
 	options := RootCmdOptions{
 		Context: ctx,
 	}
+
+	var err error
+	cmd := kamelPreAddCommandInit(options)
+	cmd = addKamelSubcommands(*cmd, options)
+	cmd, err = kamelPostAddCommandInit(*cmd)
+
+	return cmd, err
+}
+
+func kamelPreAddCommandInit(options RootCmdOptions) *cobra.Command {
+
 	var cmd = cobra.Command{
 		BashCompletionFunction: bashCompletionFunction,
 		PersistentPreRunE:      options.preRun,
@@ -57,20 +68,10 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, error) {
 	cmd.PersistentFlags().StringVar(&options.KubeConfig, "config", os.Getenv("KUBECONFIG"), "Path to the config file to use for CLI requests")
 	cmd.PersistentFlags().StringVarP(&options.Namespace, "namespace", "n", "", "Namespace to use for all operations")
 
-	cmd.AddCommand(newCmdCompletion(&cmd))
-	cmd.AddCommand(newCmdVersion())
-	cmd.AddCommand(newCmdRun(&options))
-	cmd.AddCommand(newCmdGet(&options))
-	cmd.AddCommand(newCmdDelete(&options))
-	cmd.AddCommand(newCmdInstall(&options))
-	cmd.AddCommand(newCmdLog(&options))
-	cmd.AddCommand(newCmdKit(&options))
-	cmd.AddCommand(newCmdReset(&options))
-	cmd.AddCommand(newCmdDescribe(&options))
-	cmd.AddCommand(newCmdRebuild(&options))
-	cmd.AddCommand(newCmdOperator())
-	cmd.AddCommand(newCmdBuilder(&options))
+	return &cmd
+}
 
+func kamelPostAddCommandInit(cmd cobra.Command) (*cobra.Command, error) {
 	if err := bindPFlagsHierarchy(&cmd); err != nil {
 		return nil, err
 	}
@@ -98,6 +99,24 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, error) {
 	return &cmd, nil
 }
 
+func addKamelSubcommands(cmd cobra.Command, options RootCmdOptions) *cobra.Command {
+	cmd.AddCommand(newCmdCompletion(&cmd))
+	cmd.AddCommand(newCmdVersion())
+	cmd.AddCommand(cmdOnly(newCmdRun(&options)))
+	cmd.AddCommand(cmdOnly(newCmdGet(&options)))
+	cmd.AddCommand(cmdOnly(newCmdDelete(&options)))
+	cmd.AddCommand(cmdOnly(newCmdInstall(&options)))
+	cmd.AddCommand(cmdOnly(newCmdLog(&options)))
+	cmd.AddCommand(newCmdKit(&options))
+	cmd.AddCommand(cmdOnly(newCmdReset(&options)))
+	cmd.AddCommand(newCmdDescribe(&options))
+	cmd.AddCommand(cmdOnly(newCmdRebuild(&options)))
+	cmd.AddCommand(newCmdOperator())
+	cmd.AddCommand(cmdOnly(newCmdBuilder(&options)))
+
+	return &cmd
+}
+
 func (command *RootCmdOptions) preRun(cmd *cobra.Command, _ []string) error {
 	if command.Namespace == "" {
 		current, err := client.GetCurrentNamespace(command.KubeConfig)
diff --git a/pkg/cmd/root_test.go b/pkg/cmd/root_test.go
index 57f6621..7505ffb 100644
--- a/pkg/cmd/root_test.go
+++ b/pkg/cmd/root_test.go
@@ -17,7 +17,67 @@ limitations under the License.
 
 package cmd
 
-import "testing"
+import (
+	"context"
+	"github.com/apache/camel-k/pkg/util/test"
+	"github.com/spf13/cobra"
+	"os"
+	"testing"
+)
 
-func TestDecodeRoot(t *testing.T) {
+func kamelTestPostAddCommandInit(rootCmd *cobra.Command) *cobra.Command {
+	rootCmd, _ = kamelPostAddCommandInit(*rootCmd)
+	return rootCmd
+}
+
+func kamelTestPreAddCommandInit() (RootCmdOptions, *cobra.Command) {
+	options := RootCmdOptions{
+		Context: context.Background(),
+	}
+	rootCmd := kamelPreAddCommandInit(options)
+	rootCmd.Run = test.EmptyRun
+	return options, rootCmd
+}
+
+func TestLoadFromCommandLine(t *testing.T) {
+	options, rootCmd := kamelTestPreAddCommandInit()
+
+	runCmdOptions := addTestRunCmd(options, rootCmd)
+
+	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+
+	_, err := test.ExecuteCommand(rootCmd, "run", "route.java", "--env", "VAR1=value,othervalue", "--env", "VAR2=value2")
+	if err != nil {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+
+	if len(runCmdOptions.EnvVars) != 2 {
+		t.Errorf("Properties expected to contain: \n %v elements\nGot:\n %v elemtns\n", 2, len(runCmdOptions.EnvVars))
+	}
+	if runCmdOptions.EnvVars[0] != "VAR1=value,othervalue" || runCmdOptions.EnvVars[1] != "VAR2=value2" {
+		t.Errorf("EnvVars expected to be: \n %v\nGot:\n %v\n", "[VAR1=value,othervalue VAR=value2]", runCmdOptions.EnvVars)
+	}
+}
+
+func TestLoadFromEnvVar(t *testing.T) {
+	//shows how to include a "," character inside an env value see VAR1 value
+	os.Setenv("KAMEL_RUN_ENVS", "\"VAR1=value,\"\"othervalue\"\"\",VAR2=value2")
+
+	options, rootCmd := kamelTestPreAddCommandInit()
+
+	runCmdOptions := addTestRunCmd(options, rootCmd)
+
+	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+
+	_, err := test.ExecuteCommand(rootCmd, "run", "route.java")
+	if err != nil {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+
+	if len(runCmdOptions.EnvVars) != 2 {
+		t.Fatalf("Properties expected to contain: \n %v elements\nGot:\n %v elemtns\n", 2, len(runCmdOptions.EnvVars))
+	}
+	if runCmdOptions.EnvVars[0] != "VAR1=value,\"othervalue\"" || runCmdOptions.EnvVars[1] != "VAR2=value2" {
+		t.Fatalf("EnvVars expected to be: \n %v\nGot:\n %v\n", "[VAR1=value,\"othervalue\" VAR=value2]", runCmdOptions.EnvVars)
+	}
 }
diff --git a/pkg/cmd/run.go b/pkg/cmd/run.go
index 4c41081..df1b9b6 100644
--- a/pkg/cmd/run.go
+++ b/pkg/cmd/run.go
@@ -53,7 +53,7 @@ var (
 	traitConfigRegexp = regexp.MustCompile(`^([a-z-]+)((?:\.[a-z-]+)+)=(.*)$`)
 )
 
-func newCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
+func newCmdRun(rootCmdOptions *RootCmdOptions) (*cobra.Command, *runCmdOptions) {
 	options := runCmdOptions{
 		RootCmdOptions: rootCmdOptions,
 	}
@@ -91,7 +91,7 @@ func newCmdRun(rootCmdOptions *RootCmdOptions) *cobra.Command {
 	// completion support
 	configureKnownCompletions(&cmd)
 
-	return &cmd
+	return &cmd, &options
 }
 
 type runCmdOptions struct {
diff --git a/pkg/cmd/kit.go b/pkg/cmd/run_test.go
similarity index 68%
copy from pkg/cmd/kit.go
copy to pkg/cmd/run_test.go
index 67d7ef1..bd32ed4 100644
--- a/pkg/cmd/kit.go
+++ b/pkg/cmd/run_test.go
@@ -18,19 +18,17 @@ limitations under the License.
 package cmd
 
 import (
+	"github.com/apache/camel-k/pkg/util/test"
 	"github.com/spf13/cobra"
 )
 
-func newCmdKit(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	cmd := cobra.Command{
-		Use:   "kit",
-		Short: "Configure an Integration Kit",
-		Long:  `Configure an Integration Kit.`,
+func addTestRunCmd(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOptions {
+	//add a testing version of run Command
+	runCmd, runCmdOptions := newCmdRun(&options)
+	runCmd.RunE = func(c *cobra.Command, args []string) error {
+		return nil
 	}
-
-	cmd.AddCommand(newKitCreateCmd(rootCmdOptions))
-	cmd.AddCommand(newKitDeleteCmd(rootCmdOptions))
-	cmd.AddCommand(newKitGetCmd(rootCmdOptions))
-
-	return &cmd
+	runCmd.Args = test.ArbitraryArgs
+	rootCmd.AddCommand(runCmd)
+	return runCmdOptions
 }
diff --git a/pkg/cmd/util.go b/pkg/cmd/util.go
index a32dcce..8ee87ac 100644
--- a/pkg/cmd/util.go
+++ b/pkg/cmd/util.go
@@ -183,3 +183,7 @@ func stringToSliceHookFunc(comma rune) mapstructure.DecodeHookFunc {
 		return csvReader.Read()
 	}
 }
+
+func cmdOnly(cmd *cobra.Command, options interface{}) *cobra.Command {
+	return cmd
+}
diff --git a/pkg/cmd/kit.go b/pkg/util/test/cmd.go
similarity index 59%
copy from pkg/cmd/kit.go
copy to pkg/util/test/cmd.go
index 67d7ef1..4988d78 100644
--- a/pkg/cmd/kit.go
+++ b/pkg/util/test/cmd.go
@@ -15,22 +15,31 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package cmd
+package test
 
 import (
+	"bytes"
 	"github.com/spf13/cobra"
 )
 
-func newCmdKit(rootCmdOptions *RootCmdOptions) *cobra.Command {
-	cmd := cobra.Command{
-		Use:   "kit",
-		Short: "Configure an Integration Kit",
-		Long:  `Configure an Integration Kit.`,
-	}
+func EmptyRun(*cobra.Command, []string) {}
 
-	cmd.AddCommand(newKitCreateCmd(rootCmdOptions))
-	cmd.AddCommand(newKitDeleteCmd(rootCmdOptions))
-	cmd.AddCommand(newKitGetCmd(rootCmdOptions))
+func ArbitraryArgs(cmd *cobra.Command, args []string) error {
+	return nil
+}
+
+func ExecuteCommand(root *cobra.Command, args ...string) (output string, err error) {
+	_, output, err = ExecuteCommandC(root, args...)
+	return output, err
+}
+
+func ExecuteCommandC(root *cobra.Command, args ...string) (c *cobra.Command, output string, err error) {
+	buf := new(bytes.Buffer)
+	root.SetOut(buf)
+	root.SetErr(buf)
+	root.SetArgs(args)
+
+	c, err = root.ExecuteC()
 
-	return &cmd
+	return c, buf.String(), err
 }


[camel-k] 10/10: Fixed a reference to command options not being propagated correctly.

Posted by lb...@apache.org.
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 f217ed0d857ac9ea0d911b4a6eb179719606f8df
Author: Andrea Tarocchi <an...@gmail.com>
AuthorDate: Wed Dec 18 10:15:08 2019 +0100

    Fixed a reference to command options not being propagated correctly.
---
 pkg/cmd/root.go      | 44 +++++++++++++++++++++-----------------------
 pkg/cmd/root_test.go | 24 +++++++++++++-----------
 pkg/cmd/run_test.go  |  6 +++---
 3 files changed, 37 insertions(+), 37 deletions(-)

diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go
index c1ed396..8f1450c 100644
--- a/pkg/cmd/root.go
+++ b/pkg/cmd/root.go
@@ -48,14 +48,14 @@ func NewKamelCommand(ctx context.Context) (*cobra.Command, error) {
 	}
 
 	var err error
-	cmd := kamelPreAddCommandInit(options)
-	cmd = addKamelSubcommands(*cmd, options)
-	cmd, err = kamelPostAddCommandInit(*cmd)
+	cmd := kamelPreAddCommandInit(&options)
+	addKamelSubcommands(cmd, &options)
+	err = kamelPostAddCommandInit(cmd)
 
 	return cmd, err
 }
 
-func kamelPreAddCommandInit(options RootCmdOptions) *cobra.Command {
+func kamelPreAddCommandInit(options *RootCmdOptions) *cobra.Command {
 
 	var cmd = cobra.Command{
 		BashCompletionFunction: bashCompletionFunction,
@@ -71,9 +71,9 @@ func kamelPreAddCommandInit(options RootCmdOptions) *cobra.Command {
 	return &cmd
 }
 
-func kamelPostAddCommandInit(cmd cobra.Command) (*cobra.Command, error) {
-	if err := bindPFlagsHierarchy(&cmd); err != nil {
-		return nil, err
+func kamelPostAddCommandInit(cmd *cobra.Command) error {
+	if err := bindPFlagsHierarchy(cmd); err != nil {
+		return err
 	}
 
 	configName := os.Getenv("KAMEL_CONFIG_NAME")
@@ -92,29 +92,27 @@ func kamelPostAddCommandInit(cmd cobra.Command) (*cobra.Command, error) {
 
 	if err := viper.ReadInConfig(); err != nil {
 		if _, ok := err.(viper.ConfigFileNotFoundError); !ok {
-			return nil, err
+			return err
 		}
 	}
 
-	return &cmd, nil
+	return nil
 }
 
-func addKamelSubcommands(cmd cobra.Command, options RootCmdOptions) *cobra.Command {
-	cmd.AddCommand(newCmdCompletion(&cmd))
+func addKamelSubcommands(cmd *cobra.Command, options *RootCmdOptions) {
+	cmd.AddCommand(newCmdCompletion(cmd))
 	cmd.AddCommand(newCmdVersion())
-	cmd.AddCommand(cmdOnly(newCmdRun(&options)))
-	cmd.AddCommand(cmdOnly(newCmdGet(&options)))
-	cmd.AddCommand(cmdOnly(newCmdDelete(&options)))
-	cmd.AddCommand(cmdOnly(newCmdInstall(&options)))
-	cmd.AddCommand(cmdOnly(newCmdLog(&options)))
-	cmd.AddCommand(newCmdKit(&options))
-	cmd.AddCommand(cmdOnly(newCmdReset(&options)))
-	cmd.AddCommand(newCmdDescribe(&options))
-	cmd.AddCommand(cmdOnly(newCmdRebuild(&options)))
+	cmd.AddCommand(cmdOnly(newCmdRun(options)))
+	cmd.AddCommand(cmdOnly(newCmdGet(options)))
+	cmd.AddCommand(cmdOnly(newCmdDelete(options)))
+	cmd.AddCommand(cmdOnly(newCmdInstall(options)))
+	cmd.AddCommand(cmdOnly(newCmdLog(options)))
+	cmd.AddCommand(newCmdKit(options))
+	cmd.AddCommand(cmdOnly(newCmdReset(options)))
+	cmd.AddCommand(newCmdDescribe(options))
+	cmd.AddCommand(cmdOnly(newCmdRebuild(options)))
 	cmd.AddCommand(newCmdOperator())
-	cmd.AddCommand(cmdOnly(newCmdBuilder(&options)))
-
-	return &cmd
+	cmd.AddCommand(cmdOnly(newCmdBuilder(options)))
 }
 
 func (command *RootCmdOptions) preRun(cmd *cobra.Command, _ []string) error {
diff --git a/pkg/cmd/root_test.go b/pkg/cmd/root_test.go
index 1bf886b..a050a5f 100644
--- a/pkg/cmd/root_test.go
+++ b/pkg/cmd/root_test.go
@@ -28,20 +28,22 @@ import (
 	"github.com/spf13/viper"
 )
 
-func kamelTestPostAddCommandInit(rootCmd *cobra.Command) *cobra.Command {
-	rootCmd, _ = kamelPostAddCommandInit(*rootCmd)
-	return rootCmd
+func kamelTestPostAddCommandInit(t *testing.T, rootCmd *cobra.Command) {
+	err := kamelPostAddCommandInit(rootCmd)
+	if err != nil {
+		t.Fatalf("Unexpected error: %v", err)
+	}
 }
 
-func kamelTestPreAddCommandInit() (RootCmdOptions, *cobra.Command) {
+func kamelTestPreAddCommandInit() (*RootCmdOptions, *cobra.Command) {
 	fakeClient, _ := test.NewFakeClient()
 	options := RootCmdOptions{
 		Context: context.Background(),
 		_client: fakeClient,
 	}
-	rootCmd := kamelPreAddCommandInit(options)
+	rootCmd := kamelPreAddCommandInit(&options)
 	rootCmd.Run = test.EmptyRun
-	return options, rootCmd
+	return &options, rootCmd
 }
 
 func TestLoadFromCommandLine(t *testing.T) {
@@ -49,7 +51,7 @@ func TestLoadFromCommandLine(t *testing.T) {
 
 	runCmdOptions := addTestRunCmd(options, rootCmd)
 
-	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+	kamelTestPostAddCommandInit(t, rootCmd)
 
 	const VAR2 = "VAR2=value2"
 	_, err := test.ExecuteCommand(rootCmd, "run", "route.java", "--env", "VAR1=value,othervalue", "--env", VAR2)
@@ -73,7 +75,7 @@ func TestLoadFromEnvVar(t *testing.T) {
 
 	runCmdOptions := addTestRunCmd(options, rootCmd)
 
-	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+	kamelTestPostAddCommandInit(t, rootCmd)
 
 	_, err := test.ExecuteCommand(rootCmd, "run", "route.java")
 	if err != nil {
@@ -97,7 +99,7 @@ func TestLoadFromFile(t *testing.T) {
 
 	runCmdOptions := addTestRunCmd(options, rootCmd)
 
-	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+	kamelTestPostAddCommandInit(t, rootCmd)
 
 	_, err := test.ExecuteCommand(rootCmd, "run", "route.java")
 	if err != nil {
@@ -121,7 +123,7 @@ func TestPrecedenceEnvVarOverFile(t *testing.T) {
 
 	runCmdOptions := addTestRunCmd(options, rootCmd)
 
-	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+	kamelTestPostAddCommandInit(t, rootCmd)
 
 	_, err := test.ExecuteCommand(rootCmd, "run", "route.java")
 	if err != nil {
@@ -145,7 +147,7 @@ func TestPrecedenceCommandLineOverEverythingElse(t *testing.T) {
 
 	runCmdOptions := addTestRunCmd(options, rootCmd)
 
-	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+	kamelTestPostAddCommandInit(t, rootCmd)
 
 	_, err := test.ExecuteCommand(rootCmd, "run", "route.java", "--env", "VAR3=commandLine")
 	if err != nil {
diff --git a/pkg/cmd/run_test.go b/pkg/cmd/run_test.go
index f33fbee..1fcc673 100644
--- a/pkg/cmd/run_test.go
+++ b/pkg/cmd/run_test.go
@@ -24,9 +24,9 @@ import (
 	"github.com/spf13/cobra"
 )
 
-func addTestRunCmd(options RootCmdOptions, rootCmd *cobra.Command) *runCmdOptions {
+func addTestRunCmd(options *RootCmdOptions, rootCmd *cobra.Command) *runCmdOptions {
 	//add a testing version of run Command
-	runCmd, runCmdOptions := newCmdRun(&options)
+	runCmd, runCmdOptions := newCmdRun(options)
 	runCmd.RunE = func(c *cobra.Command, args []string) error {
 		return nil
 	}
@@ -40,7 +40,7 @@ func TestRunPropertyFlag(t *testing.T) {
 
 	runCmdOptions := addTestRunCmd(options, rootCmd)
 
-	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+	kamelTestPostAddCommandInit(t, rootCmd)
 
 	_, err := test.ExecuteCommand(rootCmd, "run", "route.java", "--property", "key1=value,othervalue", "--property", "key2=value2")
 	if err != nil {


[camel-k] 09/10: Fixed a not configured k8s client being used in commands preRun preventing testability and possibly causing some unwanted effects in some scenarios like loading commands configs/flags from env vars and config files

Posted by lb...@apache.org.
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 46916233a89ce5f551ac8e637129c5eea2d18a55
Author: Andrea Tarocchi <an...@gmail.com>
AuthorDate: Tue Dec 17 14:06:50 2019 +0100

    Fixed a not configured k8s client being used in commands preRun
    preventing testability and possibly causing some unwanted effects
    in some scenarios like loading commands configs/flags from env vars and config files
---
 pkg/client/client.go    | 5 +++++
 pkg/cmd/root.go         | 7 ++++++-
 pkg/util/test/client.go | 4 ++++
 3 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/pkg/client/client.go b/pkg/client/client.go
index 55ddf41..2fcb141 100644
--- a/pkg/client/client.go
+++ b/pkg/client/client.go
@@ -53,6 +53,7 @@ type Client interface {
 	kubernetes.Interface
 	GetScheme() *runtime.Scheme
 	GetConfig() *rest.Config
+	GetCurrentNamespace(kubeConfig string) (string, error)
 }
 
 // Injectable identifies objects that can receive a Client
@@ -80,6 +81,10 @@ func (c *defaultClient) GetConfig() *rest.Config {
 	return c.config
 }
 
+func (c *defaultClient) GetCurrentNamespace(kubeConfig string) (string, error) {
+	return GetCurrentNamespace(kubeConfig)
+}
+
 // NewOutOfClusterClient creates a new k8s client that can be used from outside the cluster
 func NewOutOfClusterClient(kubeconfig string) (Client, error) {
 	initialize(kubeconfig)
diff --git a/pkg/cmd/root.go b/pkg/cmd/root.go
index cc8473d..c1ed396 100644
--- a/pkg/cmd/root.go
+++ b/pkg/cmd/root.go
@@ -119,7 +119,12 @@ func addKamelSubcommands(cmd cobra.Command, options RootCmdOptions) *cobra.Comma
 
 func (command *RootCmdOptions) preRun(cmd *cobra.Command, _ []string) error {
 	if command.Namespace == "" {
-		current, err := client.GetCurrentNamespace(command.KubeConfig)
+		var current string
+		client, err := command.GetCmdClient()
+		if err != nil {
+			return errors.Wrap(err, "cannot get command client")
+		}
+		current, err = client.GetCurrentNamespace(command.KubeConfig)
 		if err != nil {
 			return errors.Wrap(err, "cannot get current namespace")
 		}
diff --git a/pkg/util/test/client.go b/pkg/util/test/client.go
index 47d1bcd..d3df07b 100644
--- a/pkg/util/test/client.go
+++ b/pkg/util/test/client.go
@@ -61,3 +61,7 @@ func (c *FakeClient) GetScheme() *runtime.Scheme {
 func (c *FakeClient) GetConfig() *rest.Config {
 	return nil
 }
+
+func (c *FakeClient) GetCurrentNamespace(kubeConfig string) (string, error) {
+	return "", nil
+}


[camel-k] 06/10: Added viper load from env vars and file tests.

Posted by lb...@apache.org.
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 da3def297e65f4cb28fb62dd849c1a17f432dbeb
Author: Andrea Tarocchi <an...@gmail.com>
AuthorDate: Mon Dec 16 01:35:17 2019 +0100

    Added viper load from env vars and file tests.
---
 pkg/cmd/root_test.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/pkg/cmd/root_test.go b/pkg/cmd/root_test.go
index 7505ffb..0bbad46 100644
--- a/pkg/cmd/root_test.go
+++ b/pkg/cmd/root_test.go
@@ -18,9 +18,11 @@ limitations under the License.
 package cmd
 
 import (
+	"bytes"
 	"context"
 	"github.com/apache/camel-k/pkg/util/test"
 	"github.com/spf13/cobra"
+	"github.com/spf13/viper"
 	"os"
 	"testing"
 )
@@ -81,3 +83,75 @@ func TestLoadFromEnvVar(t *testing.T) {
 		t.Fatalf("EnvVars expected to be: \n %v\nGot:\n %v\n", "[VAR1=value,\"othervalue\" VAR=value2]", runCmdOptions.EnvVars)
 	}
 }
+
+func TestLoadFromFile(t *testing.T) {
+	//shows how to include a "," character inside a property value see VAR1 value
+	var propertiesFile = []byte(`kamel.run.envs: "VAR1=value,""othervalue""",VAR2=value2`)
+	viper.SetConfigType("properties")
+	viper.ReadConfig(bytes.NewReader(propertiesFile))
+	options, rootCmd := kamelTestPreAddCommandInit()
+
+	runCmdOptions := addTestRunCmd(options, rootCmd)
+
+	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+
+	_, err := test.ExecuteCommand(rootCmd, "run", "route.java")
+	if err != nil {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+
+	if len(runCmdOptions.EnvVars) != 2 {
+		t.Fatalf("Properties expected to contain: \n %v elements\nGot:\n %v elemtns\n", 2, len(runCmdOptions.EnvVars))
+	}
+	if runCmdOptions.EnvVars[0] != "VAR1=value,\"othervalue\"" || runCmdOptions.EnvVars[1] != "VAR2=value2" {
+		t.Fatalf("EnvVars expected to be: \n %v\nGot:\n %v\n", "[VAR1=value,\"othervalue\" VAR=value2]", runCmdOptions.EnvVars)
+	}
+}
+
+func TestPrecedenceEnvVarOverFile(t *testing.T) {
+	os.Setenv("KAMEL_RUN_ENVS", "VAR1=envVar")
+	var propertiesFile = []byte(`kamel.run.envs: VAR2=file`)
+	viper.SetConfigType("properties")
+	viper.ReadConfig(bytes.NewReader(propertiesFile))
+	options, rootCmd := kamelTestPreAddCommandInit()
+
+	runCmdOptions := addTestRunCmd(options, rootCmd)
+
+	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+
+	_, err := test.ExecuteCommand(rootCmd, "run", "route.java")
+	if err != nil {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+
+	if len(runCmdOptions.EnvVars) != 1 {
+		t.Fatalf("Properties expected to contain: \n %v elements\nGot:\n %v elements\n", 1, len(runCmdOptions.EnvVars))
+	}
+	if runCmdOptions.EnvVars[0] != "VAR1=envVar" {
+		t.Fatalf("EnvVars expected to be: \n %v\nGot:\n %v\n", "VAR1=envVar", runCmdOptions.EnvVars)
+	}
+}
+
+func TestPrecedenceCommandLineOverEverythingElse(t *testing.T) {
+	os.Setenv("KAMEL_RUN_ENVS", "VAR1=envVar")
+	var propertiesFile = []byte(`kamel.run.envs: VAR2=file`)
+	viper.SetConfigType("properties")
+	viper.ReadConfig(bytes.NewReader(propertiesFile))
+	options, rootCmd := kamelTestPreAddCommandInit()
+
+	runCmdOptions := addTestRunCmd(options, rootCmd)
+
+	rootCmd = kamelTestPostAddCommandInit(rootCmd)
+
+	_, err := test.ExecuteCommand(rootCmd, "run", "route.java", "--env", "VAR3=commandLine")
+	if err != nil {
+		t.Fatalf("Unexpected error: %v", err)
+	}
+
+	if len(runCmdOptions.EnvVars) != 1 {
+		t.Fatalf("Properties expected to contain: \n %v elements\nGot:\n %v elements\n", 1, len(runCmdOptions.EnvVars))
+	}
+	if runCmdOptions.EnvVars[0] != "VAR3=commandLine" {
+		t.Fatalf("EnvVars expected to be: \n %v\nGot:\n %v\n", "VAR3=commandLine", runCmdOptions.EnvVars)
+	}
+}