Repository: knative-sandbox/kn-plugin-func
Pull request #807 (2022-02-01 23:45:00)

Cleanup commands
* Command tree is build from root, not by ad hoc attaching in `init()` blocks.
* Getting rid of `FUNC_PARENT_COMMAND` and `prefix` stuff in favor of `cmd.Root().Name()`.

knative-prow-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative-sandbox/kn-plugin-func/pull/807#" title="Author self-approved">matejvasek</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative-sandbox%2Fkn-plugin-func).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/knative-sandbox/kn-plugin-func/blob/main/OWNERS)~~ [matejvasek]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
matejvasek: /hold
codecov[bot]: # [Codecov](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) Report
> Merging [#807](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) (1b8c2c3) into [main](https://codecov.io/gh/knative-sandbox/kn-plugin-func/commit/fff00497f8d48d23e37c51a3a8e6469a9a35f2bb?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) (fff0049) will **increase** coverage by `1.52%`.
> The diff coverage is `67.16%`.

[![Impacted file tree graph](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/graphs/tree.svg?width=650&height=150&src=pr&token=da1B9bMsQ9&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox)](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox)

```diff
@@            Coverage Diff             @@
##             main     #807      +/-   ##
==========================================
+ Coverage   44.35%   45.87%   +1.52%     
==========================================
  Files          47       47              
  Lines        4302     4386      +84     
==========================================
+ Hits         1908     2012     +104     
+ Misses       2113     2082      -31     
- Partials      281      292      +11     
```


| [Impacted Files](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) | Coverage Δ | |
|---|---|---|
| [cmd/build.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL2J1aWxkLmdv) | `59.12% <ø> (-0.30%)` | :arrow_down: |
| [cmd/delete.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL2RlbGV0ZS5nbw==) | `48.45% <ø> (-0.53%)` | :arrow_down: |
| [cmd/deploy.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL2RlcGxveS5nbw==) | `13.52% <ø> (-0.36%)` | :arrow_down: |
| [cmd/info.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL2luZm8uZ28=) | `24.05% <ø> (-0.95%)` | :arrow_down: |
| [cmd/list.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL2xpc3QuZ28=) | `28.78% <ø> (-1.07%)` | :arrow_down: |
| [cmd/run.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL3J1bi5nbw==) | `58.66% <ø> (-0.55%)` | :arrow_down: |
| [cmd/completion.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL2NvbXBsZXRpb24uZ28=) | `51.85% <31.57%> (+44.70%)` | :arrow_up: |
| [cmd/config\_envs.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL2NvbmZpZ19lbnZzLmdv) | `13.68% <62.50%> (+11.11%)` | :arrow_up: |
| [cmd/config\_volumes.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL2NvbmZpZ192b2x1bWVzLmdv) | `22.66% <62.50%> (+17.74%)` | :arrow_up: |
| [cmd/root.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y21kL3Jvb3QuZ28=) | `66.91% <66.00%> (+6.73%)` | :arrow_up: |
| ... and [11 more](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox). Last update [fff0049...1b8c2c3](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/807?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox).

matejvasek: @lance I think this will conflict with your PR a lot.

Patch:
diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES
index 600ae4aa..01eafc33 100644
--- a/OWNERS_ALIASES
+++ b/OWNERS_ALIASES
@@ -174,6 +174,7 @@ aliases:
   - csantanapr
   - dprotaso
   - evankanderson
+  - itsmurugappan
   - julz
   - knative-prow-releaser-robot
   - knative-prow-robot
@@ -249,6 +250,7 @@ aliases:
   - lionelvillard
   steering-committee:
   - csantanapr
+  - itsmurugappan
   - lance
   - pmorie
   - thisisnotapril
diff --git a/cmd/build.go b/cmd/build.go
index 82bce0e3..a0702f74 100644
--- a/cmd/build.go
+++ b/cmd/build.go
@@ -19,12 +19,6 @@ import (
 	"knative.dev/kn-plugin-func/progress"
 )
 
-func init() {
-	// Add to the root a new "Build" command which obtains an appropriate
-	// instance of fn.Client from the given client creator function.
-	root.AddCommand(NewBuildCmd(newBuildClient))
-}
-
 func newBuildClient(cfg buildConfig) (*fn.Client, error) {
 	builder := buildpacks.NewBuilder()
 	listener := progress.New()
diff --git a/cmd/completion.go b/cmd/completion.go
index d41838df..aedd7d60 100644
--- a/cmd/completion.go
+++ b/cmd/completion.go
@@ -7,15 +7,11 @@ import (
 	"github.com/spf13/cobra"
 )
 
-func init() {
-	root.AddCommand(completionCmd)
-}
-
-// completionCmd represents the completion command
-var completionCmd = &cobra.Command{
-	Use:   "completion <bash|zsh|fish>",
-	Short: "Generate completion scripts for bash, fish and zsh",
-	Long: `To load completion run
+func NewCompletionCmd() *cobra.Command {
+	return &cobra.Command{
+		Use:   "completion <bash|zsh|fish>",
+		Short: "Generate completion scripts for bash, fish and zsh",
+		Long: `To load completion run
 
 For zsh:
 source <(func completion zsh)
@@ -28,23 +24,25 @@ For bash:
 source <(func completion bash)
 
 `,
-	ValidArgs: []string{"bash", "zsh", "fish"},
-	Args:      cobra.ExactArgs(1),
-	RunE: func(cmd *cobra.Command, args []string) (err error) {
-		if len(args) < 1 {
-			return errors.New("missing argument")
-		}
-		switch args[0] {
-		case "bash":
-			err = root.GenBashCompletion(os.Stdout)
-		case "zsh":
-			err = root.GenZshCompletion(os.Stdout)
-		case "fish":
-			err = root.GenFishCompletion(os.Stdout, true)
-		default:
-			err = errors.New("unknown shell, only bash, zsh and fish are supported")
-		}
-
-		return err
-	},
+		ValidArgs: []string{"bash", "zsh", "fish"},
+		Args:      cobra.ExactArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			if len(args) < 1 {
+				return errors.New("missing argument")
+			}
+			switch args[0] {
+			case "bash":
+				err = cmd.Root().GenBashCompletion(os.Stdout)
+			case "zsh":
+				err = cmd.Root().GenZshCompletion(os.Stdout)
+			case "fish":
+				err = cmd.Root().GenFishCompletion(os.Stdout, true)
+			default:
+				err = errors.New("unknown shell, only bash, zsh and fish are supported")
+			}
+
+			return err
+		},
+	}
+
 }
diff --git a/cmd/config.go b/cmd/config.go
index b27429fb..e79dc01f 100644
--- a/cmd/config.go
+++ b/cmd/config.go
@@ -43,24 +43,28 @@ func (s standardLoaderSaver) Save(f fn.Function) error {
 
 var defaultLoaderSaver standardLoaderSaver
 
-func init() {
-	root.AddCommand(configCmd)
-	setPathFlag(configCmd)
-	configCmd.AddCommand(NewConfigLabelsCmd(defaultLoaderSaver))
-}
-
-var configCmd = &cobra.Command{
-	Use:   "config",
-	Short: "Configure a function",
-	Long: `Configure a function
+func NewConfigCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "config",
+		Short: "Configure a function",
+		Long: `Configure a function
 
 Interactive propmt that allows configuration of Volume mounts, Environment
 variables, and Labels for a function project present in the current directory
 or from the directory specified with --path.
 `,
-	SuggestFor: []string{"cfg", "cofnig"},
-	PreRunE:    bindEnv("path"),
-	RunE:       runConfigCmd,
+		SuggestFor: []string{"cfg", "cofnig"},
+		PreRunE:    bindEnv("path"),
+		RunE:       runConfigCmd,
+	}
+
+	setPathFlag(cmd)
+
+	cmd.AddCommand(NewConfigLabelsCmd(defaultLoaderSaver))
+	cmd.AddCommand(NewConfigEnvsCmd())
+	cmd.AddCommand(NewConfigVolumesCmd())
+
+	return cmd
 }
 
 func runConfigCmd(cmd *cobra.Command, args []string) (err error) {
diff --git a/cmd/config_envs.go b/cmd/config_envs.go
index 8d4684d9..64776915 100644
--- a/cmd/config_envs.go
+++ b/cmd/config_envs.go
@@ -14,41 +14,47 @@ import (
 	"knative.dev/kn-plugin-func/utils"
 )
 
-func init() {
-	setPathFlag(configEnvsCmd)
-	setPathFlag(configEnvsAddCmd)
-	setPathFlag(configEnvsRemoveCmd)
-	configCmd.AddCommand(configEnvsCmd)
-	configEnvsCmd.AddCommand(configEnvsAddCmd)
-	configEnvsCmd.AddCommand(configEnvsRemoveCmd)
-}
-
-var configEnvsCmd = &cobra.Command{
-	Use:   "envs",
-	Short: "List and manage configured environment variable for a function",
-	Long: `List and manage configured environment variable for a function
+func NewConfigEnvsCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "envs",
+		Short: "List and manage configured environment variable for a function",
+		Long: `List and manage configured environment variable for a function
 
 Prints configured Environment variable for a function project present in
 the current directory or from the directory specified with --path.
 `,
-	SuggestFor: []string{"ensv", "env"},
-	PreRunE:    bindEnv("path"),
-	RunE: func(cmd *cobra.Command, args []string) (err error) {
-		function, err := initConfigCommand(args, defaultLoaderSaver)
-		if err != nil {
+		SuggestFor: []string{"ensv", "env"},
+		PreRunE:    bindEnv("path"),
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			function, err := initConfigCommand(args, defaultLoaderSaver)
+			if err != nil {
+				return
+			}
+
+			listEnvs(function)
+
 			return
-		}
+		},
+	}
 
-		listEnvs(function)
+	configEnvsAddCmd := NewConfigEnvsAddCmd()
+	configEnvsRemoveCmd := NewConfigEnvsRemoveCmd()
 
-		return
-	},
+	setPathFlag(cmd)
+	setPathFlag(configEnvsAddCmd)
+	setPathFlag(configEnvsRemoveCmd)
+
+	cmd.AddCommand(configEnvsAddCmd)
+	cmd.AddCommand(configEnvsRemoveCmd)
+
+	return cmd
 }
 
-var configEnvsAddCmd = &cobra.Command{
-	Use:   "add",
-	Short: "Add environment variable to the function configuration",
-	Long: `Add environment variable to the function configuration
+func NewConfigEnvsAddCmd() *cobra.Command {
+	return &cobra.Command{
+		Use:   "add",
+		Short: "Add environment variable to the function configuration",
+		Long: `Add environment variable to the function configuration
 
 Interactive prompt to add Environment variables to the function project
 in the current directory or from the directory specified with --path.
@@ -56,36 +62,41 @@ in the current directory or from the directory specified with --path.
 The environment variable can be set directly from a value,
 from an environment variable on the local machine or from Secrets and ConfigMaps.
 `,
-	SuggestFor: []string{"ad", "create", "insert", "append"},
-	PreRunE:    bindEnv("path"),
-	RunE: func(cmd *cobra.Command, args []string) (err error) {
-		function, err := initConfigCommand(args, defaultLoaderSaver)
-		if err != nil {
-			return
-		}
+		SuggestFor: []string{"ad", "create", "insert", "append"},
+		PreRunE:    bindEnv("path"),
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			function, err := initConfigCommand(args, defaultLoaderSaver)
+			if err != nil {
+				return
+			}
+
+			return runAddEnvsPrompt(cmd.Context(), function)
+		},
+	}
 
-		return runAddEnvsPrompt(cmd.Context(), function)
-	},
 }
 
-var configEnvsRemoveCmd = &cobra.Command{
-	Use:   "remove",
-	Short: "Remove environment variable from the function configuration",
-	Long: `Remove environment variable from the function configuration
+func NewConfigEnvsRemoveCmd() *cobra.Command {
+	return &cobra.Command{
+		Use:   "remove",
+		Short: "Remove environment variable from the function configuration",
+		Long: `Remove environment variable from the function configuration
 
 Interactive prompt to remove Environment variables from the function project
 in the current directory or from the directory specified with --path.
 `,
-	SuggestFor: []string{"rm", "del", "delete", "rmeove"},
-	PreRunE:    bindEnv("path"),
-	RunE: func(cmd *cobra.Command, args []string) (err error) {
-		function, err := initConfigCommand(args, defaultLoaderSaver)
-		if err != nil {
-			return
-		}
+		SuggestFor: []string{"rm", "del", "delete", "rmeove"},
+		PreRunE:    bindEnv("path"),
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			function, err := initConfigCommand(args, defaultLoaderSaver)
+			if err != nil {
+				return
+			}
+
+			return runRemoveEnvsPrompt(function)
+		},
+	}
 
-		return runRemoveEnvsPrompt(function)
-	},
 }
 
 func listEnvs(f fn.Function) {
diff --git a/cmd/config_volumes.go b/cmd/config_volumes.go
index 4d2f8c60..656538a3 100644
--- a/cmd/config_volumes.go
+++ b/cmd/config_volumes.go
@@ -13,75 +13,86 @@ import (
 	"knative.dev/kn-plugin-func/k8s"
 )
 
-func init() {
-	setPathFlag(configVolumesCmd)
-	setPathFlag(configVolumesAddCmd)
-	setPathFlag(configVolumesRemoveCmd)
-	configCmd.AddCommand(configVolumesCmd)
-	configVolumesCmd.AddCommand(configVolumesAddCmd)
-	configVolumesCmd.AddCommand(configVolumesRemoveCmd)
-}
-
-var configVolumesCmd = &cobra.Command{
-	Use:   "volumes",
-	Short: "List and manage configured volumes for a function",
-	Long: `List and manage configured volumes for a function
+func NewConfigVolumesCmd() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "volumes",
+		Short: "List and manage configured volumes for a function",
+		Long: `List and manage configured volumes for a function
 
 Prints configured Volume mounts for a function project present in
 the current directory or from the directory specified with --path.
 `,
-	SuggestFor: []string{"volums", "volume", "vols"},
-	PreRunE:    bindEnv("path"),
-	RunE: func(cmd *cobra.Command, args []string) (err error) {
-		function, err := initConfigCommand(args, defaultLoaderSaver)
-		if err != nil {
+		SuggestFor: []string{"volums", "volume", "vols"},
+		PreRunE:    bindEnv("path"),
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			function, err := initConfigCommand(args, defaultLoaderSaver)
+			if err != nil {
+				return
+			}
+
+			listVolumes(function)
+
 			return
-		}
+		},
+	}
 
-		listVolumes(function)
+	configVolumesAddCmd := NewConfigVolumesAddCmd()
+	configVolumesRemoveCmd := NewConfigVolumesRemoveCmd()
 
-		return
-	},
+	setPathFlag(cmd)
+	setPathFlag(configVolumesAddCmd)
+	setPathFlag(configVolumesRemoveCmd)
+
+	cmd.AddCommand(configVolumesAddCmd)
+	cmd.AddCommand(configVolumesRemoveCmd)
+
+	return cmd
 }
 
-var configVolumesAddCmd = &cobra.Command{
-	Use:   "add",
-	Short: "Add volume to the function configuration",
-	Long: `Add volume to the function configuration
+func NewConfigVolumesAddCmd() *cobra.Command {
+	return &cobra.Command{
+		Use:   "add",
+		Short: "Add volume to the function configuration",
+		Long: `Add volume to the function configuration
 
 Interactive prompt to add Secrets and ConfigMaps as Volume mounts to the function project
 in the current directory or from the directory specified with --path.
 `,
-	SuggestFor: []string{"ad", "create", "insert", "append"},
-	PreRunE:    bindEnv("path"),
-	RunE: func(cmd *cobra.Command, args []string) (err error) {
-		function, err := initConfigCommand(args, defaultLoaderSaver)
-		if err != nil {
-			return
-		}
+		SuggestFor: []string{"ad", "create", "insert", "append"},
+		PreRunE:    bindEnv("path"),
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			function, err := initConfigCommand(args, defaultLoaderSaver)
+			if err != nil {
+				return
+			}
+
+			return runAddVolumesPrompt(cmd.Context(), function)
+		},
+	}
 
-		return runAddVolumesPrompt(cmd.Context(), function)
-	},
 }
 
-var configVolumesRemoveCmd = &cobra.Command{
-	Use:   "remove",
-	Short: "Remove volume from the function configuration",
-	Long: `Remove volume from the function configuration
+func NewConfigVolumesRemoveCmd() *cobra.Command {
+	return &cobra.Command{
+		Use:   "remove",
+		Short: "Remove volume from the function configuration",
+		Long: `Remove volume from the function configuration
 
 Interactive prompt to remove Volume mounts from the function project
 in the current directory or from the directory specified with --path.
 `,
-	SuggestFor: []string{"del", "delete", "rmeove"},
-	PreRunE:    bindEnv("path"),
-	RunE: func(cmd *cobra.Command, args []string) (err error) {
-		function, err := initConfigCommand(args, defaultLoaderSaver)
-		if err != nil {
-			return
-		}
+		SuggestFor: []string{"del", "delete", "rmeove"},
+		PreRunE:    bindEnv("path"),
+		RunE: func(cmd *cobra.Command, args []string) (err error) {
+			function, err := initConfigCommand(args, defaultLoaderSaver)
+			if err != nil {
+				return
+			}
+
+			return runRemoveVolumesPrompt(function)
+		},
+	}
 
-		return runRemoveVolumesPrompt(function)
-	},
 }
 
 func listVolumes(f fn.Function) {
diff --git a/cmd/create.go b/cmd/create.go
index d11c7d75..fa9f8b79 100644
--- a/cmd/create.go
+++ b/cmd/create.go
@@ -25,12 +25,6 @@ type ErrInvalidRuntime error
 // ErrInvalidTemplate indicates that the passed template was invalid.
 type ErrInvalidTemplate error
 
-func init() {
-	// Add to the root a new "Create" command which obtains an appropriate
-	// instance of fn.Client from the given client creator function.
-	root.AddCommand(NewCreateCmd(newCreateClient))
-}
-
 // createClientFn is a factory function which returns a Client suitable for
 // use with the Create command.
 type createClientFn func(createConfig) *fn.Client
@@ -53,16 +47,16 @@ func NewCreateCmd(clientFn createClientFn) *cobra.Command {
 		Short: "Create a Function Project",
 		Long: `
 NAME
-	{{.Prefix}}func create - Create a Function project.
+	{{.Name}} create - Create a Function project.
 
 SYNOPSIS
-	{{.Prefix}}func create [-l|--language] [-t|--template] [-r|--repository]
+	{{.Name}} create [-l|--language] [-t|--template] [-r|--repository]
 	            [-c|--confirm]  [-v|--verbose]  [path]
 
 DESCRIPTION
 	Creates a new Function project.
 
-	  $ {{.Prefix}}func create -l node -t http
+	  $ {{.Name}} create -l node -t http
 
 	Creates a Function in the current directory '.' which is written in the
 	language/runtime 'node' and handles HTTP events.
@@ -71,24 +65,24 @@ DESCRIPTION
 	the path if necessary.
 
 	To complete this command interactivly, use --confirm (-c):
-	  $ {{.Prefix}}func create -c
+	  $ {{.Name}} create -c
 
 	Available Language Runtimes and Templates:
 {{ .Options | indent 2 " " | indent 1 "\t" }}
 
-	To install more language runtimes and their templates see '{{.Prefix}}func repository'.
+	To install more language runtimes and their templates see '{{.Name}} repository'.
 
 EXAMPLES
 	o Create a Node.js Function (the default language runtime) in the current
 	  directory (the default path) which handles http events (the default
 	  template).
-	  $ {{.Prefix}}func create
+	  $ {{.Name}} create
 
 	o Create a Node.js Function in the directory 'myfunc'.
-	  $ {{.Prefix}}func create myfunc
+	  $ {{.Name}} create myfunc
 
 	o Create a Go Function which handles CloudEvents in ./myfunc.
-	  $ {{.Prefix}}func create -l go -t cloudevents myfunc
+	  $ {{.Name}} create -l go -t cloudevents myfunc
 		`,
 		SuggestFor: []string{"vreate", "creaet", "craete", "new"},
 		PreRunE:    bindEnv("language", "template", "repository", "confirm"),
@@ -182,10 +176,10 @@ func runCreateHelp(cmd *cobra.Command, args []string, clientFn createClientFn) {
 
 	var data = struct {
 		Options string
-		Prefix  string
+		Name    string
 	}{
 		Options: options,
-		Prefix:  pluginPrefix(),
+		Name:    cmd.Root().Name(),
 	}
 	if err := tpl.Execute(cmd.OutOrStdout(), data); err != nil {
 		fmt.Fprintf(cmd.ErrOrStderr(), "unable to display help text: %v", err)
diff --git a/cmd/delete.go b/cmd/delete.go
index c718b23e..09407415 100644
--- a/cmd/delete.go
+++ b/cmd/delete.go
@@ -14,12 +14,6 @@ import (
 	"knative.dev/kn-plugin-func/progress"
 )
 
-func init() {
-	// Create a new delete command with a reference to
-	// a function which yields an appropriate concrete client instance.
-	root.AddCommand(NewDeleteCmd(newDeleteClient))
-}
-
 // newDeleteClient returns an instance of a Client using the
 // final config state.
 // Testing note: This method is swapped out during testing to allow
diff --git a/cmd/deploy.go b/cmd/deploy.go
index d68f318e..55e3f4b7 100644
--- a/cmd/deploy.go
+++ b/cmd/deploy.go
@@ -24,10 +24,6 @@ import (
 	"knative.dev/kn-plugin-func/progress"
 )
 
-func init() {
-	root.AddCommand(NewDeployCmd(newDeployClient))
-}
-
 func newDeployClient(cfg deployConfig) (*fn.Client, error) {
 	listener := progress.New()
 	builder := buildpacks.NewBuilder()
diff --git a/cmd/func/main.go b/cmd/func/main.go
index bc79adf8..9ac9932a 100644
--- a/cmd/func/main.go
+++ b/cmd/func/main.go
@@ -2,6 +2,7 @@ package main
 
 import (
 	"context"
+	"fmt"
 	"os"
 	"os/signal"
 	"syscall"
@@ -28,6 +29,25 @@ func main() {
 		os.Exit(137)
 	}()
 
-	cmd.SetMeta(date, vers, hash)
-	cmd.Execute(ctx)
+	root, err := cmd.NewRootCmd(cmd.RootCommandConfig{
+		Name:    "func",
+		Date:    date,
+		Version: vers,
+		Hash:    hash,
+	})
+
+	if err != nil {
+		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
+		os.Exit(1)
+	}
+
+	if err := root.ExecuteContext(ctx); err != nil {
+		if ctx.Err() != nil {
+			os.Exit(130)
+			return
+		}
+		// Errors are printed to STDERR output and the process exits with code of 1.
+		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
+		os.Exit(1)
+	}
 }
diff --git a/cmd/info.go b/cmd/info.go
index 7b771cf4..d910327a 100644
--- a/cmd/info.go
+++ b/cmd/info.go
@@ -15,10 +15,6 @@ import (
 	"knative.dev/kn-plugin-func/knative"
 )
 
-func init() {
-	root.AddCommand(NewInfoCmd(newInfoClient))
-}
-
 func newInfoClient(cfg infoConfig) (*fn.Client, error) {
 	describer, err := knative.NewDescriber(cfg.Namespace)
 	if err != nil {
diff --git a/cmd/invoke.go b/cmd/invoke.go
index b7e523dd..6d64a047 100644
--- a/cmd/invoke.go
+++ b/cmd/invoke.go
@@ -18,10 +18,6 @@ import (
 	knative "knative.dev/kn-plugin-func/knative"
 )
 
-func init() {
-	root.AddCommand(NewInvokeCmd(newInvokeClient))
-}
-
 type invokeClientFn func(invokeConfig) (*fn.Client, error)
 
 func newInvokeClient(cfg invokeConfig) (*fn.Client, error) {
@@ -44,10 +40,10 @@ func NewInvokeCmd(clientFn invokeClientFn) *cobra.Command {
 		Short: "Invoke a Function",
 		Long: `
 NAME
-	{{.Prefix}}func invoke - Invoke a Function.
+	{{.Name}} invoke - Invoke a Function.
 
 SYNOPSIS
-	{{.Prefix}}func invoke [-t|--target] [-f|--format]
+	{{.Name}} invoke [-t|--target] [-f|--format]
 	             [--id] [--source] [--type] [--data] [--file] [--content-type]
 	             [-s|--save] [-p|--path] [-c|--confirm] [-v|--verbose]
 
@@ -71,54 +67,54 @@ DESCRIPTION
 	Invocation Target
 	  The Function instance to invoke can be specified using the --target flag
 	  which accepts the values "local", "remote", or <URL>.  By default the
-	  local Function instance is chosen if running (see {{.Prefix}}func run).
+	  local Function instance is chosen if running (see {{.Name}} run).
 	  To explicitly target the remote (deployed) Function:
-	    {{.Prefix}}func invoke --target=remote
+	    {{.Name}} invoke --target=remote
 	  To target an arbitrary endpoint, provide a URL:
-	    {{.Prefix}}func invoke --target=https://myfunction.example.com
+	    {{.Name}} invoke --target=https://myfunction.example.com
 
 	Invocation Data
 	  Providing a filename in the --file flag will base64 encode its contents
 	  as the "data" parameter sent to the Function.  The value of --content-type
 	  should be set to the type from the source file.  For example, the following
 	  would send a JPEG base64 encoded in the "data" POST parameter:
-	    {{.Prefix}}func invoke --file=example.jpeg --content-type=image/jpeg
+	    {{.Name}} invoke --file=example.jpeg --content-type=image/jpeg
 
 	Message Format
 	  By default Functions are sent messages which match the invocation format
 	  of the template they were created using; for example "http" or "cloudevent".
 	  To override this behavior, use the --format (-f) flag.
-	    {{.Prefix}}func invoke -f=cloudevent -t=http://my-sink.my-cluster
+	    {{.Name}} invoke -f=cloudevent -t=http://my-sink.my-cluster
 
 EXAMPLES
 
 	o Invoke the default (local or remote) running Function with default values
-	  $ {{.Prefix}}func invoke
+	  $ {{.Name}} invoke
 
 	o Run the Function locally and then invoke it with a test request:
 	  (run in two terminals or by running the first in the background)
-	  $ {{.Prefix}}func run
-	  $ {{.Prefix}}func invoke
+	  $ {{.Name}} run
+	  $ {{.Name}} invoke
 
 	o Deploy and then invoke the remote Function:
-	  $ {{.Prefix}}func deploy
-	  $ {{.Prefix}}func invoke
+	  $ {{.Name}} deploy
+	  $ {{.Name}} invoke
 
 	o Invoke a remote (deployed) Function when it is already running locally:
 	  (overrides the default behavior of preferring locally running instances)
-	  $ {{.Prefix}}func invoke --target=remote
+	  $ {{.Name}} invoke --target=remote
 
 	o Specify the data to send to the Function as a flag
-	  $ {{.Prefix}}func invoke --data="Hello World!"
+	  $ {{.Name}} invoke --data="Hello World!"
 
 	o Send a JPEG to the Function
-	  $ {{.Prefix}}func invoke --file=example.jpeg --content-type=image/jpeg
+	  $ {{.Name}} invoke --file=example.jpeg --content-type=image/jpeg
 
 	o Invoke an arbitrary endpoint (HTTP POST)
-		$ {{.Prefix}}func invoke --target="https://my-http-handler.example.com"
+		$ {{.Name}} invoke --target="https://my-http-handler.example.com"
 
 	o Invoke an arbitrary endpoint (CloudEvent)
-		$ {{.Prefix}}func invoke -f=cloudevent -t="https://my-event-broker.example.com"
+		$ {{.Name}} invoke -f=cloudevent -t="https://my-event-broker.example.com"
 
 `,
 		SuggestFor: []string{"emit", "emti", "send", "emit", "exec", "nivoke", "onvoke", "unvoke", "knvoke", "imvoke", "ihvoke", "ibvoke"},
@@ -203,9 +199,9 @@ func runInvokeHelp(cmd *cobra.Command, args []string, clientFn invokeClientFn) {
 	)
 
 	var data = struct {
-		Prefix string
+		Name string
 	}{
-		Prefix: pluginPrefix(),
+		Name: cmd.Root().Name(),
 	}
 
 	if err := tpl.Execute(cmd.OutOrStdout(), data); err != nil {
diff --git a/cmd/list.go b/cmd/list.go
index e0169213..e94d2951 100644
--- a/cmd/list.go
+++ b/cmd/list.go
@@ -17,10 +17,6 @@ import (
 	"knative.dev/kn-plugin-func/knative"
 )
 
-func init() {
-	root.AddCommand(NewListCmd(newListClient))
-}
-
 func newListClient(cfg listConfig) (*fn.Client, error) {
 	// TODO(lkingland): does an empty namespace mean all namespaces
 	// or the default namespace as defined in user's config?
diff --git a/cmd/repository.go b/cmd/repository.go
index 6c3da17c..9863a019 100644
--- a/cmd/repository.go
+++ b/cmd/repository.go
@@ -12,15 +12,6 @@ import (
 	fn "knative.dev/kn-plugin-func"
 )
 
-func init() {
-	repositoryCmd := NewRepositoryCmd(newRepositoryClient)
-	repositoryCmd.AddCommand(NewRepositoryListCmd(newRepositoryClient))
-	repositoryCmd.AddCommand(NewRepositoryAddCmd(newRepositoryClient))
-	repositoryCmd.AddCommand(NewRepositoryRenameCmd(newRepositoryClient))
-	repositoryCmd.AddCommand(NewRepositoryRemoveCmd(newRepositoryClient))
-	root.AddCommand(repositoryCmd)
-}
-
 // repositoryClientFn is a function which yields both a client and the final
 // config used to instantiate.
 type repositoryClientFn func([]string) (repositoryConfig, RepositoryClient, error)
@@ -174,6 +165,12 @@ EXAMPLES
 	cmd.RunE = func(cmd *cobra.Command, args []string) error {
 		return runRepository(cmd, args, clientFn)
 	}
+
+	cmd.AddCommand(NewRepositoryListCmd(newRepositoryClient))
+	cmd.AddCommand(NewRepositoryAddCmd(newRepositoryClient))
+	cmd.AddCommand(NewRepositoryRenameCmd(newRepositoryClient))
+	cmd.AddCommand(NewRepositoryRemoveCmd(newRepositoryClient))
+
 	return cmd
 }
 
diff --git a/cmd/root.go b/cmd/root.go
index aaae633a..fdbd86bd 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -2,7 +2,6 @@ package cmd
 
 import (
 	"bytes"
-	"context"
 	"fmt"
 	"os"
 	"path/filepath"
@@ -29,69 +28,34 @@ var exampleTemplate = template.Must(template.New("example").Parse(`
 curl $(kn service describe myfunc -o url)
 `))
 
-// The root of the command tree defines the command name, description, globally
-// available flags, etc.  It has no action of its own, such that running the
-// resultant binary with no arguments prints the help/usage text.
-var root = &cobra.Command{
-	Use:           "func",
-	Short:         "Serverless Functions",
-	SilenceErrors: true, // we explicitly handle errors in Execute()
-	SilenceUsage:  true, // no usage dump on error
-	Long: `Serverless Functions
-
-Create, build and deploy Functions in serverless containers for multiple runtimes on Knative`,
+type RootCommandConfig struct {
+	Name    string // usually `func` or `kn func`
+	Date    string
+	Version string
+	Hash    string
 }
 
-func init() {
+// NewRootCmd creates the root of the command tree defines the command name, description, globally
+// available flags, etc.  It has no action of its own, such that running the
+// resultant binary with no arguments prints the help/usage text.
+func NewRootCmd(config RootCommandConfig) (*cobra.Command, error) {
 	var err error
-	root.Example, err = replaceNameInTemplate("func", "example")
-	if err != nil {
-		root.Example = "Usage could not be loaded"
-	}
-}
 
-func replaceNameInTemplate(name, template string) (string, error) {
-	var buffer bytes.Buffer
-	err := exampleTemplate.ExecuteTemplate(&buffer, template, name)
-	if err != nil {
-		return "", err
-	}
-	return buffer.String(), nil
-}
+	root := &cobra.Command{
+		Use:           config.Name,
+		Short:         "Serverless Functions",
+		SilenceErrors: true, // we explicitly handle errors in Execute()
+		SilenceUsage:  true, // no usage dump on error
+		Long: `Serverless Functions
 
-// pluginPrefix returns an optional prefix for help commands based on the
-// value of the FUNC_PARENT_COMMAND environment variable.
-func pluginPrefix() string {
-	parent := os.Getenv("FUNC_PARENT_COMMAND")
-	if parent != "" {
-		return parent + " "
+Create, build and deploy Functions in serverless containers for multiple runtimes on Knative`,
 	}
-	return ""
-}
 
-// NewRootCmd can be used to embed the func commands as a library, such as
-// a plugin in 'kn'.
-func NewRootCmd() (*cobra.Command, error) {
-	// TODO: have 'kn' provide this environment variable, such that this works
-	// generically, and works whether it is compiled in as a library or used via
-	// the `kn-func` binary naming convention.
-	os.Setenv("FUNC_PARENT_COMMAND", "kn")
-
-	// TODO: update the below to use the environment variable, and the general
-	// structure seen in the create command's help text.
-	root.Use = "kn func"
-	var err error
-	root.Example, err = replaceNameInTemplate("kn func", "example")
+	root.Example, err = replaceNameInTemplate(config.Name, "example")
 	if err != nil {
 		root.Example = "Usage could not be loaded"
 	}
-	return root, err
-}
 
-// When the code is loaded into memory upon invocation, the cobra/viper packages
-// are invoked to gather system context.  This includes reading the configuration
-// file, environment variables, and parsing the command flags.
-func init() {
 	// read in environment variables that match
 	viper.AutomaticEnv()
 
@@ -101,9 +65,9 @@ func init() {
 	// which thus overrides both the default and the value read in from the
 	// config file (i.e. flags always take highest precidence).
 	root.PersistentFlags().BoolVarP(&verbose, "verbose", "v", verbose, "print verbose logs")
-	err := viper.BindPFlag("verbose", root.PersistentFlags().Lookup("verbose"))
+	err = viper.BindPFlag("verbose", root.PersistentFlags().Lookup("verbose"))
 	if err != nil {
-		panic(err)
+		return nil, err
 	}
 
 	// Override the --version template to match the output format from the
@@ -112,24 +76,38 @@ func init() {
 
 	// Prefix all environment variables with "FUNC_" to avoid collisions with other apps.
 	viper.SetEnvPrefix("func")
-}
 
-// Execute the command tree by executing the root command, which runs
-// according to the context defined by:  the optional config file,
-// Environment Variables, command arguments and flags.
-func Execute(ctx context.Context) {
-	// Sets version to a string partially populated by compile-time flags.
+	version := Version{
+		Date: config.Date,
+		Vers: config.Version,
+		Hash: config.Hash,
+	}
+
 	root.Version = version.String()
-	// Execute the root of the command tree.
-	if err := root.ExecuteContext(ctx); err != nil {
-		if ctx.Err() != nil {
-			os.Exit(130)
-			return
-		}
-		// Errors are printed to STDERR output and the process exits with code of 1.
-		fmt.Fprintf(os.Stderr, "Error: %v\n", err)
-		os.Exit(1)
+
+	root.AddCommand(NewVersionCmd(version))
+	root.AddCommand(NewCreateCmd(newCreateClient))
+	root.AddCommand(NewConfigCmd())
+	root.AddCommand(NewBuildCmd(newBuildClient))
+	root.AddCommand(NewDeployCmd(newDeployClient))
+	root.AddCommand(NewDeleteCmd(newDeleteClient))
+	root.AddCommand(NewInfoCmd(newInfoClient))
+	root.AddCommand(NewListCmd(newListClient))
+	root.AddCommand(NewInvokeCmd(newInvokeClient))
+	root.AddCommand(NewRepositoryCmd(newRepositoryClient))
+	root.AddCommand(NewRunCmd(newRunClient))
+	root.AddCommand(NewCompletionCmd())
+
+	return root, nil
+}
+
+func replaceNameInTemplate(name, template string) (string, error) {
+	var buffer bytes.Buffer
+	err := exampleTemplate.ExecuteTemplate(&buffer, template, name)
+	if err != nil {
+		return "", err
 	}
+	return buffer.String(), nil
 }
 
 // Helpers
@@ -338,3 +316,45 @@ func setPathFlag(cmd *cobra.Command) {
 func setNamespaceFlag(cmd *cobra.Command) {
 	cmd.Flags().StringP("namespace", "n", "", "The namespace on the cluster. By default, the namespace in func.yaml is used or the currently active namespace if not set in the configuration. (Env: $FUNC_NAMESPACE)")
 }
+
+type Version struct {
+	// Date of compilation
+	Date string
+	// Version tag of the git commit, or 'tip' if no tag.
+	Vers string
+	// Hash of the currently active git commit on build.
+	Hash string
+	// Verbose printing enabled for the string representation.
+	Verbose bool
+}
+
+func (v Version) String() string {
+	// If 'vers' is not a semver already, then the binary was built either
+	// from an untagged git commit (set semver to v0.0.0), or was built
+	// directly from source (set semver to v0.0.0-source).
+	if strings.HasPrefix(v.Vers, "v") {
+		// Was built via make with a tagged commit
+		if v.Verbose {
+			return fmt.Sprintf("%s-%s-%s", v.Vers, v.Hash, v.Date)
+		} else {
+			return v.Vers
+		}
+	} else if v.Vers == "tip" {
+		// Was built via make from an untagged commit
+		v.Vers = "v0.0.0"
+		if v.Verbose {
+			return fmt.Sprintf("%s-%s-%s", v.Vers, v.Hash, v.Date)
+		} else {
+			return v.Vers
+		}
+	} else {
+		// Was likely built from source
+		v.Vers = "v0.0.0"
+		v.Hash = "source"
+		if v.Verbose {
+			return fmt.Sprintf("%s-%s", v.Vers, v.Hash)
+		} else {
+			return v.Vers
+		}
+	}
+}
diff --git a/cmd/run.go b/cmd/run.go
index 2666cfdc..c4e5cb75 100644
--- a/cmd/run.go
+++ b/cmd/run.go
@@ -15,10 +15,6 @@ import (
 	"knative.dev/kn-plugin-func/progress"
 )
 
-func init() {
-	root.AddCommand(NewRunCmd(newRunClient))
-}
-
 func newRunClient(cfg runConfig) *fn.Client {
 	bc := newBuildConfig()
 	runner := docker.NewRunner()
diff --git a/cmd/version.go b/cmd/version.go
index e53f4e95..465b943a 100644
--- a/cmd/version.go
+++ b/cmd/version.go
@@ -2,88 +2,25 @@ package cmd
 
 import (
 	"fmt"
-	"strings"
 
-	"github.com/ory/viper"
 	"github.com/spf13/cobra"
 )
 
-// metadata about the build process/binary etc.
-// Not populated if building from source with go build.
-// Set by the `make` targets.
-var version = Version{}
-
-// SetMeta is called by `main` with any provided build metadata
-func SetMeta(date, vers, hash string) {
-	version.Date = date // build timestamp
-	version.Vers = vers // version tag
-	version.Hash = hash // git commit hash
-}
-
-func init() {
-	root.AddCommand(versionCmd)
-}
+func NewVersionCmd(version Version) *cobra.Command {
+	runVersion := func(cmd *cobra.Command, args []string) {
+		fmt.Println(version)
+	}
 
-var versionCmd = &cobra.Command{
-	Use:   "version",
-	Short: "Show the version",
-	Long: `Show the version
+	cmd := &cobra.Command{
+		Use:   "version",
+		Short: "Show the version",
+		Long: `Show the version
 
 Use the --verbose option to include the build date stamp and commit hash"
 `,
-	SuggestFor: []string{"vers", "verison"},
-	Run:        runVersion,
-}
-
-func runVersion(cmd *cobra.Command, args []string) {
-	// update version with the value of the (global) flag 'verbose'
-	version.Verbose = viper.GetBool("verbose")
-
-	// version is the metadata, serialized.
-	fmt.Println(version)
-}
-
-// versionMetadata is set by the main package.
-// When compiled from source, they remain the zero value.
-// When compiled via `make`, they are initialized to the noted values.
-type Version struct {
-	// Date of compilation
-	Date string
-	// Version tag of the git commit, or 'tip' if no tag.
-	Vers string
-	// Hash of the currently active git commit on build.
-	Hash string
-	// Verbose printing enabled for the string representation.
-	Verbose bool
-}
-
-func (v Version) String() string {
-	// If 'vers' is not a semver already, then the binary was built either
-	// from an untagged git commit (set semver to v0.0.0), or was built
-	// directly from source (set semver to v0.0.0-source).
-	if strings.HasPrefix(v.Vers, "v") {
-		// Was built via make with a tagged commit
-		if v.Verbose {
-			return fmt.Sprintf("%s-%s-%s", v.Vers, v.Hash, v.Date)
-		} else {
-			return v.Vers
-		}
-	} else if v.Vers == "tip" {
-		// Was built via make from an untagged commit
-		v.Vers = "v0.0.0"
-		if v.Verbose {
-			return fmt.Sprintf("%s-%s-%s", v.Vers, v.Hash, v.Date)
-		} else {
-			return v.Vers
-		}
-	} else {
-		// Was likely built from source
-		v.Vers = "v0.0.0"
-		v.Hash = "source"
-		if v.Verbose {
-			return fmt.Sprintf("%s-%s", v.Vers, v.Hash)
-		} else {
-			return v.Vers
-		}
+		SuggestFor: []string{"vers", "verison"}, //nolint:misspell
+		Run:        runVersion,
 	}
+
+	return cmd
 }
diff --git a/docs/installing_cli.md b/docs/installing_cli.md
index 4cfaaaa4..0b51cf30 100644
--- a/docs/installing_cli.md
+++ b/docs/installing_cli.md
@@ -23,3 +23,5 @@ make
 mv func /usr/local/bin/
 ```
 
+## Integration with `kn`
+See [plugins](https://github.com/knative/client/blob/main/docs/README.md#plugin-configuration) section of `kn`
diff --git a/function.go b/function.go
index 84737137..949bb3ef 100644
--- a/function.go
+++ b/function.go
@@ -20,7 +20,7 @@ type Function struct {
 	// Version at which this function is known to be compatible.
 	// More specifically, it is the highest migration which has been applied.
 	// For details see the .Migrated() and .Migrate() methods.
-	Version string // semver format
+	Version string `yaml:"version"` // semver format
 
 	// Root on disk at which to find/create source and config files.
 	Root string `yaml:"-"`
@@ -40,7 +40,7 @@ type Function struct {
 
 	// Registry at which to store interstitial containers, in the form
 	// [registry]/[user].
-	Registry string
+	Registry string `yaml:"registry"`
 
 	// Optional full OCI image tag in form:
 	//   [registry]/[namespace]/[name]:[tag]
@@ -99,7 +99,7 @@ type Function struct {
 	// Created time is the moment that creation was successfully completed
 	// according to the client which is in charge of what constitutes being
 	// fully "Created" (aka initialized)
-	Created time.Time
+	Created time.Time `yaml:"created"`
 
 	// Invocation defines hints for use when invoking this function.
 	// See Client.Invoke for usage.
diff --git a/plugin/plugin.go b/plugin/plugin.go
index 2f4e0036..3fb43919 100644
--- a/plugin/plugin.go
+++ b/plugin/plugin.go
@@ -35,13 +35,19 @@ func (f *funcPlugin) Execute(args []string) error {
 		cancel()
 	}()
 
-	rootCmd, _ := cmd.NewRootCmd()
+	rootConfig := cmd.RootCommandConfig{
+		Name: "kn func",
+	}
+
 	info, _ := debug.ReadBuildInfo()
 	for _, dep := range info.Deps {
 		if strings.Contains(dep.Path, "knative.dev/kn-plugin-func") {
-			cmd.SetMeta("", dep.Version, dep.Sum)
+			rootConfig.Version, rootConfig.Hash = dep.Version, dep.Sum
 		}
 	}
+
+	rootCmd, _ := cmd.NewRootCmd(rootConfig)
+
 	oldArgs := os.Args
 	defer (func() {
 		os.Args = oldArgs
diff --git a/schema/func_yaml-schema.json b/schema/func_yaml-schema.json
index 0a2e27a4..c2cc2fa3 100644
--- a/schema/func_yaml-schema.json
+++ b/schema/func_yaml-schema.json
@@ -20,11 +20,11 @@
 		},
 		"Function": {
 			"required": [
-				"Version",
+				"version",
 				"name",
 				"namespace",
 				"runtime",
-				"Registry",
+				"registry",
 				"image",
 				"imageDigest",
 				"build",
@@ -39,10 +39,10 @@
 				"options",
 				"labels",
 				"healthEndpoints",
-				"Created"
+				"created"
 			],
 			"properties": {
-				"Version": {
+				"version": {
 					"type": "string"
 				},
 				"name": {
@@ -55,7 +55,7 @@
 				"runtime": {
 					"type": "string"
 				},
-				"Registry": {
+				"registry": {
 					"type": "string"
 				},
 				"image": {
@@ -135,7 +135,7 @@
 					"$schema": "http://json-schema.org/draft-04/schema#",
 					"$ref": "#/definitions/HealthEndpoints"
 				},
-				"Created": {
+				"created": {
 					"type": "string",
 					"format": "date-time"
 				},
diff --git a/templates/python/manifest.yaml b/templates/python/manifest.yaml
index 796cb173..39b269dc 100644
--- a/templates/python/manifest.yaml
+++ b/templates/python/manifest.yaml
@@ -1,2 +1,2 @@
 builders:
-  default: quay.io/boson/faas-python-builder:v0.8.4
+  default: quay.io/boson/faas-python-builder:v0.9.2
diff --git a/templates/quarkus/cloudevents/manifest.yaml b/templates/quarkus/cloudevents/manifest.yaml
index 92626191..a9f1c13b 100644
--- a/templates/quarkus/cloudevents/manifest.yaml
+++ b/templates/quarkus/cloudevents/manifest.yaml
@@ -1,7 +1,7 @@
 builders:
-  default: quay.io/boson/faas-jvm-builder:v0.8.4
-  jvm: quay.io/boson/faas-jvm-builder:v0.8.4
-  native: quay.io/boson/faas-quarkus-native-builder:v0.8.4
+  default: quay.io/boson/faas-jvm-builder:v0.9.2
+  jvm: quay.io/boson/faas-jvm-builder:v0.9.2
+  native: quay.io/boson/faas-quarkus-native-builder:v0.9.2
 
 invocation:
   format: "cloudevent"
diff --git a/templates/quarkus/manifest.yaml b/templates/quarkus/manifest.yaml
index 9bc6c6ee..d6b6ec17 100644
--- a/templates/quarkus/manifest.yaml
+++ b/templates/quarkus/manifest.yaml
@@ -1,4 +1,4 @@
 builders:
-  default: quay.io/boson/faas-jvm-builder:v0.8.4
-  jvm: quay.io/boson/faas-jvm-builder:v0.8.4
-  native: quay.io/boson/faas-quarkus-native-builder:v0.8.4
+  default: quay.io/boson/faas-jvm-builder:v0.9.2
+  jvm: quay.io/boson/faas-jvm-builder:v0.9.2
+  native: quay.io/boson/faas-quarkus-native-builder:v0.9.2


Test patch:
diff --git a/cmd/root_test.go b/cmd/root_test.go
index 8c5c3532..fcad03a0 100644
--- a/cmd/root_test.go
+++ b/cmd/root_test.go
@@ -120,6 +120,11 @@ func TestRoot_mergeEnvMaps(t *testing.T) {
 
 func TestRoot_CMDParameterized(t *testing.T) {
 
+	rootConfig := RootCommandConfig{
+		Name: "func",
+	}
+
+	root, _ := NewRootCmd(rootConfig)
 	if root.Use != "func" {
 		t.Fatalf("default command use should be \"func\".")
 	}
@@ -129,13 +134,17 @@ func TestRoot_CMDParameterized(t *testing.T) {
 		t.Fatalf("default command example should assume \"func\" as executable name. error: %v", err)
 	}
 
-	cmd, err := NewRootCmd()
+	rootConfig = RootCommandConfig{
+		Name: "kn func",
+	}
+
+	cmd, err := NewRootCmd(rootConfig)
 	if cmd.Use != "kn func" && err != nil {
 		t.Fatalf("plugin command use should be \"kn func\".")
 	}
 
 	usageExample, _ = replaceNameInTemplate("kn func", "example")
-	cmd, err = NewRootCmd()
+	cmd, err = NewRootCmd(rootConfig)
 	if cmd.Example != usageExample || err != nil {
 		t.Fatalf("plugin command example should assume \"kn func\" as executable name. error: %v", err)
 	}