From 6acf8ec0101f6f01e6ae022462e17ed9e48b5eaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Tue, 16 Jun 2020 11:28:23 +0200 Subject: [PATCH 01/20] Add grouping for help message + streamlined help messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The top-level looks like kn is the command line interface for managing Knative Serving and Eventing objects Find more information about Knative at: https://knative.dev Serving Commands: service Manage Knative services revision Manage service revisions route List and show service routes Eventing Commands: source Manage event sources trigger Manage event triggers Other Commands: plugin Manage kn plugins completion Output shell completion code version Show the version of this client Use "kn --help" for more information about a given command. Use "kn options" for a list of global command-line options (applies to all commands). The following changes have been applied: * Add CommandGroups for grouping commands together * Add flexible templating for the help messages * Moved global options to an own command ('kn options', much like 'kubectl options') * Aligned wording and typography of help messages These features has been highly inspired by kubectl grouping & help templating but has been considerably been stripped down to the needs of kn. Signed-off-by: Roland Huß --- cmd/kn/main.go | 24 ++- docs/cmd/kn.md | 22 +- docs/cmd/kn_completion.md | 4 +- docs/cmd/kn_plugin.md | 10 +- docs/cmd/kn_plugin_list.md | 6 +- docs/cmd/kn_revision.md | 12 +- docs/cmd/kn_revision_delete.md | 8 +- docs/cmd/kn_revision_describe.md | 4 +- docs/cmd/kn_revision_list.md | 6 +- docs/cmd/kn_route.md | 10 +- docs/cmd/kn_route_describe.md | 4 +- docs/cmd/kn_route_list.md | 8 +- docs/cmd/kn_service.md | 18 +- docs/cmd/kn_service_create.md | 8 +- docs/cmd/kn_service_delete.md | 8 +- docs/cmd/kn_service_describe.md | 4 +- docs/cmd/kn_service_export.md | 8 +- docs/cmd/kn_service_list.md | 8 +- docs/cmd/kn_service_update.md | 8 +- docs/cmd/kn_source.md | 18 +- docs/cmd/kn_source_apiserver.md | 18 +- docs/cmd/kn_source_apiserver_create.md | 8 +- docs/cmd/kn_source_apiserver_delete.md | 8 +- docs/cmd/kn_source_apiserver_describe.md | 8 +- docs/cmd/kn_source_apiserver_list.md | 8 +- docs/cmd/kn_source_apiserver_update.md | 8 +- docs/cmd/kn_source_binding.md | 16 +- docs/cmd/kn_source_binding_create.md | 8 +- docs/cmd/kn_source_binding_delete.md | 8 +- docs/cmd/kn_source_binding_describe.md | 4 +- docs/cmd/kn_source_binding_list.md | 8 +- docs/cmd/kn_source_binding_update.md | 8 +- docs/cmd/kn_source_list-types.md | 12 +- docs/cmd/kn_source_list.md | 8 +- docs/cmd/kn_source_ping.md | 18 +- docs/cmd/kn_source_ping_create.md | 8 +- docs/cmd/kn_source_ping_delete.md | 8 +- docs/cmd/kn_source_ping_describe.md | 8 +- docs/cmd/kn_source_ping_list.md | 8 +- docs/cmd/kn_source_ping_update.md | 8 +- docs/cmd/kn_trigger.md | 12 +- docs/cmd/kn_trigger_create.md | 4 +- docs/cmd/kn_trigger_delete.md | 8 +- docs/cmd/kn_trigger_describe.md | 4 +- docs/cmd/kn_trigger_list.md | 8 +- docs/cmd/kn_trigger_update.md | 4 +- docs/cmd/kn_version.md | 8 +- pkg/kn/commands/completion/completion.go | 15 +- pkg/kn/commands/completion/completion_test.go | 18 +- pkg/kn/commands/options/options.go | 50 +++++ pkg/kn/commands/plugin/list.go | 2 +- pkg/kn/commands/plugin/plugin.go | 6 +- pkg/kn/commands/revision/delete.go | 2 +- pkg/kn/commands/revision/list.go | 4 +- pkg/kn/commands/revision/revision.go | 2 +- pkg/kn/commands/route/list.go | 2 +- pkg/kn/commands/route/route.go | 2 +- pkg/kn/commands/service/create.go | 2 +- pkg/kn/commands/service/delete.go | 2 +- pkg/kn/commands/service/export.go | 2 +- pkg/kn/commands/service/list.go | 4 +- pkg/kn/commands/service/service.go | 2 +- pkg/kn/commands/service/update.go | 4 +- pkg/kn/commands/source/apiserver/apiserver.go | 4 +- pkg/kn/commands/source/apiserver/create.go | 4 +- pkg/kn/commands/source/apiserver/delete.go | 2 +- pkg/kn/commands/source/apiserver/describe.go | 2 +- pkg/kn/commands/source/apiserver/list.go | 2 +- pkg/kn/commands/source/apiserver/update.go | 4 +- pkg/kn/commands/source/binding/binding.go | 4 +- pkg/kn/commands/source/binding/create.go | 4 +- pkg/kn/commands/source/binding/delete.go | 2 +- pkg/kn/commands/source/binding/list.go | 2 +- pkg/kn/commands/source/binding/update.go | 4 +- pkg/kn/commands/source/list.go | 2 +- pkg/kn/commands/source/list_types.go | 6 +- pkg/kn/commands/source/ping/create.go | 4 +- pkg/kn/commands/source/ping/delete.go | 2 +- pkg/kn/commands/source/ping/describe.go | 2 +- pkg/kn/commands/source/ping/list.go | 2 +- pkg/kn/commands/source/ping/ping.go | 4 +- pkg/kn/commands/source/ping/update.go | 4 +- pkg/kn/commands/source/source.go | 4 +- pkg/kn/commands/trigger/create.go | 2 +- pkg/kn/commands/trigger/delete.go | 2 +- pkg/kn/commands/trigger/list.go | 4 +- pkg/kn/commands/trigger/trigger.go | 2 +- pkg/kn/commands/trigger/update.go | 2 +- pkg/kn/commands/version/version.go | 2 +- pkg/kn/commands/version/version_test.go | 3 +- pkg/kn/root/root.go | 71 +++---- pkg/kn/root/root_test.go | 2 +- pkg/templates/command_groups.go | 66 ++++++ pkg/templates/template_engine.go | 190 ++++++++++++++++++ pkg/templates/templates.go | 95 +++++++++ 95 files changed, 741 insertions(+), 317 deletions(-) create mode 100644 pkg/kn/commands/options/options.go create mode 100644 pkg/templates/command_groups.go create mode 100644 pkg/templates/template_engine.go create mode 100644 pkg/templates/templates.go diff --git a/cmd/kn/main.go b/cmd/kn/main.go index 36883674d8..48a5991eec 100644 --- a/cmd/kn/main.go +++ b/cmd/kn/main.go @@ -18,6 +18,7 @@ import ( "fmt" "math/rand" "os" + "regexp" "strings" "time" @@ -35,8 +36,9 @@ func init() { func main() { err := run(os.Args[1:]) - if err != nil { + if err != nil && len(os.Args) > 1 { fmt.Fprintf(os.Stderr, "Error: %v\n", err) + fmt.Fprintf(os.Stderr, "Run '%s --help' for usage\n", extractCommandPathFromErrorMessage(err.Error(), os.Args[0])) // This is the only point from where to exit when an error occurs os.Exit(1) } @@ -106,8 +108,14 @@ func stripFlags(args []string) ([]string, error) { *commandsFound = append(*commandsFound, arg) } }, + SilenceErrors: true, + SilenceUsage: true, } + // No help and usage functions to prin + extractCommand.SetHelpFunc(func(*cobra.Command, []string) {}) + extractCommand.SetUsageFunc(func(*cobra.Command) error { return nil }) + // Filter out --help and -h options to avoid special treatment which we don't // need here extractCommand.SetArgs(filterHelpOptions(args)) @@ -172,10 +180,22 @@ func validateRootCommand(cmd *cobra.Command) error { if err == nil && foundCmd.HasSubCommands() && len(innerArgs) > 0 { argsWithoutFlags, err := stripFlags(innerArgs) if len(argsWithoutFlags) > 0 || err != nil { - return errors.Errorf("unknown sub-command '%s' for '%s'. Available sub-commands: %s", innerArgs[0], foundCmd.Name(), strings.Join(root.ExtractSubCommandNames(foundCmd.Commands()), ", ")) + return errors.Errorf("unknown sub-command '%s' for '%s'. Available sub-commands: %s", innerArgs[0], foundCmd.CommandPath(), strings.Join(root.ExtractSubCommandNames(foundCmd.Commands()), ", ")) } // If no args where given (only flags), then fall through to execute the command itself, which leads to // a more appropriate error message } return nil } + +// extractCommandPathFromErrorMessage tries to extract the command name from an error message +// by checking a pattern like 'kn service' in the error message. If not found, return the +// base command name. +func extractCommandPathFromErrorMessage(errorMsg string, arg0 string) string { + extractPattern := regexp.MustCompile(fmt.Sprintf("'(%s\\s.+?)'", arg0)) + command := extractPattern.FindSubmatch([]byte(errorMsg)) + if command != nil { + return string(command[1]) + } + return arg0 +} diff --git a/docs/cmd/kn.md b/docs/cmd/kn.md index 3c45095896..eecf628f83 100644 --- a/docs/cmd/kn.md +++ b/docs/cmd/kn.md @@ -1,13 +1,12 @@ ## kn -Knative client +kn manages Knative Serving and Eventing resources ### Synopsis -Manage your Knative building blocks: +kn is the command line interface for managing Knative Serving and Eventing resources -* Serving: Manage your services and release new software to them. -* Eventing: Manage event subscriptions and channels. Connect up event sources. + Find more information about Knative at: https://knative.dev ### Options @@ -21,11 +20,12 @@ Manage your Knative building blocks: ### SEE ALSO * [kn completion](kn_completion.md) - Output shell completion code -* [kn plugin](kn_plugin.md) - Plugin command group -* [kn revision](kn_revision.md) - Revision command group -* [kn route](kn_route.md) - Route command group -* [kn service](kn_service.md) - Service command group -* [kn source](kn_source.md) - Event source command group -* [kn trigger](kn_trigger.md) - Trigger command group -* [kn version](kn_version.md) - Prints the client version +* [kn options](kn_options.md) - Print the list of flags inherited by all commands +* [kn plugin](kn_plugin.md) - Manage kn plugins +* [kn revision](kn_revision.md) - Manage service revisions +* [kn route](kn_route.md) - List and show service routes +* [kn service](kn_service.md) - Manage Knative services +* [kn source](kn_source.md) - Manage event sources +* [kn trigger](kn_trigger.md) - Manage event triggers +* [kn version](kn_version.md) - Show the version of this client diff --git a/docs/cmd/kn_completion.md b/docs/cmd/kn_completion.md index bf751f438f..5c40e568d3 100644 --- a/docs/cmd/kn_completion.md +++ b/docs/cmd/kn_completion.md @@ -13,7 +13,7 @@ Supported Shells: - zsh ``` -kn completion [SHELL] [flags] +kn completion SHELL ``` ### Examples @@ -44,5 +44,5 @@ kn completion [SHELL] [flags] ### SEE ALSO -* [kn](kn.md) - Knative client +* [kn](kn.md) - kn manages Knative Serving and Eventing resources diff --git a/docs/cmd/kn_plugin.md b/docs/cmd/kn_plugin.md index e5fbcccd0e..2f0470884f 100644 --- a/docs/cmd/kn_plugin.md +++ b/docs/cmd/kn_plugin.md @@ -1,16 +1,16 @@ ## kn plugin -Plugin command group +Manage kn plugins ### Synopsis -Provides utilities for interacting and managing with kn plugins. +Manage kn plugins. Plugins provide extended functionality that is not part of the core kn command-line distribution. -Please refer to the documentation and examples for more information about how write your own plugins. +Please refer to the documentation and examples for more information about how to write your own plugins. ``` -kn plugin [flags] +kn plugin ``` ### Options @@ -29,6 +29,6 @@ kn plugin [flags] ### SEE ALSO -* [kn](kn.md) - Knative client +* [kn](kn.md) - kn manages Knative Serving and Eventing resources * [kn plugin list](kn_plugin_list.md) - List plugins diff --git a/docs/cmd/kn_plugin_list.md b/docs/cmd/kn_plugin_list.md index f424b55053..28009fb524 100644 --- a/docs/cmd/kn_plugin_list.md +++ b/docs/cmd/kn_plugin_list.md @@ -10,10 +10,10 @@ Available plugins are those that are: - executable - begin with "kn-" - Kn's plugin directory -- Anywhere in the execution $PATH (if plugins.path-lookup config variable is enabled) +- Anywhere in the execution $PATH (if plugins.path-lookup configuration variable is enabled) ``` -kn plugin list [flags] +kn plugin list ``` ### Options @@ -33,5 +33,5 @@ kn plugin list [flags] ### SEE ALSO -* [kn plugin](kn_plugin.md) - Plugin command group +* [kn plugin](kn_plugin.md) - Manage kn plugins diff --git a/docs/cmd/kn_revision.md b/docs/cmd/kn_revision.md index 5097d39c32..d264d28385 100644 --- a/docs/cmd/kn_revision.md +++ b/docs/cmd/kn_revision.md @@ -1,13 +1,13 @@ ## kn revision -Revision command group +Manage service revisions ### Synopsis -Revision command group +Manage service revisions ``` -kn revision [flags] +kn revision ``` ### Options @@ -26,8 +26,8 @@ kn revision [flags] ### SEE ALSO -* [kn](kn.md) - Knative client -* [kn revision delete](kn_revision_delete.md) - Delete a revision. +* [kn](kn.md) - kn manages Knative Serving and Eventing resources +* [kn revision delete](kn_revision_delete.md) - Delete a revision * [kn revision describe](kn_revision_describe.md) - Show details of a revision -* [kn revision list](kn_revision_list.md) - List available revisions. +* [kn revision list](kn_revision_list.md) - List revisions diff --git a/docs/cmd/kn_revision_delete.md b/docs/cmd/kn_revision_delete.md index 1d7b55e7d6..504747fb68 100644 --- a/docs/cmd/kn_revision_delete.md +++ b/docs/cmd/kn_revision_delete.md @@ -1,13 +1,13 @@ ## kn revision delete -Delete a revision. +Delete a revision ### Synopsis -Delete a revision. +Delete a revision ``` -kn revision delete NAME [flags] +kn revision delete NAME ``` ### Examples @@ -39,5 +39,5 @@ kn revision delete NAME [flags] ### SEE ALSO -* [kn revision](kn_revision.md) - Revision command group +* [kn revision](kn_revision.md) - Manage service revisions diff --git a/docs/cmd/kn_revision_describe.md b/docs/cmd/kn_revision_describe.md index 933625bd2e..c997b0fda3 100644 --- a/docs/cmd/kn_revision_describe.md +++ b/docs/cmd/kn_revision_describe.md @@ -7,7 +7,7 @@ Show details of a revision Show details of a revision ``` -kn revision describe NAME [flags] +kn revision describe NAME ``` ### Options @@ -31,5 +31,5 @@ kn revision describe NAME [flags] ### SEE ALSO -* [kn revision](kn_revision.md) - Revision command group +* [kn revision](kn_revision.md) - Manage service revisions diff --git a/docs/cmd/kn_revision_list.md b/docs/cmd/kn_revision_list.md index 4984a990b5..2764c26198 100644 --- a/docs/cmd/kn_revision_list.md +++ b/docs/cmd/kn_revision_list.md @@ -1,13 +1,13 @@ ## kn revision list -List available revisions. +List revisions ### Synopsis List revisions for a given service. ``` -kn revision list [name] [flags] +kn revision list ``` ### Examples @@ -50,5 +50,5 @@ kn revision list [name] [flags] ### SEE ALSO -* [kn revision](kn_revision.md) - Revision command group +* [kn revision](kn_revision.md) - Manage service revisions diff --git a/docs/cmd/kn_route.md b/docs/cmd/kn_route.md index d108848434..9a8f11e168 100644 --- a/docs/cmd/kn_route.md +++ b/docs/cmd/kn_route.md @@ -1,13 +1,13 @@ ## kn route -Route command group +List and show service routes ### Synopsis -Route command group +List and show service routes ``` -kn route [flags] +kn route ``` ### Options @@ -26,7 +26,7 @@ kn route [flags] ### SEE ALSO -* [kn](kn.md) - Knative client +* [kn](kn.md) - kn manages Knative Serving and Eventing resources * [kn route describe](kn_route_describe.md) - Show details of a route -* [kn route list](kn_route_list.md) - List available routes. +* [kn route list](kn_route_list.md) - List routes diff --git a/docs/cmd/kn_route_describe.md b/docs/cmd/kn_route_describe.md index 1989872462..946c468a71 100644 --- a/docs/cmd/kn_route_describe.md +++ b/docs/cmd/kn_route_describe.md @@ -7,7 +7,7 @@ Show details of a route Show details of a route ``` -kn route describe NAME [flags] +kn route describe NAME ``` ### Options @@ -31,5 +31,5 @@ kn route describe NAME [flags] ### SEE ALSO -* [kn route](kn_route.md) - Route command group +* [kn route](kn_route.md) - List and show service routes diff --git a/docs/cmd/kn_route_list.md b/docs/cmd/kn_route_list.md index bda0b62704..b120f336fd 100644 --- a/docs/cmd/kn_route_list.md +++ b/docs/cmd/kn_route_list.md @@ -1,13 +1,13 @@ ## kn route list -List available routes. +List routes ### Synopsis -List available routes. +List routes ``` -kn route list NAME [flags] +kn route list NAME ``` ### Examples @@ -46,5 +46,5 @@ kn route list NAME [flags] ### SEE ALSO -* [kn route](kn_route.md) - Route command group +* [kn route](kn_route.md) - List and show service routes diff --git a/docs/cmd/kn_service.md b/docs/cmd/kn_service.md index d7e4563627..dc4f6f0519 100644 --- a/docs/cmd/kn_service.md +++ b/docs/cmd/kn_service.md @@ -1,13 +1,13 @@ ## kn service -Service command group +Manage Knative services ### Synopsis -Service command group +Manage Knative services ``` -kn service [flags] +kn service ``` ### Options @@ -26,11 +26,11 @@ kn service [flags] ### SEE ALSO -* [kn](kn.md) - Knative client -* [kn service create](kn_service_create.md) - Create a service. -* [kn service delete](kn_service_delete.md) - Delete a service. +* [kn](kn.md) - kn manages Knative Serving and Eventing resources +* [kn service create](kn_service_create.md) - Create a service +* [kn service delete](kn_service_delete.md) - Delete a service * [kn service describe](kn_service_describe.md) - Show details of a service -* [kn service export](kn_service_export.md) - Export a service. -* [kn service list](kn_service_list.md) - List available services. -* [kn service update](kn_service_update.md) - Update a service. +* [kn service export](kn_service_export.md) - Export a service and its revisions +* [kn service list](kn_service_list.md) - List available services +* [kn service update](kn_service_update.md) - Update a service diff --git a/docs/cmd/kn_service_create.md b/docs/cmd/kn_service_create.md index ff970191f8..4bfb25ff1f 100644 --- a/docs/cmd/kn_service_create.md +++ b/docs/cmd/kn_service_create.md @@ -1,13 +1,13 @@ ## kn service create -Create a service. +Create a service ### Synopsis -Create a service. +Create a service ``` -kn service create NAME --image IMAGE [flags] +kn service create NAME --image IMAGE ``` ### Examples @@ -101,5 +101,5 @@ kn service create NAME --image IMAGE [flags] ### SEE ALSO -* [kn service](kn_service.md) - Service command group +* [kn service](kn_service.md) - Manage Knative services diff --git a/docs/cmd/kn_service_delete.md b/docs/cmd/kn_service_delete.md index 56fed786e8..c31fe4adeb 100644 --- a/docs/cmd/kn_service_delete.md +++ b/docs/cmd/kn_service_delete.md @@ -1,13 +1,13 @@ ## kn service delete -Delete a service. +Delete a service ### Synopsis -Delete a service. +Delete a service ``` -kn service delete NAME [flags] +kn service delete NAME ``` ### Examples @@ -46,5 +46,5 @@ kn service delete NAME [flags] ### SEE ALSO -* [kn service](kn_service.md) - Service command group +* [kn service](kn_service.md) - Manage Knative services diff --git a/docs/cmd/kn_service_describe.md b/docs/cmd/kn_service_describe.md index fe5db58aea..4f9d274a41 100644 --- a/docs/cmd/kn_service_describe.md +++ b/docs/cmd/kn_service_describe.md @@ -7,7 +7,7 @@ Show details of a service Show details of a service ``` -kn service describe NAME [flags] +kn service describe NAME ``` ### Options @@ -31,5 +31,5 @@ kn service describe NAME [flags] ### SEE ALSO -* [kn service](kn_service.md) - Service command group +* [kn service](kn_service.md) - Manage Knative services diff --git a/docs/cmd/kn_service_export.md b/docs/cmd/kn_service_export.md index ffa9d20c65..404919a347 100644 --- a/docs/cmd/kn_service_export.md +++ b/docs/cmd/kn_service_export.md @@ -1,13 +1,13 @@ ## kn service export -Export a service. +Export a service and its revisions ### Synopsis -Export a service. +Export a service and its revisions ``` -kn service export NAME [flags] +kn service export NAME ``` ### Examples @@ -46,5 +46,5 @@ kn service export NAME [flags] ### SEE ALSO -* [kn service](kn_service.md) - Service command group +* [kn service](kn_service.md) - Manage Knative services diff --git a/docs/cmd/kn_service_list.md b/docs/cmd/kn_service_list.md index 0e4fca7666..d9199e2c4c 100644 --- a/docs/cmd/kn_service_list.md +++ b/docs/cmd/kn_service_list.md @@ -1,13 +1,13 @@ ## kn service list -List available services. +List available services ### Synopsis -List available services. +List available services ``` -kn service list [name] [flags] +kn service list ``` ### Examples @@ -46,5 +46,5 @@ kn service list [name] [flags] ### SEE ALSO -* [kn service](kn_service.md) - Service command group +* [kn service](kn_service.md) - Manage Knative services diff --git a/docs/cmd/kn_service_update.md b/docs/cmd/kn_service_update.md index 9d90996501..22763af3aa 100644 --- a/docs/cmd/kn_service_update.md +++ b/docs/cmd/kn_service_update.md @@ -1,13 +1,13 @@ ## kn service update -Update a service. +Update a service ### Synopsis -Update a service. +Update a service ``` -kn service update NAME [flags] +kn service update NAME ``` ### Examples @@ -91,5 +91,5 @@ kn service update NAME [flags] ### SEE ALSO -* [kn service](kn_service.md) - Service command group +* [kn service](kn_service.md) - Manage Knative services diff --git a/docs/cmd/kn_source.md b/docs/cmd/kn_source.md index c375311906..8eece17416 100644 --- a/docs/cmd/kn_source.md +++ b/docs/cmd/kn_source.md @@ -1,13 +1,13 @@ ## kn source -Event source command group +Manage event sources ### Synopsis -Event source command group +Manage event sources ``` -kn source [flags] +kn source SOURCE|COMMAND ``` ### Options @@ -26,10 +26,10 @@ kn source [flags] ### SEE ALSO -* [kn](kn.md) - Knative client -* [kn source apiserver](kn_source_apiserver.md) - Kubernetes API Server Event Source command group -* [kn source binding](kn_source_binding.md) - Sink binding command group -* [kn source list](kn_source_list.md) - List available sources -* [kn source list-types](kn_source_list-types.md) - List available source types -* [kn source ping](kn_source_ping.md) - Ping source command group +* [kn](kn.md) - kn manages Knative Serving and Eventing resources +* [kn source apiserver](kn_source_apiserver.md) - Manage Kubernetes api-server sources +* [kn source binding](kn_source_binding.md) - Manage sink bindings +* [kn source list](kn_source_list.md) - List event sources +* [kn source list-types](kn_source_list-types.md) - List event source types +* [kn source ping](kn_source_ping.md) - Manage ping sources diff --git a/docs/cmd/kn_source_apiserver.md b/docs/cmd/kn_source_apiserver.md index 89e9cd5d01..78a285a6fb 100644 --- a/docs/cmd/kn_source_apiserver.md +++ b/docs/cmd/kn_source_apiserver.md @@ -1,13 +1,13 @@ ## kn source apiserver -Kubernetes API Server Event Source command group +Manage Kubernetes api-server sources ### Synopsis -Kubernetes API Server Event Source command group +Manage Kubernetes api-server sources ``` -kn source apiserver [flags] +kn source apiserver COMMAND ``` ### Options @@ -26,10 +26,10 @@ kn source apiserver [flags] ### SEE ALSO -* [kn source](kn_source.md) - Event source command group -* [kn source apiserver create](kn_source_apiserver_create.md) - Create an ApiServer source. -* [kn source apiserver delete](kn_source_apiserver_delete.md) - Delete an ApiServer source. -* [kn source apiserver describe](kn_source_apiserver_describe.md) - Show details of an ApiServer source -* [kn source apiserver list](kn_source_apiserver_list.md) - List ApiServer sources. -* [kn source apiserver update](kn_source_apiserver_update.md) - Update an ApiServer source. +* [kn source](kn_source.md) - Manage event sources +* [kn source apiserver create](kn_source_apiserver_create.md) - Create an api-server source +* [kn source apiserver delete](kn_source_apiserver_delete.md) - Delete api-server sources +* [kn source apiserver describe](kn_source_apiserver_describe.md) - Show details of an api-server source +* [kn source apiserver list](kn_source_apiserver_list.md) - List api-server sources +* [kn source apiserver update](kn_source_apiserver_update.md) - Update an api-server source diff --git a/docs/cmd/kn_source_apiserver_create.md b/docs/cmd/kn_source_apiserver_create.md index e1eea6dd5d..be0d6a66d7 100644 --- a/docs/cmd/kn_source_apiserver_create.md +++ b/docs/cmd/kn_source_apiserver_create.md @@ -1,13 +1,13 @@ ## kn source apiserver create -Create an ApiServer source. +Create an api-server source ### Synopsis -Create an ApiServer source. +Create an api-server source ``` -kn source apiserver create NAME --resource RESOURCE --service-account ACCOUNTNAME --sink SINK --mode MODE [flags] +kn source apiserver create NAME --resource RESOURCE --sink SINK ``` ### Examples @@ -43,5 +43,5 @@ kn source apiserver create NAME --resource RESOURCE --service-account ACCOUNTNAM ### SEE ALSO -* [kn source apiserver](kn_source_apiserver.md) - Kubernetes API Server Event Source command group +* [kn source apiserver](kn_source_apiserver.md) - Manage Kubernetes api-server sources diff --git a/docs/cmd/kn_source_apiserver_delete.md b/docs/cmd/kn_source_apiserver_delete.md index 45820828e6..4e9533c03c 100644 --- a/docs/cmd/kn_source_apiserver_delete.md +++ b/docs/cmd/kn_source_apiserver_delete.md @@ -1,13 +1,13 @@ ## kn source apiserver delete -Delete an ApiServer source. +Delete api-server sources ### Synopsis -Delete an ApiServer source. +Delete api-server sources ``` -kn source apiserver delete NAME [flags] +kn source apiserver delete NAME ``` ### Examples @@ -35,5 +35,5 @@ kn source apiserver delete NAME [flags] ### SEE ALSO -* [kn source apiserver](kn_source_apiserver.md) - Kubernetes API Server Event Source command group +* [kn source apiserver](kn_source_apiserver.md) - Manage Kubernetes api-server sources diff --git a/docs/cmd/kn_source_apiserver_describe.md b/docs/cmd/kn_source_apiserver_describe.md index d214ed9eed..d681c6e480 100644 --- a/docs/cmd/kn_source_apiserver_describe.md +++ b/docs/cmd/kn_source_apiserver_describe.md @@ -1,13 +1,13 @@ ## kn source apiserver describe -Show details of an ApiServer source +Show details of an api-server source ### Synopsis -Show details of an ApiServer source +Show details of an api-server source ``` -kn source apiserver describe NAME [flags] +kn source apiserver describe NAME ``` ### Examples @@ -36,5 +36,5 @@ kn source apiserver describe NAME [flags] ### SEE ALSO -* [kn source apiserver](kn_source_apiserver.md) - Kubernetes API Server Event Source command group +* [kn source apiserver](kn_source_apiserver.md) - Manage Kubernetes api-server sources diff --git a/docs/cmd/kn_source_apiserver_list.md b/docs/cmd/kn_source_apiserver_list.md index 5fc4c20407..523f8d5e4f 100644 --- a/docs/cmd/kn_source_apiserver_list.md +++ b/docs/cmd/kn_source_apiserver_list.md @@ -1,13 +1,13 @@ ## kn source apiserver list -List ApiServer sources. +List api-server sources ### Synopsis -List ApiServer sources. +List api-server sources ``` -kn source apiserver list [flags] +kn source apiserver list ``` ### Examples @@ -43,5 +43,5 @@ kn source apiserver list [flags] ### SEE ALSO -* [kn source apiserver](kn_source_apiserver.md) - Kubernetes API Server Event Source command group +* [kn source apiserver](kn_source_apiserver.md) - Manage Kubernetes api-server sources diff --git a/docs/cmd/kn_source_apiserver_update.md b/docs/cmd/kn_source_apiserver_update.md index 959efccb0d..ef77284a0d 100644 --- a/docs/cmd/kn_source_apiserver_update.md +++ b/docs/cmd/kn_source_apiserver_update.md @@ -1,13 +1,13 @@ ## kn source apiserver update -Update an ApiServer source. +Update an api-server source ### Synopsis -Update an ApiServer source. +Update an api-server source ``` -kn source apiserver update NAME --resource RESOURCE --service-account ACCOUNTNAME --sink SINK --mode MODE [flags] +kn source apiserver update NAME ``` ### Examples @@ -43,5 +43,5 @@ kn source apiserver update NAME --resource RESOURCE --service-account ACCOUNTNAM ### SEE ALSO -* [kn source apiserver](kn_source_apiserver.md) - Kubernetes API Server Event Source command group +* [kn source apiserver](kn_source_apiserver.md) - Manage Kubernetes api-server sources diff --git a/docs/cmd/kn_source_binding.md b/docs/cmd/kn_source_binding.md index cbe18cc8e7..0205448724 100644 --- a/docs/cmd/kn_source_binding.md +++ b/docs/cmd/kn_source_binding.md @@ -1,13 +1,13 @@ ## kn source binding -Sink binding command group +Manage sink bindings ### Synopsis -Sink binding command group +Manage sink bindings ``` -kn source binding [flags] +kn source binding COMMAND ``` ### Options @@ -26,10 +26,10 @@ kn source binding [flags] ### SEE ALSO -* [kn source](kn_source.md) - Event source command group -* [kn source binding create](kn_source_binding_create.md) - Create a sink binding. -* [kn source binding delete](kn_source_binding_delete.md) - Delete a sink binding. +* [kn source](kn_source.md) - Manage event sources +* [kn source binding create](kn_source_binding_create.md) - Create a sink binding +* [kn source binding delete](kn_source_binding_delete.md) - Delete a sink binding * [kn source binding describe](kn_source_binding_describe.md) - Show details of a sink binding -* [kn source binding list](kn_source_binding_list.md) - List sink bindings. -* [kn source binding update](kn_source_binding_update.md) - Update a sink binding. +* [kn source binding list](kn_source_binding_list.md) - List sink bindings +* [kn source binding update](kn_source_binding_update.md) - Update a sink binding diff --git a/docs/cmd/kn_source_binding_create.md b/docs/cmd/kn_source_binding_create.md index 040e40a182..6f616eba20 100644 --- a/docs/cmd/kn_source_binding_create.md +++ b/docs/cmd/kn_source_binding_create.md @@ -1,13 +1,13 @@ ## kn source binding create -Create a sink binding. +Create a sink binding ### Synopsis -Create a sink binding. +Create a sink binding ``` -kn source binding create NAME --subject SUBJECT --sink SINK --ce-override KEY=VALUE [flags] +kn source binding create NAME --subject SUBJECT --sink SINK ``` ### Examples @@ -38,5 +38,5 @@ kn source binding create NAME --subject SUBJECT --sink SINK --ce-override KEY=VA ### SEE ALSO -* [kn source binding](kn_source_binding.md) - Sink binding command group +* [kn source binding](kn_source_binding.md) - Manage sink bindings diff --git a/docs/cmd/kn_source_binding_delete.md b/docs/cmd/kn_source_binding_delete.md index 349a75c85f..880092ffa5 100644 --- a/docs/cmd/kn_source_binding_delete.md +++ b/docs/cmd/kn_source_binding_delete.md @@ -1,13 +1,13 @@ ## kn source binding delete -Delete a sink binding. +Delete a sink binding ### Synopsis -Delete a sink binding. +Delete a sink binding ``` -kn source binding delete NAME [flags] +kn source binding delete NAME ``` ### Examples @@ -35,5 +35,5 @@ kn source binding delete NAME [flags] ### SEE ALSO -* [kn source binding](kn_source_binding.md) - Sink binding command group +* [kn source binding](kn_source_binding.md) - Manage sink bindings diff --git a/docs/cmd/kn_source_binding_describe.md b/docs/cmd/kn_source_binding_describe.md index b0a0ee1717..fe762f14df 100644 --- a/docs/cmd/kn_source_binding_describe.md +++ b/docs/cmd/kn_source_binding_describe.md @@ -7,7 +7,7 @@ Show details of a sink binding Show details of a sink binding ``` -kn source binding describe NAME [flags] +kn source binding describe NAME ``` ### Examples @@ -36,5 +36,5 @@ kn source binding describe NAME [flags] ### SEE ALSO -* [kn source binding](kn_source_binding.md) - Sink binding command group +* [kn source binding](kn_source_binding.md) - Manage sink bindings diff --git a/docs/cmd/kn_source_binding_list.md b/docs/cmd/kn_source_binding_list.md index 9400f435c0..f5b71cd1f7 100644 --- a/docs/cmd/kn_source_binding_list.md +++ b/docs/cmd/kn_source_binding_list.md @@ -1,13 +1,13 @@ ## kn source binding list -List sink bindings. +List sink bindings ### Synopsis -List sink bindings. +List sink bindings ``` -kn source binding list [flags] +kn source binding list ``` ### Examples @@ -43,5 +43,5 @@ kn source binding list [flags] ### SEE ALSO -* [kn source binding](kn_source_binding.md) - Sink binding command group +* [kn source binding](kn_source_binding.md) - Manage sink bindings diff --git a/docs/cmd/kn_source_binding_update.md b/docs/cmd/kn_source_binding_update.md index b537e45331..0f1f2f6915 100644 --- a/docs/cmd/kn_source_binding_update.md +++ b/docs/cmd/kn_source_binding_update.md @@ -1,13 +1,13 @@ ## kn source binding update -Update a sink binding. +Update a sink binding ### Synopsis -Update a sink binding. +Update a sink binding ``` -kn source binding update NAME --subject SCHEDULE --sink SINK --ce-override OVERRIDE [flags] +kn source binding update NAME ``` ### Examples @@ -38,5 +38,5 @@ kn source binding update NAME --subject SCHEDULE --sink SINK --ce-override OVERR ### SEE ALSO -* [kn source binding](kn_source_binding.md) - Sink binding command group +* [kn source binding](kn_source_binding.md) - Manage sink bindings diff --git a/docs/cmd/kn_source_list-types.md b/docs/cmd/kn_source_list-types.md index f844b24fb0..a4a52c0765 100644 --- a/docs/cmd/kn_source_list-types.md +++ b/docs/cmd/kn_source_list-types.md @@ -1,23 +1,23 @@ ## kn source list-types -List available source types +List event source types ### Synopsis -List available source types +List event source types ``` -kn source list-types [flags] +kn source list-types ``` ### Examples ``` - # List available eventing source types + # List available event source types kn source list-types - # List available eventing source types in YAML format + # List available event source types in YAML format kn source list-types -o yaml ``` @@ -42,5 +42,5 @@ kn source list-types [flags] ### SEE ALSO -* [kn source](kn_source.md) - Event source command group +* [kn source](kn_source.md) - Manage event sources diff --git a/docs/cmd/kn_source_list.md b/docs/cmd/kn_source_list.md index 1686ec94b3..8053e9c41d 100644 --- a/docs/cmd/kn_source_list.md +++ b/docs/cmd/kn_source_list.md @@ -1,13 +1,13 @@ ## kn source list -List available sources +List event sources ### Synopsis -List available sources +List event sources ``` -kn source list [flags] +kn source list ``` ### Examples @@ -47,5 +47,5 @@ kn source list [flags] ### SEE ALSO -* [kn source](kn_source.md) - Event source command group +* [kn source](kn_source.md) - Manage event sources diff --git a/docs/cmd/kn_source_ping.md b/docs/cmd/kn_source_ping.md index 3e4337b490..fc9649782d 100644 --- a/docs/cmd/kn_source_ping.md +++ b/docs/cmd/kn_source_ping.md @@ -1,13 +1,13 @@ ## kn source ping -Ping source command group +Manage ping sources ### Synopsis -Ping source command group +Manage ping sources ``` -kn source ping [flags] +kn source ping COMMAND ``` ### Options @@ -26,10 +26,10 @@ kn source ping [flags] ### SEE ALSO -* [kn source](kn_source.md) - Event source command group -* [kn source ping create](kn_source_ping_create.md) - Create a Ping source. -* [kn source ping delete](kn_source_ping_delete.md) - Delete a Ping source. -* [kn source ping describe](kn_source_ping_describe.md) - Show details of a Ping source -* [kn source ping list](kn_source_ping_list.md) - List Ping sources. -* [kn source ping update](kn_source_ping_update.md) - Update a Ping source. +* [kn source](kn_source.md) - Manage event sources +* [kn source ping create](kn_source_ping_create.md) - Create a ping source +* [kn source ping delete](kn_source_ping_delete.md) - Delete a ping source +* [kn source ping describe](kn_source_ping_describe.md) - Show details of a ping source +* [kn source ping list](kn_source_ping_list.md) - List ping sources +* [kn source ping update](kn_source_ping_update.md) - Update a ping source diff --git a/docs/cmd/kn_source_ping_create.md b/docs/cmd/kn_source_ping_create.md index 39d308e279..8c26e709a2 100644 --- a/docs/cmd/kn_source_ping_create.md +++ b/docs/cmd/kn_source_ping_create.md @@ -1,13 +1,13 @@ ## kn source ping create -Create a Ping source. +Create a ping source ### Synopsis -Create a Ping source. +Create a ping source ``` -kn source ping create NAME --schedule SCHEDULE --sink SINK --data DATA [flags] +kn source ping create NAME ``` ### Examples @@ -39,5 +39,5 @@ kn source ping create NAME --schedule SCHEDULE --sink SINK --data DATA [flags] ### SEE ALSO -* [kn source ping](kn_source_ping.md) - Ping source command group +* [kn source ping](kn_source_ping.md) - Manage ping sources diff --git a/docs/cmd/kn_source_ping_delete.md b/docs/cmd/kn_source_ping_delete.md index 9ba26aa3a8..3f1f593f2c 100644 --- a/docs/cmd/kn_source_ping_delete.md +++ b/docs/cmd/kn_source_ping_delete.md @@ -1,13 +1,13 @@ ## kn source ping delete -Delete a Ping source. +Delete a ping source ### Synopsis -Delete a Ping source. +Delete a ping source ``` -kn source ping delete NAME [flags] +kn source ping delete NAME ``` ### Examples @@ -35,5 +35,5 @@ kn source ping delete NAME [flags] ### SEE ALSO -* [kn source ping](kn_source_ping.md) - Ping source command group +* [kn source ping](kn_source_ping.md) - Manage ping sources diff --git a/docs/cmd/kn_source_ping_describe.md b/docs/cmd/kn_source_ping_describe.md index 29b11ae32b..068576a75d 100644 --- a/docs/cmd/kn_source_ping_describe.md +++ b/docs/cmd/kn_source_ping_describe.md @@ -1,13 +1,13 @@ ## kn source ping describe -Show details of a Ping source +Show details of a ping source ### Synopsis -Show details of a Ping source +Show details of a ping source ``` -kn source ping describe NAME [flags] +kn source ping describe NAME ``` ### Examples @@ -36,5 +36,5 @@ kn source ping describe NAME [flags] ### SEE ALSO -* [kn source ping](kn_source_ping.md) - Ping source command group +* [kn source ping](kn_source_ping.md) - Manage ping sources diff --git a/docs/cmd/kn_source_ping_list.md b/docs/cmd/kn_source_ping_list.md index d7835c7c12..990d875a95 100644 --- a/docs/cmd/kn_source_ping_list.md +++ b/docs/cmd/kn_source_ping_list.md @@ -1,13 +1,13 @@ ## kn source ping list -List Ping sources. +List ping sources ### Synopsis -List Ping sources. +List ping sources ``` -kn source ping list [flags] +kn source ping list ``` ### Examples @@ -43,5 +43,5 @@ kn source ping list [flags] ### SEE ALSO -* [kn source ping](kn_source_ping.md) - Ping source command group +* [kn source ping](kn_source_ping.md) - Manage ping sources diff --git a/docs/cmd/kn_source_ping_update.md b/docs/cmd/kn_source_ping_update.md index ffdef3c543..7b9de02329 100644 --- a/docs/cmd/kn_source_ping_update.md +++ b/docs/cmd/kn_source_ping_update.md @@ -1,13 +1,13 @@ ## kn source ping update -Update a Ping source. +Update a ping source ### Synopsis -Update a Ping source. +Update a ping source ``` -kn source ping update NAME --schedule SCHEDULE --sink SERVICE --data DATA [flags] +kn source ping update NAME ``` ### Examples @@ -39,5 +39,5 @@ kn source ping update NAME --schedule SCHEDULE --sink SERVICE --data DATA [flags ### SEE ALSO -* [kn source ping](kn_source_ping.md) - Ping source command group +* [kn source ping](kn_source_ping.md) - Manage ping sources diff --git a/docs/cmd/kn_trigger.md b/docs/cmd/kn_trigger.md index f80c8fb3f3..4f82747ce4 100644 --- a/docs/cmd/kn_trigger.md +++ b/docs/cmd/kn_trigger.md @@ -1,13 +1,13 @@ ## kn trigger -Trigger command group +Manage event triggers ### Synopsis -Trigger command group +Manage event triggers ``` -kn trigger [flags] +kn trigger ``` ### Options @@ -26,10 +26,10 @@ kn trigger [flags] ### SEE ALSO -* [kn](kn.md) - Knative client +* [kn](kn.md) - kn manages Knative Serving and Eventing resources * [kn trigger create](kn_trigger_create.md) - Create a trigger -* [kn trigger delete](kn_trigger_delete.md) - Delete a trigger. +* [kn trigger delete](kn_trigger_delete.md) - Delete a trigger * [kn trigger describe](kn_trigger_describe.md) - Show details of a trigger -* [kn trigger list](kn_trigger_list.md) - List available triggers. +* [kn trigger list](kn_trigger_list.md) - List triggers * [kn trigger update](kn_trigger_update.md) - Update a trigger diff --git a/docs/cmd/kn_trigger_create.md b/docs/cmd/kn_trigger_create.md index 036079f795..ab1f9b078b 100644 --- a/docs/cmd/kn_trigger_create.md +++ b/docs/cmd/kn_trigger_create.md @@ -7,7 +7,7 @@ Create a trigger Create a trigger ``` -kn trigger create NAME --broker BROKER --sink SINK [flags] +kn trigger create NAME --sink SINK ``` ### Examples @@ -42,5 +42,5 @@ kn trigger create NAME --broker BROKER --sink SINK [flags] ### SEE ALSO -* [kn trigger](kn_trigger.md) - Trigger command group +* [kn trigger](kn_trigger.md) - Manage event triggers diff --git a/docs/cmd/kn_trigger_delete.md b/docs/cmd/kn_trigger_delete.md index b54419ea3a..868e94c40d 100644 --- a/docs/cmd/kn_trigger_delete.md +++ b/docs/cmd/kn_trigger_delete.md @@ -1,13 +1,13 @@ ## kn trigger delete -Delete a trigger. +Delete a trigger ### Synopsis -Delete a trigger. +Delete a trigger ``` -kn trigger delete NAME [flags] +kn trigger delete NAME ``` ### Examples @@ -35,5 +35,5 @@ kn trigger delete NAME [flags] ### SEE ALSO -* [kn trigger](kn_trigger.md) - Trigger command group +* [kn trigger](kn_trigger.md) - Manage event triggers diff --git a/docs/cmd/kn_trigger_describe.md b/docs/cmd/kn_trigger_describe.md index 9fb992c596..6727ef5c3b 100644 --- a/docs/cmd/kn_trigger_describe.md +++ b/docs/cmd/kn_trigger_describe.md @@ -7,7 +7,7 @@ Show details of a trigger Show details of a trigger ``` -kn trigger describe NAME [flags] +kn trigger describe NAME ``` ### Examples @@ -36,5 +36,5 @@ kn trigger describe NAME [flags] ### SEE ALSO -* [kn trigger](kn_trigger.md) - Trigger command group +* [kn trigger](kn_trigger.md) - Manage event triggers diff --git a/docs/cmd/kn_trigger_list.md b/docs/cmd/kn_trigger_list.md index 2c1c124ed9..7bbe298b3e 100644 --- a/docs/cmd/kn_trigger_list.md +++ b/docs/cmd/kn_trigger_list.md @@ -1,13 +1,13 @@ ## kn trigger list -List available triggers. +List triggers ### Synopsis -List available triggers. +List triggers ``` -kn trigger list [name] [flags] +kn trigger list ``` ### Examples @@ -43,5 +43,5 @@ kn trigger list [name] [flags] ### SEE ALSO -* [kn trigger](kn_trigger.md) - Trigger command group +* [kn trigger](kn_trigger.md) - Manage event triggers diff --git a/docs/cmd/kn_trigger_update.md b/docs/cmd/kn_trigger_update.md index c4fe3a1867..c674b0efb7 100644 --- a/docs/cmd/kn_trigger_update.md +++ b/docs/cmd/kn_trigger_update.md @@ -7,7 +7,7 @@ Update a trigger Update a trigger ``` -kn trigger update NAME --filter KEY=VALUE --sink SINK [flags] +kn trigger update NAME ``` ### Examples @@ -46,5 +46,5 @@ kn trigger update NAME --filter KEY=VALUE --sink SINK [flags] ### SEE ALSO -* [kn trigger](kn_trigger.md) - Trigger command group +* [kn trigger](kn_trigger.md) - Manage event triggers diff --git a/docs/cmd/kn_version.md b/docs/cmd/kn_version.md index 2ad1433643..cb9503c968 100644 --- a/docs/cmd/kn_version.md +++ b/docs/cmd/kn_version.md @@ -1,13 +1,13 @@ ## kn version -Prints the client version +Show the version of this client ### Synopsis -Prints the client version +Show the version of this client ``` -kn version [flags] +kn version ``` ### Options @@ -27,5 +27,5 @@ kn version [flags] ### SEE ALSO -* [kn](kn.md) - Knative client +* [kn](kn.md) - kn manages Knative Serving and Eventing resources diff --git a/pkg/kn/commands/completion/completion.go b/pkg/kn/commands/completion/completion.go index c2d55f1ac6..2979bf8970 100644 --- a/pkg/kn/commands/completion/completion.go +++ b/pkg/kn/commands/completion/completion.go @@ -15,9 +15,10 @@ package completion import ( - "fmt" "os" + "github.com/pkg/errors" + "knative.dev/client/pkg/kn/commands" "github.com/spf13/cobra" @@ -43,23 +44,23 @@ Supported Shells: // NewCompletionCommand implements shell auto-completion feature for Bash and Zsh func NewCompletionCommand(p *commands.KnParams) *cobra.Command { return &cobra.Command{ - Use: "completion [SHELL]", + Use: "completion SHELL", Short: "Output shell completion code", Long: desc, ValidArgs: []string{"bash", "zsh"}, Example: eg, - Run: func(cmd *cobra.Command, args []string) { + RunE: func(cmd *cobra.Command, args []string) error { if len(args) == 1 { switch args[0] { case "bash": - cmd.Root().GenBashCompletion(os.Stdout) + return cmd.Root().GenBashCompletion(os.Stdout) case "zsh": - cmd.Root().GenZshCompletion(os.Stdout) + return cmd.Root().GenZshCompletion(os.Stdout) default: - fmt.Println("only supports 'bash' or 'zsh' shell completion") + return errors.New("'bash' or 'zsh' shell completion is supported") } } else { - fmt.Println("accepts one argument either 'bash' or 'zsh'") + return errors.New("Only one argument is can be provided, either 'bash' or 'zsh'") } }, } diff --git a/pkg/kn/commands/completion/completion_test.go b/pkg/kn/commands/completion/completion_test.go index 1bc821e36c..258d979b3c 100644 --- a/pkg/kn/commands/completion/completion_test.go +++ b/pkg/kn/commands/completion/completion_test.go @@ -28,14 +28,16 @@ func TestCompletionUsage(t *testing.T) { completionCmd := NewCompletionCommand(&commands.KnParams{}) assert.Assert(t, util.ContainsAllIgnoreCase(completionCmd.Use, "completion")) assert.Assert(t, util.ContainsAllIgnoreCase(completionCmd.Short, "completion", "shell")) - assert.Assert(t, completionCmd.RunE == nil) + assert.Assert(t, completionCmd.Run == nil) + assert.Assert(t, completionCmd.RunE != nil) } func TestCompletionGeneration(t *testing.T) { for _, shell := range []string{"bash", "zsh"} { completionCmd := NewCompletionCommand(&commands.KnParams{}) c := commands.CaptureStdout(t) - completionCmd.Run(&cobra.Command{}, []string{shell}) + err := completionCmd.RunE(&cobra.Command{}, []string{shell}) + assert.NilError(t, err) out := c.Close() assert.Assert(t, out != "") } @@ -43,16 +45,12 @@ func TestCompletionGeneration(t *testing.T) { func TestCompletionNoArg(t *testing.T) { completionCmd := NewCompletionCommand(&commands.KnParams{}) - c := commands.CaptureStdout(t) - completionCmd.Run(&cobra.Command{}, []string{}) - out := c.Close() - assert.Assert(t, util.ContainsAll(out, "bash", "zsh", "one", "argument")) + err := completionCmd.RunE(&cobra.Command{}, []string{}) + assert.Assert(t, util.ContainsAll(err.Error(), "bash", "zsh", "one", "argument")) } func TestCompletionWrongArg(t *testing.T) { completionCmd := NewCompletionCommand(&commands.KnParams{}) - c := commands.CaptureStdout(t) - completionCmd.Run(&cobra.Command{}, []string{"sh"}) - out := c.Close() - assert.Assert(t, util.ContainsAll(out, "bash", "zsh", "only", "supports")) + err := completionCmd.RunE(&cobra.Command{}, []string{"sh"}) + assert.Assert(t, util.ContainsAll(err.Error(), "bash", "zsh", "support")) } diff --git a/pkg/kn/commands/options/options.go b/pkg/kn/commands/options/options.go new file mode 100644 index 0000000000..c62ce7a360 --- /dev/null +++ b/pkg/kn/commands/options/options.go @@ -0,0 +1,50 @@ +// Copyright © 2020 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package options + +import ( + "github.com/pkg/errors" + "github.com/spf13/cobra" + + "knative.dev/client/pkg/templates" +) + +// NewCmdOptions implements the options command +func NewOptionsCommand() *cobra.Command { + cmd := &cobra.Command{ + Use: "options", + Short: "Print the list of flags inherited by all commands", + Long: "Print the list of flags inherited by all commands", + Example: `# Print flags inherited by all commands +kn options`, + Run: func(cmd *cobra.Command, args []string) { + cmd.SetOut(cmd.OutOrStdout()) + cmd.Usage() + }, + // Be quiet + SilenceErrors: true, + SilenceUsage: true, + // Allow all options + FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true}, + } + cmd.SetFlagErrorFunc(func(c *cobra.Command, err error) error { + return errors.Errorf("%s for '%s'", err.Error(), c.CommandPath()) + }) + cmd.SetUsageFunc(templates.NewGlobalOptionsFunc()) + cmd.SetHelpFunc(func(command *cobra.Command, args []string) { + templates.NewGlobalOptionsFunc()(command) + }) + return cmd +} diff --git a/pkg/kn/commands/plugin/list.go b/pkg/kn/commands/plugin/list.go index df99444ac2..153a8f5a08 100644 --- a/pkg/kn/commands/plugin/list.go +++ b/pkg/kn/commands/plugin/list.go @@ -48,7 +48,7 @@ Available plugins are those that are: - executable - begin with "kn-" - Kn's plugin directory -- Anywhere in the execution $PATH (if plugins.path-lookup config variable is enabled)`, +- Anywhere in the execution $PATH (if plugins.path-lookup configuration variable is enabled)`, RunE: func(cmd *cobra.Command, args []string) error { return listPlugins(cmd, plFlags) }, diff --git a/pkg/kn/commands/plugin/plugin.go b/pkg/kn/commands/plugin/plugin.go index b608484f73..473516b064 100644 --- a/pkg/kn/commands/plugin/plugin.go +++ b/pkg/kn/commands/plugin/plugin.go @@ -23,11 +23,11 @@ import ( func NewPluginCommand(p *commands.KnParams) *cobra.Command { pluginCmd := &cobra.Command{ Use: "plugin", - Short: "Plugin command group", - Long: `Provides utilities for interacting and managing with kn plugins. + Short: "Manage kn plugins", + Long: `Manage kn plugins. Plugins provide extended functionality that is not part of the core kn command-line distribution. -Please refer to the documentation and examples for more information about how write your own plugins.`, +Please refer to the documentation and examples for more information about how to write your own plugins.`, } pluginCmd.AddCommand(NewPluginListCommand(p)) diff --git a/pkg/kn/commands/revision/delete.go b/pkg/kn/commands/revision/delete.go index e3c3ad7b1e..536704506b 100644 --- a/pkg/kn/commands/revision/delete.go +++ b/pkg/kn/commands/revision/delete.go @@ -30,7 +30,7 @@ func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command { RevisionDeleteCommand := &cobra.Command{ Use: "delete NAME", - Short: "Delete a revision.", + Short: "Delete a revision", Example: ` # Delete a revision 'svc1-abcde' in default namespace kn revision delete svc1-abcde`, diff --git a/pkg/kn/commands/revision/list.go b/pkg/kn/commands/revision/list.go index 360efe8203..5fd57e6f30 100644 --- a/pkg/kn/commands/revision/list.go +++ b/pkg/kn/commands/revision/list.go @@ -38,8 +38,8 @@ func NewRevisionListCommand(p *commands.KnParams) *cobra.Command { revisionListFlags := flags.NewListPrintFlags(RevisionListHandlers) revisionListCommand := &cobra.Command{ - Use: "list [name]", - Short: "List available revisions.", + Use: "list", + Short: "List revisions", Long: "List revisions for a given service.", Example: ` # List all revisions diff --git a/pkg/kn/commands/revision/revision.go b/pkg/kn/commands/revision/revision.go index ad7fa8d95e..c7c2fc32ff 100644 --- a/pkg/kn/commands/revision/revision.go +++ b/pkg/kn/commands/revision/revision.go @@ -24,7 +24,7 @@ import ( func NewRevisionCommand(p *commands.KnParams) *cobra.Command { revisionCmd := &cobra.Command{ Use: "revision", - Short: "Revision command group", + Short: "Manage service revisions", } revisionCmd.AddCommand(NewRevisionListCommand(p)) revisionCmd.AddCommand(NewRevisionDescribeCommand(p)) diff --git a/pkg/kn/commands/route/list.go b/pkg/kn/commands/route/list.go index 981677689f..9db68b5f88 100644 --- a/pkg/kn/commands/route/list.go +++ b/pkg/kn/commands/route/list.go @@ -32,7 +32,7 @@ func NewRouteListCommand(p *commands.KnParams) *cobra.Command { routeListFlags := flags.NewListPrintFlags(RouteListHandlers) routeListCommand := &cobra.Command{ Use: "list NAME", - Short: "List available routes.", + Short: "List routes", Example: ` # List all routes kn route list diff --git a/pkg/kn/commands/route/route.go b/pkg/kn/commands/route/route.go index cc1a3f56f2..7f9c907037 100644 --- a/pkg/kn/commands/route/route.go +++ b/pkg/kn/commands/route/route.go @@ -23,7 +23,7 @@ import ( func NewRouteCommand(p *commands.KnParams) *cobra.Command { routeCmd := &cobra.Command{ Use: "route", - Short: "Route command group", + Short: "List and show service routes", } routeCmd.AddCommand(NewRouteListCommand(p)) routeCmd.AddCommand(NewRouteDescribeCommand(p)) diff --git a/pkg/kn/commands/service/create.go b/pkg/kn/commands/service/create.go index ac7795e7e9..249f3f65bd 100644 --- a/pkg/kn/commands/service/create.go +++ b/pkg/kn/commands/service/create.go @@ -72,7 +72,7 @@ func NewServiceCreateCommand(p *commands.KnParams) *cobra.Command { serviceCreateCommand := &cobra.Command{ Use: "create NAME --image IMAGE", - Short: "Create a service.", + Short: "Create a service", Example: create_example, RunE: func(cmd *cobra.Command, args []string) (err error) { if len(args) != 1 { diff --git a/pkg/kn/commands/service/delete.go b/pkg/kn/commands/service/delete.go index 49c3504f77..22ddf81b93 100644 --- a/pkg/kn/commands/service/delete.go +++ b/pkg/kn/commands/service/delete.go @@ -31,7 +31,7 @@ func NewServiceDeleteCommand(p *commands.KnParams) *cobra.Command { serviceDeleteCommand := &cobra.Command{ Use: "delete NAME", - Short: "Delete a service.", + Short: "Delete a service", Example: ` # Delete a service 'svc1' in default namespace kn service delete svc1 diff --git a/pkg/kn/commands/service/export.go b/pkg/kn/commands/service/export.go index ae47ae3a7d..cd5ec8adb5 100644 --- a/pkg/kn/commands/service/export.go +++ b/pkg/kn/commands/service/export.go @@ -50,7 +50,7 @@ func NewServiceExportCommand(p *commands.KnParams) *cobra.Command { command := &cobra.Command{ Use: "export NAME", - Short: "Export a service.", + Short: "Export a service and its revisions", Example: ` # Export a service in YAML format kn service export foo -n bar -o yaml diff --git a/pkg/kn/commands/service/list.go b/pkg/kn/commands/service/list.go index 10a3308cc2..9b0030ae93 100644 --- a/pkg/kn/commands/service/list.go +++ b/pkg/kn/commands/service/list.go @@ -31,8 +31,8 @@ func NewServiceListCommand(p *commands.KnParams) *cobra.Command { serviceListFlags := flags.NewListPrintFlags(ServiceListHandlers) serviceListCommand := &cobra.Command{ - Use: "list [name]", - Short: "List available services.", + Use: "list", + Short: "List available services", Example: ` # List all services kn service list diff --git a/pkg/kn/commands/service/service.go b/pkg/kn/commands/service/service.go index b6f357e646..1652f65a2b 100644 --- a/pkg/kn/commands/service/service.go +++ b/pkg/kn/commands/service/service.go @@ -34,7 +34,7 @@ const ( func NewServiceCommand(p *commands.KnParams) *cobra.Command { serviceCmd := &cobra.Command{ Use: "service", - Short: "Service command group", + Short: "Manage Knative services", } serviceCmd.AddCommand(NewServiceListCommand(p)) serviceCmd.AddCommand(NewServiceDescribeCommand(p)) diff --git a/pkg/kn/commands/service/update.go b/pkg/kn/commands/service/update.go index c8b64410f8..9c53cbc366 100644 --- a/pkg/kn/commands/service/update.go +++ b/pkg/kn/commands/service/update.go @@ -55,8 +55,8 @@ func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command { var waitFlags commands.WaitFlags var trafficFlags flags.Traffic serviceUpdateCommand := &cobra.Command{ - Use: "update NAME [flags]", - Short: "Update a service.", + Use: "update NAME", + Short: "Update a service", Example: updateExample, RunE: func(cmd *cobra.Command, args []string) (err error) { if len(args) != 1 { diff --git a/pkg/kn/commands/source/apiserver/apiserver.go b/pkg/kn/commands/source/apiserver/apiserver.go index 7cbdabe445..8143c0cb25 100644 --- a/pkg/kn/commands/source/apiserver/apiserver.go +++ b/pkg/kn/commands/source/apiserver/apiserver.go @@ -26,8 +26,8 @@ import ( // NewAPIServerCommand for managing ApiServer source func NewAPIServerCommand(p *commands.KnParams) *cobra.Command { apiServerSourceCmd := &cobra.Command{ - Use: "apiserver", - Short: "Kubernetes API Server Event Source command group", + Use: "apiserver COMMAND", + Short: "Manage Kubernetes api-server sources", } apiServerSourceCmd.AddCommand(NewAPIServerCreateCommand(p)) apiServerSourceCmd.AddCommand(NewAPIServerUpdateCommand(p)) diff --git a/pkg/kn/commands/source/apiserver/create.go b/pkg/kn/commands/source/apiserver/create.go index 928ef00bf6..86a7dd458b 100644 --- a/pkg/kn/commands/source/apiserver/create.go +++ b/pkg/kn/commands/source/apiserver/create.go @@ -32,8 +32,8 @@ func NewAPIServerCreateCommand(p *commands.KnParams) *cobra.Command { var sinkFlags flags.SinkFlags cmd := &cobra.Command{ - Use: "create NAME --resource RESOURCE --service-account ACCOUNTNAME --sink SINK --mode MODE", - Short: "Create an ApiServer source.", + Use: "create NAME --resource RESOURCE --sink SINK", + Short: "Create an api-server source", Example: ` # Create an ApiServerSource 'k8sevents' which consumes Kubernetes events and sends message to service 'mysvc' as a cloudevent kn source apiserver create k8sevents --resource Event:v1 --service-account myaccountname --sink svc:mysvc`, diff --git a/pkg/kn/commands/source/apiserver/delete.go b/pkg/kn/commands/source/apiserver/delete.go index 91c42f61f5..82c52324fb 100644 --- a/pkg/kn/commands/source/apiserver/delete.go +++ b/pkg/kn/commands/source/apiserver/delete.go @@ -27,7 +27,7 @@ import ( func NewAPIServerDeleteCommand(p *commands.KnParams) *cobra.Command { deleteCommand := &cobra.Command{ Use: "delete NAME", - Short: "Delete an ApiServer source.", + Short: "Delete api-server sources", Example: ` # Delete an ApiServerSource 'k8sevents' in default namespace kn source apiserver delete k8sevents`, diff --git a/pkg/kn/commands/source/apiserver/describe.go b/pkg/kn/commands/source/apiserver/describe.go index a691da4a92..c30ac769cc 100644 --- a/pkg/kn/commands/source/apiserver/describe.go +++ b/pkg/kn/commands/source/apiserver/describe.go @@ -32,7 +32,7 @@ func NewAPIServerDescribeCommand(p *commands.KnParams) *cobra.Command { apiServerDescribe := &cobra.Command{ Use: "describe NAME", - Short: "Show details of an ApiServer source", + Short: "Show details of an api-server source", Example: ` # Describe an ApiServer source with name 'k8sevents' kn source apiserver describe k8sevents`, diff --git a/pkg/kn/commands/source/apiserver/list.go b/pkg/kn/commands/source/apiserver/list.go index 3337fc44a9..5d8e64deb1 100644 --- a/pkg/kn/commands/source/apiserver/list.go +++ b/pkg/kn/commands/source/apiserver/list.go @@ -29,7 +29,7 @@ func NewAPIServerListCommand(p *commands.KnParams) *cobra.Command { listCommand := &cobra.Command{ Use: "list", - Short: "List ApiServer sources.", + Short: "List api-server sources", Example: ` # List all ApiServer sources kn source apiserver list diff --git a/pkg/kn/commands/source/apiserver/update.go b/pkg/kn/commands/source/apiserver/update.go index 785b5819a4..c613f71da7 100644 --- a/pkg/kn/commands/source/apiserver/update.go +++ b/pkg/kn/commands/source/apiserver/update.go @@ -32,8 +32,8 @@ func NewAPIServerUpdateCommand(p *commands.KnParams) *cobra.Command { var sinkFlags flags.SinkFlags cmd := &cobra.Command{ - Use: "update NAME --resource RESOURCE --service-account ACCOUNTNAME --sink SINK --mode MODE", - Short: "Update an ApiServer source.", + Use: "update NAME", + Short: "Update an api-server source", Example: ` # Update an ApiServerSource 'k8sevents' with different service account and sink service kn source apiserver update k8sevents --service-account newsa --sink svc:newsvc`, diff --git a/pkg/kn/commands/source/binding/binding.go b/pkg/kn/commands/source/binding/binding.go index 3a6e2e626d..bab932fa4a 100644 --- a/pkg/kn/commands/source/binding/binding.go +++ b/pkg/kn/commands/source/binding/binding.go @@ -32,8 +32,8 @@ import ( // NewBindingCommand is the root command for all binding related commands func NewBindingCommand(p *commands.KnParams) *cobra.Command { bindingCmd := &cobra.Command{ - Use: "binding", - Short: "Sink binding command group", + Use: "binding COMMAND", + Short: "Manage sink bindings", } bindingCmd.AddCommand(NewBindingCreateCommand(p)) bindingCmd.AddCommand(NewBindingUpdateCommand(p)) diff --git a/pkg/kn/commands/source/binding/create.go b/pkg/kn/commands/source/binding/create.go index ea2c96bf63..a5ec6c208a 100644 --- a/pkg/kn/commands/source/binding/create.go +++ b/pkg/kn/commands/source/binding/create.go @@ -32,8 +32,8 @@ func NewBindingCreateCommand(p *commands.KnParams) *cobra.Command { var sinkFlags flags.SinkFlags cmd := &cobra.Command{ - Use: "create NAME --subject SUBJECT --sink SINK --ce-override KEY=VALUE", - Short: "Create a sink binding.", + Use: "create NAME --subject SUBJECT --sink SINK", + Short: "Create a sink binding", Example: ` # Create a sink binding which connects a deployment 'myapp' with a Knative service 'mysvc' kn source binding create my-binding --subject Deployment:apps/v1:myapp --sink svc:mysvc`, diff --git a/pkg/kn/commands/source/binding/delete.go b/pkg/kn/commands/source/binding/delete.go index e4ee97ffd0..84c9fc075d 100644 --- a/pkg/kn/commands/source/binding/delete.go +++ b/pkg/kn/commands/source/binding/delete.go @@ -26,7 +26,7 @@ import ( func NewBindingDeleteCommand(p *commands.KnParams) *cobra.Command { cmd := &cobra.Command{ Use: "delete NAME", - Short: "Delete a sink binding.", + Short: "Delete a sink binding", Example: ` # Delete a sink binding with name 'my-binding' kn source binding delete my-binding`, diff --git a/pkg/kn/commands/source/binding/list.go b/pkg/kn/commands/source/binding/list.go index 07f9110f14..c326ccd8a0 100644 --- a/pkg/kn/commands/source/binding/list.go +++ b/pkg/kn/commands/source/binding/list.go @@ -28,7 +28,7 @@ func NewBindingListCommand(p *commands.KnParams) *cobra.Command { cmd := &cobra.Command{ Use: "list", - Short: "List sink bindings.", + Short: "List sink bindings", Example: ` # List all sink binidngs kn source binding list diff --git a/pkg/kn/commands/source/binding/update.go b/pkg/kn/commands/source/binding/update.go index e7e6e7ea3f..c438b97078 100644 --- a/pkg/kn/commands/source/binding/update.go +++ b/pkg/kn/commands/source/binding/update.go @@ -32,8 +32,8 @@ func NewBindingUpdateCommand(p *commands.KnParams) *cobra.Command { var sinkFlags flags.SinkFlags cmd := &cobra.Command{ - Use: "update NAME --subject SCHEDULE --sink SINK --ce-override OVERRIDE", - Short: "Update a sink binding.", + Use: "update NAME", + Short: "Update a sink binding", Example: ` # Update the subject of a sink binding 'my-binding' to a new cronjob with label selector 'app=ping' kn source binding update my-binding --subject cronjob:batch/v1beta1:app=ping"`, diff --git a/pkg/kn/commands/source/list.go b/pkg/kn/commands/source/list.go index 943143d451..a45c0afd9f 100644 --- a/pkg/kn/commands/source/list.go +++ b/pkg/kn/commands/source/list.go @@ -41,7 +41,7 @@ func NewListCommand(p *commands.KnParams) *cobra.Command { listFlags := flags.NewListPrintFlags(ListHandlers) listCommand := &cobra.Command{ Use: "list", - Short: "List available sources", + Short: "List event sources", Example: listExample, RunE: func(cmd *cobra.Command, args []string) error { namespace, err := p.GetNamespace(cmd) diff --git a/pkg/kn/commands/source/list_types.go b/pkg/kn/commands/source/list_types.go index c10074f0b7..67f44131be 100644 --- a/pkg/kn/commands/source/list_types.go +++ b/pkg/kn/commands/source/list_types.go @@ -28,12 +28,12 @@ func NewListTypesCommand(p *commands.KnParams) *cobra.Command { listTypesFlags := flags.NewListPrintFlags(ListTypesHandlers) listTypesCommand := &cobra.Command{ Use: "list-types", - Short: "List available source types", + Short: "List event source types", Example: ` - # List available eventing source types + # List available event source types kn source list-types - # List available eventing source types in YAML format + # List available event source types in YAML format kn source list-types -o yaml`, RunE: func(cmd *cobra.Command, args []string) error { namespace, err := p.GetNamespace(cmd) diff --git a/pkg/kn/commands/source/ping/create.go b/pkg/kn/commands/source/ping/create.go index 997c146331..b667d0d8a6 100644 --- a/pkg/kn/commands/source/ping/create.go +++ b/pkg/kn/commands/source/ping/create.go @@ -32,8 +32,8 @@ func NewPingCreateCommand(p *commands.KnParams) *cobra.Command { var sinkFlags flags.SinkFlags cmd := &cobra.Command{ - Use: "create NAME --schedule SCHEDULE --sink SINK --data DATA", - Short: "Create a Ping source.", + Use: "create NAME", + Short: "Create a ping source", Example: ` # Create a Ping source 'my-ping' which fires every two minutes and sends '{ value: "hello" }' to service 'mysvc' as a cloudevent kn source ping create my-ping --schedule "*/2 * * * *" --data '{ value: "hello" }' --sink svc:mysvc`, diff --git a/pkg/kn/commands/source/ping/delete.go b/pkg/kn/commands/source/ping/delete.go index 6a00df0cef..3dcecaf2ce 100644 --- a/pkg/kn/commands/source/ping/delete.go +++ b/pkg/kn/commands/source/ping/delete.go @@ -26,7 +26,7 @@ import ( func NewPingDeleteCommand(p *commands.KnParams) *cobra.Command { pingDeleteCommand := &cobra.Command{ Use: "delete NAME", - Short: "Delete a Ping source.", + Short: "Delete a ping source", Example: ` # Delete a Ping source 'my-ping' kn source ping delete my-ping`, diff --git a/pkg/kn/commands/source/ping/describe.go b/pkg/kn/commands/source/ping/describe.go index 88b9b5cd50..599de1f4a8 100644 --- a/pkg/kn/commands/source/ping/describe.go +++ b/pkg/kn/commands/source/ping/describe.go @@ -32,7 +32,7 @@ func NewPingDescribeCommand(p *commands.KnParams) *cobra.Command { pingDescribe := &cobra.Command{ Use: "describe NAME", - Short: "Show details of a Ping source", + Short: "Show details of a ping source", Example: ` # Describe a Ping source with name 'myping' kn source ping describe myping`, diff --git a/pkg/kn/commands/source/ping/list.go b/pkg/kn/commands/source/ping/list.go index 2fd285dfba..51667d5f58 100644 --- a/pkg/kn/commands/source/ping/list.go +++ b/pkg/kn/commands/source/ping/list.go @@ -29,7 +29,7 @@ func NewPingListCommand(p *commands.KnParams) *cobra.Command { listCommand := &cobra.Command{ Use: "list", - Short: "List Ping sources.", + Short: "List ping sources", Example: ` # List all Ping sources kn source ping list diff --git a/pkg/kn/commands/source/ping/ping.go b/pkg/kn/commands/source/ping/ping.go index 7ff3871a9f..78e307f710 100644 --- a/pkg/kn/commands/source/ping/ping.go +++ b/pkg/kn/commands/source/ping/ping.go @@ -26,8 +26,8 @@ import ( // NewPingCommand is the root command for all Ping source related commands func NewPingCommand(p *commands.KnParams) *cobra.Command { pingImporterCmd := &cobra.Command{ - Use: "ping", - Short: "Ping source command group", + Use: "ping COMMAND", + Short: "Manage ping sources", } pingImporterCmd.AddCommand(NewPingCreateCommand(p)) pingImporterCmd.AddCommand(NewPingDeleteCommand(p)) diff --git a/pkg/kn/commands/source/ping/update.go b/pkg/kn/commands/source/ping/update.go index 9c254ec44b..3ddd0a8069 100644 --- a/pkg/kn/commands/source/ping/update.go +++ b/pkg/kn/commands/source/ping/update.go @@ -32,8 +32,8 @@ func NewPingUpdateCommand(p *commands.KnParams) *cobra.Command { var sinkFlags flags.SinkFlags cmd := &cobra.Command{ - Use: "update NAME --schedule SCHEDULE --sink SERVICE --data DATA", - Short: "Update a Ping source.", + Use: "update NAME", + Short: "Update a ping source", Example: ` # Update the schedule of a Ping source 'my-ping' to fire every minute kn source ping update my-ping --schedule "* * * * *"`, diff --git a/pkg/kn/commands/source/source.go b/pkg/kn/commands/source/source.go index 0e08a56ec8..b3e30c0fc9 100644 --- a/pkg/kn/commands/source/source.go +++ b/pkg/kn/commands/source/source.go @@ -25,8 +25,8 @@ import ( func NewSourceCommand(p *commands.KnParams) *cobra.Command { sourceCmd := &cobra.Command{ - Use: "source", - Short: "Event source command group", + Use: "source SOURCE|COMMAND", + Short: "Manage event sources", } sourceCmd.AddCommand(NewListTypesCommand(p)) sourceCmd.AddCommand(NewListCommand(p)) diff --git a/pkg/kn/commands/trigger/create.go b/pkg/kn/commands/trigger/create.go index d62c603098..a31c564c20 100644 --- a/pkg/kn/commands/trigger/create.go +++ b/pkg/kn/commands/trigger/create.go @@ -33,7 +33,7 @@ func NewTriggerCreateCommand(p *commands.KnParams) *cobra.Command { var sinkFlags flags.SinkFlags cmd := &cobra.Command{ - Use: "create NAME --broker BROKER --sink SINK", + Use: "create NAME --sink SINK", Short: "Create a trigger", Example: ` # Create a trigger 'mytrigger' to declare a subscription to events from default broker. The subscriber is service 'mysvc' diff --git a/pkg/kn/commands/trigger/delete.go b/pkg/kn/commands/trigger/delete.go index 1d4656892e..b0b10bdf50 100644 --- a/pkg/kn/commands/trigger/delete.go +++ b/pkg/kn/commands/trigger/delete.go @@ -26,7 +26,7 @@ import ( func NewTriggerDeleteCommand(p *commands.KnParams) *cobra.Command { TriggerDeleteCommand := &cobra.Command{ Use: "delete NAME", - Short: "Delete a trigger.", + Short: "Delete a trigger", Example: ` # Delete a trigger 'mytrigger' in default namespace kn trigger delete mytrigger`, diff --git a/pkg/kn/commands/trigger/list.go b/pkg/kn/commands/trigger/list.go index c4cadbbc12..a237ffd823 100644 --- a/pkg/kn/commands/trigger/list.go +++ b/pkg/kn/commands/trigger/list.go @@ -28,8 +28,8 @@ func NewTriggerListCommand(p *commands.KnParams) *cobra.Command { triggerListFlags := flags.NewListPrintFlags(TriggerListHandlers) triggerListCommand := &cobra.Command{ - Use: "list [name]", - Short: "List available triggers.", + Use: "list", + Short: "List triggers", Example: ` # List all triggers kn trigger list diff --git a/pkg/kn/commands/trigger/trigger.go b/pkg/kn/commands/trigger/trigger.go index 7338077d06..683f7de983 100644 --- a/pkg/kn/commands/trigger/trigger.go +++ b/pkg/kn/commands/trigger/trigger.go @@ -29,7 +29,7 @@ const ( func NewTriggerCommand(p *commands.KnParams) *cobra.Command { triggerCmd := &cobra.Command{ Use: "trigger", - Short: "Trigger command group", + Short: "Manage event triggers", } triggerCmd.AddCommand(NewTriggerCreateCommand(p)) triggerCmd.AddCommand(NewTriggerUpdateCommand(p)) diff --git a/pkg/kn/commands/trigger/update.go b/pkg/kn/commands/trigger/update.go index 20f0ccc5d6..06a81393c6 100644 --- a/pkg/kn/commands/trigger/update.go +++ b/pkg/kn/commands/trigger/update.go @@ -36,7 +36,7 @@ func NewTriggerUpdateCommand(p *commands.KnParams) *cobra.Command { var sinkFlags flags.SinkFlags cmd := &cobra.Command{ - Use: "update NAME --filter KEY=VALUE --sink SINK", + Use: "update NAME", Short: "Update a trigger", Example: ` # Update the filter which key is 'type' to value 'knative.dev.bar' in a trigger 'mytrigger' diff --git a/pkg/kn/commands/version/version.go b/pkg/kn/commands/version/version.go index 81d87ef0c4..7691a2a133 100644 --- a/pkg/kn/commands/version/version.go +++ b/pkg/kn/commands/version/version.go @@ -50,7 +50,7 @@ type knVersion struct { func NewVersionCommand(p *commands.KnParams) *cobra.Command { versionCmd := &cobra.Command{ Use: "version", - Short: "Prints the client version", + Short: "Show the version of this client", RunE: func(cmd *cobra.Command, args []string) error { if cmd.Flags().Changed("output") { return printVersionMachineReadable(cmd) diff --git a/pkg/kn/commands/version/version_test.go b/pkg/kn/commands/version/version_test.go index c514d717f7..8d380af81d 100644 --- a/pkg/kn/commands/version/version_test.go +++ b/pkg/kn/commands/version/version_test.go @@ -25,6 +25,7 @@ import ( "sigs.k8s.io/yaml" "knative.dev/client/pkg/kn/commands" + "knative.dev/client/pkg/util" ) var versionOutputTemplate = `Version: {{.Version}} @@ -73,7 +74,7 @@ func TestVersion(t *testing.T) { t.Run("creates a VersionCommand", func(t *testing.T) { setup() assert.Equal(t, versionCmd.Use, "version") - assert.Equal(t, versionCmd.Short, "Prints the client version") + assert.Assert(t, util.ContainsAll(versionCmd.Short, "version")) assert.Assert(t, versionCmd.RunE != nil) }) diff --git a/pkg/kn/root/root.go b/pkg/kn/root/root.go index b434ffb418..2589b2a225 100644 --- a/pkg/kn/root/root.go +++ b/pkg/kn/root/root.go @@ -17,17 +17,16 @@ package root import ( "flag" "fmt" - "os" "strings" "github.com/pkg/errors" "github.com/spf13/cobra" - "golang.org/x/crypto/ssh/terminal" _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" "knative.dev/client/pkg/kn/commands" "knative.dev/client/pkg/kn/commands/completion" + "knative.dev/client/pkg/kn/commands/options" "knative.dev/client/pkg/kn/commands/plugin" "knative.dev/client/pkg/kn/commands/revision" "knative.dev/client/pkg/kn/commands/route" @@ -37,6 +36,7 @@ import ( "knative.dev/client/pkg/kn/commands/version" "knative.dev/client/pkg/kn/config" "knative.dev/client/pkg/kn/flags" + "knative.dev/client/pkg/templates" ) // NewRootCommand creates the default `kn` command with a default plugin handler @@ -46,21 +46,14 @@ func NewRootCommand() (*cobra.Command, error) { rootCmd := &cobra.Command{ Use: "kn", - Short: "Knative client", - Long: `Manage your Knative building blocks: + Short: "kn manages Knative Serving and Eventing resources", + Long: `kn is the command line interface for managing Knative Serving and Eventing resources -* Serving: Manage your services and release new software to them. -* Eventing: Manage event subscriptions and channels. Connect up event sources.`, + Find more information about Knative at: https://knative.dev`, // Disable docs header DisableAutoGenTag: true, - // Affects children as well - SilenceUsage: true, - - // Prevents Cobra from dealing with errors as we deal with them in main.go - SilenceErrors: true, - // Validate our boolean configs PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return flags.ReconcileBoolFlags(cmd.Flags()) @@ -77,18 +70,40 @@ func NewRootCommand() (*cobra.Command, error) { rootCmd.PersistentFlags().StringVar(&p.KubeCfgPath, "kubeconfig", "", "kubectl configuration file (default: ~/.kube/config)") flags.AddBothBoolFlags(rootCmd.PersistentFlags(), &p.LogHTTP, "log-http", "", false, "log http traffic") - // root child commands - rootCmd.AddCommand(service.NewServiceCommand(p)) - rootCmd.AddCommand(revision.NewRevisionCommand(p)) - rootCmd.AddCommand(plugin.NewPluginCommand(p)) - rootCmd.AddCommand(route.NewRouteCommand(p)) - rootCmd.AddCommand(completion.NewCompletionCommand(p)) - rootCmd.AddCommand(version.NewVersionCommand(p)) - rootCmd.AddCommand(source.NewSourceCommand(p)) - rootCmd.AddCommand(trigger.NewTriggerCommand(p)) + // Grouped commands + groups := templates.CommandGroups{ + { + Header: "Serving Commands:", + Commands: []*cobra.Command{ + service.NewServiceCommand(p), + revision.NewRevisionCommand(p), + route.NewRouteCommand(p), + }, + }, + { + Header: "Eventing Commands:", + Commands: []*cobra.Command{ + source.NewSourceCommand(p), + trigger.NewTriggerCommand(p), + }, + }, + { + Header: "Other Commands:", + Commands: []*cobra.Command{ + plugin.NewPluginCommand(p), + completion.NewCompletionCommand(p), + version.NewVersionCommand(p), + }, + }, + } + // Add all commands to the root command, flat + groups.AddTo(rootCmd) // Initialize default `help` cmd early to prevent unknown command errors - rootCmd.InitDefaultHelpCmd() + groups.SetRootUsage(rootCmd) + + // Add the "options" commands for showing all global options + rootCmd.AddCommand(options.NewOptionsCommand()) // Check that command groups can't execute and that leaf commands don't h err := validateCommandStructure(rootCmd) @@ -96,9 +111,6 @@ func NewRootCommand() (*cobra.Command, error) { return nil, err } - // Wrap usage. - fitUsageMessageToTerminalWidth(rootCmd) - // For glog parse error. TOO: Check why this is needed flag.CommandLine.Parse([]string{}) return rootCmd, nil @@ -132,15 +144,6 @@ func validateCommandStructure(cmd *cobra.Command) error { return nil } -func fitUsageMessageToTerminalWidth(rootCmd *cobra.Command) { - width, _, err := terminal.GetSize(int(os.Stdout.Fd())) - if err == nil { - newUsage := strings.ReplaceAll(rootCmd.UsageTemplate(), "FlagUsages ", - fmt.Sprintf("FlagUsagesWrapped %d ", width)) - rootCmd.SetUsageTemplate(newUsage) - } -} - // ExtractSubCommandNames extracts the names of all sub commands of a given command func ExtractSubCommandNames(cmds []*cobra.Command) []string { var ret []string diff --git a/pkg/kn/root/root_test.go b/pkg/kn/root/root_test.go index ed99dc5120..c2c6a1e0b6 100644 --- a/pkg/kn/root/root_test.go +++ b/pkg/kn/root/root_test.go @@ -30,7 +30,7 @@ func TestNewRootCommand(t *testing.T) { assert.Assert(t, rootCmd != nil) assert.Equal(t, rootCmd.Name(), "kn") - assert.Equal(t, rootCmd.Short, "Knative client") + assert.Assert(t, util.ContainsAll(rootCmd.Short, "Knative", "Serving", "Eventing")) assert.Assert(t, util.ContainsAll(rootCmd.Long, "Knative", "Serving", "Eventing")) assert.Assert(t, rootCmd.DisableAutoGenTag) diff --git a/pkg/templates/command_groups.go b/pkg/templates/command_groups.go new file mode 100644 index 0000000000..f0093ca067 --- /dev/null +++ b/pkg/templates/command_groups.go @@ -0,0 +1,66 @@ +// Copyright © 2019 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package templates + +import ( + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +// A command group is for grouping together commands +type CommandGroup struct { + + // Title for command group shown in help/usage messages + Header string + + // List of commans for this group + Commands []*cobra.Command +} + +type CommandGroups []CommandGroup + +// Add all commands from this group slice to the given command +func (g CommandGroups) AddTo(cmd *cobra.Command) { + for _, group := range g { + for _, sub := range group.Commands { + cmd.AddCommand(sub) + } + } +} + +// SetRootUsage sets our own help and usage function messages to the root command +func (g CommandGroups) SetRootUsage(rootCmd *cobra.Command) { + engine := &templateEngine{ + RootCmd: rootCmd, + CommandGroups: g, + } + setHelpFlagsToSubCommands(rootCmd) + rootCmd.SilenceUsage = true + rootCmd.SilenceErrors = true + rootCmd.SetFlagErrorFunc(func(c *cobra.Command, err error) error { + return errors.Errorf("%s for '%s'", err.Error(), c.CommandPath()) + }) + rootCmd.SetUsageFunc(engine.usageFunc()) + rootCmd.SetHelpFunc(engine.helpFunc()) +} + +func setHelpFlagsToSubCommands(parent *cobra.Command) { + for _, cmd := range parent.Commands() { + if cmd.HasSubCommands() { + setHelpFlagsToSubCommands(cmd) + } + cmd.DisableFlagsInUseLine = true + } +} diff --git a/pkg/templates/template_engine.go b/pkg/templates/template_engine.go new file mode 100644 index 0000000000..826b2383bd --- /dev/null +++ b/pkg/templates/template_engine.go @@ -0,0 +1,190 @@ +// Copyright © 2019 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package templates + +import ( + "bytes" + "fmt" + "os" + "strings" + "text/template" + "unicode" + + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + "golang.org/x/crypto/ssh/terminal" +) + +type templateEngine struct { + RootCmd *cobra.Command + CommandGroups +} + +// Get the function to show the global options +func NewGlobalOptionsFunc() func(command *cobra.Command) error { + return templateEngine{}.optionsFunc() +} + +func (e templateEngine) usageFunc() func(command *cobra.Command) error { + return func(c *cobra.Command) error { + return e.fillTemplate("usage", c, usageTemplate()) + } +} + +func (e templateEngine) helpFunc() func(*cobra.Command, []string) { + return func(c *cobra.Command, s []string) { + err := e.fillTemplate("help", c, helpTemplate()) + if err != nil { + c.Println(err) + } + } +} + +func (e templateEngine) optionsFunc() func(command *cobra.Command) error { + return func(c *cobra.Command) error { + return e.fillTemplate("options", c, optionsTemplate()) + } +} + +func (e templateEngine) fillTemplate(name string, c *cobra.Command, templ string) error { + t := template.New(name) + t.Funcs(e.templateFunctions()) + _, err := t.Parse(templ) + if err != nil { + fmt.Fprintf(c.ErrOrStderr(), "\nINTERNAL: >>>>> %v\n", err) + return err + } + // out := term.NewResponsiveWriter(c.OutOrStdout()) + return t.Execute(c.OutOrStdout(), c) +} + +// ====================================================================================== +// Template helper functions + +func (e templateEngine) templateFunctions() template.FuncMap { + return template.FuncMap{ + "cmdGroupsString": e.cmdGroupsString, + "subCommandsString": e.subCommandsString, + "useLine": useLine, + "visibleFlags": visibleFlags, + "rpad": rpad, + "rootCmdName": e.rootCmdName, + "isRootCmd": e.isRootCmd, + "flagsUsages": flagsUsagesCobra, // or use flagsUsagesKubectl for kubectl like flag styles + "trim": strings.TrimSpace, + "trimRight": func(s string) string { return strings.TrimRightFunc(s, unicode.IsSpace) }, + "trimLeft": func(s string) string { return strings.TrimLeftFunc(s, unicode.IsSpace) }, + } +} + +func (e templateEngine) cmdGroupsString() string { + var groups []string + for _, cmdGroup := range e.CommandGroups { + groups = append(groups, formatCommandGroup(cmdGroup)) + } + return strings.Join(groups, "\n\n") +} + +func (e templateEngine) subCommandsString(c *cobra.Command) string { + return formatCommandGroup(CommandGroup{ + Header: "Available Commands:", + Commands: c.Commands(), + }) +} + +func (e templateEngine) rootCmdName() string { + return e.RootCmd.CommandPath() +} + +func (e templateEngine) isRootCmd(c *cobra.Command) bool { + return e.RootCmd == c +} + +func visibleFlags(c *cobra.Command) *flag.FlagSet { + ret := flag.NewFlagSet("filtered", flag.ContinueOnError) + local := c.LocalFlags() + persistent := c.PersistentFlags() + local.VisitAll(func(flag *flag.Flag) { + if flag.Name != "help" && persistent.Lookup(flag.Name) == nil { + ret.AddFlag(flag) + } + }) + return ret +} + +func useLine(c *cobra.Command) string { + var useline string + if c.HasParent() { + useline = c.Parent().CommandPath() + " " + c.Use + } else { + useline = c.Use + } + suffix := "[options]" + if c.HasFlags() && !strings.Contains(useline, suffix) { + useline += " " + suffix + } + return useline +} + +func formatCommandGroup(cmdGroup CommandGroup) string { + cmds := []string{cmdGroup.Header} + for _, cmd := range cmdGroup.Commands { + if cmd.IsAvailableCommand() { + cmds = append(cmds, " "+rpad(cmd.Name(), cmd.NamePadding())+" "+cmd.Short) + } + } + return strings.Join(cmds, "\n") +} + +func rpad(s string, padding int) string { + t := fmt.Sprintf("%%-%ds", padding) + return fmt.Sprintf(t, s) +} + +// flagsUsagesCobra formats flags in Cobra style +func flagsUsagesCobra(f *flag.FlagSet) string { + width, _, err := terminal.GetSize(int(os.Stdout.Fd())) + if err == nil { + return f.FlagUsagesWrapped(width) + } else { + return f.FlagUsages() + } +} + +// flagsUsagesKubectl formats the flags like kubectl does +func flagsUsagesKubectl(f *flag.FlagSet) string { + x := new(bytes.Buffer) + + f.VisitAll(func(flag *flag.Flag) { + if flag.Hidden { + return + } + format := "--%s=%s: %s\n" + + if flag.Value.Type() == "string" { + format = "--%s='%s': %s\n" + } + + if len(flag.Shorthand) > 0 { + format = " -%s, " + format + } else { + format = " %s " + format + } + + fmt.Fprintf(x, format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage) + }) + + return x.String() +} diff --git a/pkg/templates/templates.go b/pkg/templates/templates.go new file mode 100644 index 0000000000..51bc1625ea --- /dev/null +++ b/pkg/templates/templates.go @@ -0,0 +1,95 @@ +// Copyright © 2020 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package templates + +import ( + "strings" + "unicode" +) + +// Templates for help & usage messages. These has been initially taken over from +// https://github.com/kubernetes/kubectl/blob/f9e4fa6b9cff11b6e2949b76680b8cd5b8192eab/pkg/util/templates/templates.go +// and adapted to the specific needs of `kn` + +const ( + // sectionAliases is the help template section that displays command aliases. + sectionAliases = `{{if gt .Aliases 0}}Aliases: +{{.NameAndAliases}} + +{{end}}` + + // sectionExamples is the help template section that displays command examples. + sectionExamples = `{{if .HasExample}}Examples: +{{trimRight .Example}} + +{{end}}` + + // sectionCommandGroups is the grouped help message + sectionCommandGroups = `{{if isRootCmd .}}{{cmdGroupsString}} + +{{end}}` + + // sectionSubCommands is the help template section that displays the command's subcommands. + sectionSubCommands = `{{if and (not (isRootCmd .)) .HasAvailableSubCommands}}{{subCommandsString .}} + +{{end}}` + + // sectionFlags is the help template section that displays the command's flags. + sectionFlags = `{{$visibleFlags := visibleFlags .}}{{ if $visibleFlags.HasFlags}}Options: +{{trimRight (flagsUsages $visibleFlags)}} + +{{end}}` + + // sectionUsage is the help template section that displays the command's usage. + sectionUsage = `{{if and .Runnable (ne .UseLine "") (not (isRootCmd .))}}Usage: + {{useLine .}} + +{{end}}` + + // sectionTipsHelp is the help template section that displays the '--help' hint. + sectionTipsHelp = `{{if .HasSubCommands}}Use "{{rootCmdName}} --help" for more information about a given command. +{{end}}` + + // sectionTipsGlobalOptions is the help template section that displays the 'options' hint for displaying global flags. + sectionTipsGlobalOptions = `Use "{{rootCmdName}} options" for a list of global command-line options (applies to all commands).` +) + +// usageTemplate if the template for 'usage' used by most commands. +func usageTemplate() string { + sections := []string{ + "\n\n", + // sectionAliases, + sectionExamples, + sectionCommandGroups, + sectionSubCommands, + sectionFlags, + sectionUsage, + sectionTipsHelp, + sectionTipsGlobalOptions, + } + return strings.TrimRightFunc(strings.Join(sections, ""), unicode.IsSpace) + "\n" +} + +// helpTemplate is the template for 'help' used by most commands. +func helpTemplate() string { + return `{{with or .Long .Short }}{{. | trim}}{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` +} + +// optionsTemplate is the template used by "kn options" +func optionsTemplate() string { + return `{{ if .HasInheritedFlags}}The following options can be passed to any command: + +{{flagsUsages .InheritedFlags}}{{end}}` +} From 8f7d6461fb779ce0e5495ffd29da13334ce603d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Tue, 16 Jun 2020 11:56:02 +0200 Subject: [PATCH 02/20] chore: Add missing file --- docs/cmd/kn_options.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 docs/cmd/kn_options.md diff --git a/docs/cmd/kn_options.md b/docs/cmd/kn_options.md new file mode 100644 index 0000000000..2732acb3f2 --- /dev/null +++ b/docs/cmd/kn_options.md @@ -0,0 +1,37 @@ +## kn options + +Print the list of flags inherited by all commands + +### Synopsis + +Print the list of flags inherited by all commands + +``` +kn options [flags] +``` + +### Examples + +``` +# Print flags inherited by all commands +kn options +``` + +### Options + +``` + -h, --help help for options +``` + +### Options inherited from parent commands + +``` + --config string kn configuration file (default: ~/.config/kn/config.yaml) + --kubeconfig string kubectl configuration file (default: ~/.kube/config) + --log-http log http traffic +``` + +### SEE ALSO + +* [kn](kn.md) - kn manages Knative Serving and Eventing resources + From aaf97c83fa669b8a69296f966978f74e772b6920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Tue, 16 Jun 2020 11:57:25 +0200 Subject: [PATCH 03/20] Update pkg/templates/command_groups.go Co-authored-by: Matt Moore --- pkg/templates/command_groups.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/templates/command_groups.go b/pkg/templates/command_groups.go index f0093ca067..52d22798fe 100644 --- a/pkg/templates/command_groups.go +++ b/pkg/templates/command_groups.go @@ -25,7 +25,7 @@ type CommandGroup struct { // Title for command group shown in help/usage messages Header string - // List of commans for this group + // List of commands for this group Commands []*cobra.Command } From 20f35f66e193a9e751f678dfdb4cde47b8b2d172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Tue, 16 Jun 2020 22:16:25 +0200 Subject: [PATCH 04/20] chore: Add some test for error messages --- cmd/kn/main.go | 16 +++++++-- cmd/kn/main_test.go | 32 +++++++++++++++-- pkg/kn/commands/completion/completion_test.go | 7 ++-- pkg/kn/commands/testing_helper.go | 35 ++++++++++++------- pkg/kn/commands/testing_helper_test.go | 7 ++-- 5 files changed, 75 insertions(+), 22 deletions(-) diff --git a/cmd/kn/main.go b/cmd/kn/main.go index 48a5991eec..045a7bc59f 100644 --- a/cmd/kn/main.go +++ b/cmd/kn/main.go @@ -37,8 +37,7 @@ func init() { func main() { err := run(os.Args[1:]) if err != nil && len(os.Args) > 1 { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - fmt.Fprintf(os.Stderr, "Run '%s --help' for usage\n", extractCommandPathFromErrorMessage(err.Error(), os.Args[0])) + printError(err) // This is the only point from where to exit when an error occurs os.Exit(1) } @@ -188,6 +187,12 @@ func validateRootCommand(cmd *cobra.Command) error { return nil } +// printError prints out any given error +func printError(err error) { + fmt.Fprintf(os.Stderr, "Error: %s\n", cleanupErrorMessage(err.Error())) + fmt.Fprintf(os.Stderr, "Run '%s --help' for usage\n", extractCommandPathFromErrorMessage(err.Error(), os.Args[0])) +} + // extractCommandPathFromErrorMessage tries to extract the command name from an error message // by checking a pattern like 'kn service' in the error message. If not found, return the // base command name. @@ -199,3 +204,10 @@ func extractCommandPathFromErrorMessage(errorMsg string, arg0 string) string { } return arg0 } + +// cleanupErrorMessage remove any redundance content of an error message +func cleanupErrorMessage(msg string) string { + regexp := regexp.MustCompile("(?i)^error:\\s*") + return string(regexp.ReplaceAll([]byte(msg), []byte(""))) +} + diff --git a/cmd/kn/main_test.go b/cmd/kn/main_test.go index d7db1e6340..3f469800fa 100644 --- a/cmd/kn/main_test.go +++ b/cmd/kn/main_test.go @@ -15,8 +15,10 @@ package main import ( + "errors" "fmt" "os" + "strings" "testing" "github.com/spf13/cobra" @@ -226,6 +228,32 @@ func TestStripFlags(t *testing.T) { } } +func TestRunWithError(t *testing.T) { + data := []struct { + given string + expected string + } { + { + "unknown sub-command blub", + "Error: unknown sub-command blub", + }, + { + "error: unknown type blub", + "Error: unknown type blub", + }, + + } + for _, d := range data { + capture := commands.CaptureOutput(t) + printError(errors.New(d.given)) + stdOut, errOut := capture.Close() + + assert.Equal(t, stdOut, "") + assert.Assert(t, strings.Contains(errOut, d.expected)) + assert.Assert(t, util.ContainsAll(errOut, "Run", "--help", "usage")) + } +} + // Smoke test func TestRun(t *testing.T) { oldArgs := os.Args @@ -234,9 +262,9 @@ func TestRun(t *testing.T) { os.Args = oldArgs })() - capture := commands.CaptureStdout(t) + capture := commands.CaptureOutput(t) err := run(os.Args[1:]) - out := capture.Close() + out, _ := capture.Close() assert.NilError(t, err) assert.Assert(t, util.ContainsAllIgnoreCase(out, "version", "build", "git")) diff --git a/pkg/kn/commands/completion/completion_test.go b/pkg/kn/commands/completion/completion_test.go index 258d979b3c..7ca71708fb 100644 --- a/pkg/kn/commands/completion/completion_test.go +++ b/pkg/kn/commands/completion/completion_test.go @@ -35,11 +35,12 @@ func TestCompletionUsage(t *testing.T) { func TestCompletionGeneration(t *testing.T) { for _, shell := range []string{"bash", "zsh"} { completionCmd := NewCompletionCommand(&commands.KnParams{}) - c := commands.CaptureStdout(t) + c := commands.CaptureOutput(t) err := completionCmd.RunE(&cobra.Command{}, []string{shell}) assert.NilError(t, err) - out := c.Close() - assert.Assert(t, out != "") + stdOut, stdErr := c.Close() + assert.Assert(t, stdErr == "") + assert.Assert(t, stdOut != "") } } diff --git a/pkg/kn/commands/testing_helper.go b/pkg/kn/commands/testing_helper.go index 13693d9049..4c8d2c76b9 100644 --- a/pkg/kn/commands/testing_helper.go +++ b/pkg/kn/commands/testing_helper.go @@ -93,33 +93,44 @@ func CreateDynamicTestKnCommand(cmd *cobra.Command, knParams *KnParams, objects } -type StdoutCapture struct { - r, w *os.File - t *testing.T +type OutputCapture struct { + outRead, outWrite *os.File + errorRead, errorWrite *os.File + t *testing.T oldStdout *os.File + oldStderr *os.File } -func CaptureStdout(t *testing.T) StdoutCapture { - ret := StdoutCapture{ +func CaptureOutput(t *testing.T) OutputCapture { + ret := OutputCapture{ oldStdout: os.Stdout, + oldStderr: os.Stderr, t: t, } var err error - ret.r, ret.w, err = os.Pipe() + ret.outRead, ret.outWrite, err = os.Pipe() assert.NilError(t, err) - os.Stdout = ret.w + os.Stdout = ret.outWrite + ret.errorRead, ret.errorWrite, err = os.Pipe() + assert.NilError(t, err) + os.Stderr = ret.errorWrite return ret } -// CaptureStdout collects the current content of os.Stdout -func (c StdoutCapture) Close() string { - err := c.w.Close() +// CaptureOutput collects the current content of os.Stdout +func (c OutputCapture) Close() (string, string) { + err := c.outWrite.Close() + assert.NilError(c.t, err) + err = c.errorWrite.Close() + assert.NilError(c.t, err) + outOutput, err := ioutil.ReadAll(c.outRead) assert.NilError(c.t, err) - ret, err := ioutil.ReadAll(c.r) + errOutput, err := ioutil.ReadAll(c.errorRead) assert.NilError(c.t, err) os.Stdout = c.oldStdout - return string(ret) + os.Stderr = c.oldStderr + return string(outOutput), string(errOutput) } // NewTestCommand can be used by tes diff --git a/pkg/kn/commands/testing_helper_test.go b/pkg/kn/commands/testing_helper_test.go index 3a729e1e8d..fea84d3a78 100644 --- a/pkg/kn/commands/testing_helper_test.go +++ b/pkg/kn/commands/testing_helper_test.go @@ -56,8 +56,9 @@ func TestCreateDynamicTestKnCommand(t *testing.T) { } func TestCaptureStdout(t *testing.T) { - c := CaptureStdout(t) + c := CaptureOutput(t) fmt.Print("Hello World !") - out := c.Close() - assert.Equal(t, out, "Hello World !") + stdOut, stdErr := c.Close() + assert.Equal(t, stdErr, "") + assert.Equal(t, stdOut, "Hello World !") } From 1676df6332631522ddc7650234073807a6f89279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Tue, 16 Jun 2020 22:31:39 +0200 Subject: [PATCH 05/20] fix formatting --- cmd/kn/main.go | 1 - cmd/kn/main_test.go | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cmd/kn/main.go b/cmd/kn/main.go index 045a7bc59f..876cd50fe1 100644 --- a/cmd/kn/main.go +++ b/cmd/kn/main.go @@ -210,4 +210,3 @@ func cleanupErrorMessage(msg string) string { regexp := regexp.MustCompile("(?i)^error:\\s*") return string(regexp.ReplaceAll([]byte(msg), []byte(""))) } - diff --git a/cmd/kn/main_test.go b/cmd/kn/main_test.go index 3f469800fa..c41ba3cfec 100644 --- a/cmd/kn/main_test.go +++ b/cmd/kn/main_test.go @@ -230,9 +230,9 @@ func TestStripFlags(t *testing.T) { func TestRunWithError(t *testing.T) { data := []struct { - given string + given string expected string - } { + }{ { "unknown sub-command blub", "Error: unknown sub-command blub", @@ -241,7 +241,6 @@ func TestRunWithError(t *testing.T) { "error: unknown type blub", "Error: unknown type blub", }, - } for _, d := range data { capture := commands.CaptureOutput(t) From f2a93e3bf7fe2fa48f9b54d594b6454d9876eccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 08:17:36 +0200 Subject: [PATCH 06/20] chore: Add test --- pkg/templates/template_engine_test.go | 175 ++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 pkg/templates/template_engine_test.go diff --git a/pkg/templates/template_engine_test.go b/pkg/templates/template_engine_test.go new file mode 100644 index 0000000000..990373c910 --- /dev/null +++ b/pkg/templates/template_engine_test.go @@ -0,0 +1,175 @@ +// Copyright © 2019 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package templates + +import ( + "strings" + "testing" + + flag "github.com/spf13/pflag" + + "github.com/spf13/cobra" + "gotest.tools/assert" + + "knative.dev/client/pkg/kn/commands" + "knative.dev/client/pkg/util" +) + +type testData struct { + cmd *cobra.Command + validate func(*testing.T, string, *cobra.Command) +} + +func TestUsageFunc(t *testing.T) { + rootCmd, engine := newTemplateEngine() + subCmdWithSubs, _, _ := rootCmd.Find([]string{"g1.1"}) + subCmd, _, _ := rootCmd.Find([]string{"g2.1"}) + + data := []testData{ + { + rootCmd, + func(t *testing.T, out string, command *cobra.Command) { + validateRootUsageOutput(t, out) + }, + }, + { + subCmd, + func(t *testing.T, out string, command *cobra.Command) { + validateSubUsageOutput(t, out, command) + }, + }, + { + subCmdWithSubs, + func(t *testing.T, out string, command *cobra.Command) { + validateSubUsageOutput(t, out, command) + subsub := command.Commands()[0] + assert.Assert(t, util.ContainsAll(out, subsub.Name(), subsub.Short, "Available Commands:")) + }, + }, + } + for _, d := range data { + capture := commands.CaptureOutput(t) + err := (engine.usageFunc())(d.cmd) + assert.NilError(t, err) + stdOut, stdErr := capture.Close() + + assert.Equal(t, stdErr, "") + d.validate(t, stdOut, d.cmd) + } +} + +func TestHelpFunc(t *testing.T) { + rootCmd, engine := newTemplateEngine() + subCmd := rootCmd.Commands()[0] + + data := []testData{ + { + rootCmd, + func(t *testing.T, out string, command *cobra.Command) { + validateRootUsageOutput(t, out) + assert.Assert(t, strings.Contains(out, command.Long)) + }, + }, + { + subCmd, + func(t *testing.T, out string, command *cobra.Command) { + validateSubUsageOutput(t, out, command) + assert.Assert(t, strings.Contains(out, command.Long)) + }, + }, + } + for _, d := range data { + capture := commands.CaptureOutput(t) + (engine.helpFunc())(d.cmd, []string{}) + stdOut, stdErr := capture.Close() + + assert.Equal(t, stdErr, "") + d.validate(t, stdOut, d.cmd) + } +} + +func TestOptionsFunc(t *testing.T) { + rootCmd, _ := newTemplateEngine() + subCmd := rootCmd.Commands()[0] + capture := commands.CaptureOutput(t) + err := NewGlobalOptionsFunc()(subCmd) + assert.NilError(t, err) + stdOut, stdErr := capture.Close() + + assert.Equal(t, stdErr, "") + assert.Assert(t, util.ContainsAll(stdOut, "options", "any command", "--global-opt", "global option")) +} + +func TestUsageFlags(t *testing.T) { + f := flag.NewFlagSet("test", flag.ContinueOnError) + f.StringP("test", "t", "default", "test-option") + usage := flagsUsagesKubectl(f) + assert.Equal(t, usage, " -t, --test='default': test-option\n") + usage = flagsUsagesCobra(f) + assert.Equal(t, usage, " -t, --test string test-option (default \"default\")\n") + +} +func validateRootUsageOutput(t *testing.T, stdOut string) { + assert.Assert(t, util.ContainsAll(stdOut, "root")) + assert.Assert(t, util.ContainsAll(stdOut, "header-1", "g1.1", "desc-g1.1", "g1.2", "desc-g1.2")) + assert.Assert(t, util.ContainsAll(stdOut, "header-2", "g2.1", "desc-g2.1", "g2.2", "desc-g2.2", "g2.3", "desc-g2.3")) + assert.Assert(t, util.ContainsAll(stdOut, "Use", "root", "--help")) + assert.Assert(t, util.ContainsAll(stdOut, "Use", "root", "options", "global")) +} + +func validateSubUsageOutput(t *testing.T, stdOut string, cmd *cobra.Command) { + assert.Assert(t, util.ContainsAll(stdOut, "Usage", cmd.CommandPath()+" [options]")) + assert.Assert(t, util.ContainsAll(stdOut, "Options", "--local-opt", "local option")) + assert.Assert(t, util.ContainsAll(stdOut, "Use", "root", "options", "global")) +} + +func newTemplateEngine() (*cobra.Command, templateEngine) { + rootCmd := &cobra.Command{Use: "root", Short: "desc-root", Long: "longdesc-root"} + rootCmd.PersistentFlags().String("global-opt", "", "global option") + cmdGroups := CommandGroups{ + { + "header-1", + []*cobra.Command{newCmd("g1.1"), newCmd("g1.2")}, + }, + { + "header-2", + []*cobra.Command{newCmd("g2.1"), newCmd("g2.2"), newCmd("g2.3")}, + }, + } + engine := templateEngine{ + RootCmd: rootCmd, + CommandGroups: cmdGroups, + } + cmdGroups.AddTo(rootCmd) + + // Add a sub-command to first command + cmd, _, _ := rootCmd.Find([]string{"g1.1"}) + cmd.AddCommand(newCmd("g1.1.1")) + + rootCmd.SetUsageFunc(engine.usageFunc()) + + return rootCmd, engine +} + +func newCmd(name string) *cobra.Command { + ret := &cobra.Command{ + Use: name, + Short: "desc-" + name, + Long: "longdesc-" + name, + Run: func(cmd *cobra.Command, args []string) {}, + } + ret.Flags().String("local-opt", "", "local option") + return ret +} From 41338722cdc2124dda2b3a594527749a31d8b735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 08:58:57 +0200 Subject: [PATCH 07/20] moar tests --- pkg/templates/command_groups.go | 2 +- pkg/templates/command_groups_test.go | 75 +++++++++++++++++++++++++++ pkg/templates/template_engine.go | 2 +- pkg/templates/template_engine_test.go | 2 +- 4 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 pkg/templates/command_groups_test.go diff --git a/pkg/templates/command_groups.go b/pkg/templates/command_groups.go index 52d22798fe..abac9d6e05 100644 --- a/pkg/templates/command_groups.go +++ b/pkg/templates/command_groups.go @@ -1,4 +1,4 @@ -// Copyright © 2019 The Knative Authors +// Copyright © 2020 The Knative Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/pkg/templates/command_groups_test.go b/pkg/templates/command_groups_test.go new file mode 100644 index 0000000000..4e3cc02c7e --- /dev/null +++ b/pkg/templates/command_groups_test.go @@ -0,0 +1,75 @@ +// Copyright © 2020 The Knative Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package templates + +import ( + "errors" + "fmt" + "testing" + + "github.com/spf13/cobra" + "gotest.tools/assert" + + "knative.dev/client/pkg/kn/commands" + "knative.dev/client/pkg/util" +) + +var groups = CommandGroups{ + { + "header-1", + []*cobra.Command{{Use: "c0"}, {Use: "c1"}}, + }, + { + "header-2", + []*cobra.Command{{Use: "c2"}}, + }, +} + +func TestAddTo(t *testing.T) { + rootCmd := &cobra.Command{Use: "root"} + groups.AddTo(rootCmd) + + for idx, cmd := range rootCmd.Commands() { + assert.Equal(t, cmd.Name(), fmt.Sprintf("c%d", idx)) + } +} + +func TestSetUsage(t *testing.T) { + rootCmd := &cobra.Command{Use: "root", Short: "root", Run: func(cmd *cobra.Command, args []string) {}} + groups.AddTo(rootCmd) + groups.SetRootUsage(rootCmd) + + for _, cmd := range rootCmd.Commands() { + assert.Assert(t, cmd.DisableFlagsInUseLine) + } + assert.Assert(t, rootCmd.SilenceUsage) + assert.Assert(t, rootCmd.SilenceErrors) + fErrorFunc := rootCmd.FlagErrorFunc() + err := fErrorFunc(rootCmd, errors.New("test")) + assert.Equal(t, err.Error(), "test for 'root'") + + capture := commands.CaptureOutput(t) + err = (rootCmd.UsageFunc())(rootCmd) + assert.NilError(t, err) + stdOut, stdErr := capture.Close() + assert.Equal(t, stdErr, "") + assert.Assert(t, util.ContainsAll(stdOut, "header-1", "header-2")) + + capture = commands.CaptureOutput(t) + (rootCmd.HelpFunc())(rootCmd, nil) + stdOut, stdErr = capture.Close() + assert.Equal(t, stdErr, "") + assert.Assert(t, util.ContainsAll(stdOut, "root", "header-1", "header-2")) +} diff --git a/pkg/templates/template_engine.go b/pkg/templates/template_engine.go index 826b2383bd..a927078788 100644 --- a/pkg/templates/template_engine.go +++ b/pkg/templates/template_engine.go @@ -1,4 +1,4 @@ -// Copyright © 2019 The Knative Authors +// Copyright © 2020 The Knative Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/pkg/templates/template_engine_test.go b/pkg/templates/template_engine_test.go index 990373c910..b1ee05dfcc 100644 --- a/pkg/templates/template_engine_test.go +++ b/pkg/templates/template_engine_test.go @@ -1,4 +1,4 @@ -// Copyright © 2019 The Knative Authors +// Copyright © 2020 The Knative Authors // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. From c57267b3d2960204fc0504cda5d8ce1b469470c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 14:50:44 +0200 Subject: [PATCH 08/20] Update pkg/kn/commands/completion/completion.go Co-authored-by: Navid Shaikh --- pkg/kn/commands/completion/completion.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kn/commands/completion/completion.go b/pkg/kn/commands/completion/completion.go index 2979bf8970..c8e64224c9 100644 --- a/pkg/kn/commands/completion/completion.go +++ b/pkg/kn/commands/completion/completion.go @@ -60,7 +60,7 @@ func NewCompletionCommand(p *commands.KnParams) *cobra.Command { return errors.New("'bash' or 'zsh' shell completion is supported") } } else { - return errors.New("Only one argument is can be provided, either 'bash' or 'zsh'") + return errors.New("Only one argument can be provided, either 'bash' or 'zsh'") } }, } From 98f46e5bee867f0ca1f370ddf6d180fdc66cc51d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 14:51:11 +0200 Subject: [PATCH 09/20] Update pkg/kn/commands/source/apiserver/delete.go Co-authored-by: Navid Shaikh --- pkg/kn/commands/source/apiserver/delete.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kn/commands/source/apiserver/delete.go b/pkg/kn/commands/source/apiserver/delete.go index 82c52324fb..b4ce0b7fbc 100644 --- a/pkg/kn/commands/source/apiserver/delete.go +++ b/pkg/kn/commands/source/apiserver/delete.go @@ -27,7 +27,7 @@ import ( func NewAPIServerDeleteCommand(p *commands.KnParams) *cobra.Command { deleteCommand := &cobra.Command{ Use: "delete NAME", - Short: "Delete api-server sources", + Short: "Delete an api-server source", Example: ` # Delete an ApiServerSource 'k8sevents' in default namespace kn source apiserver delete k8sevents`, From 48ac48a249886adf00484d805287e4ad87b337be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 14:51:41 +0200 Subject: [PATCH 10/20] Update pkg/kn/commands/service/list.go Co-authored-by: Navid Shaikh --- pkg/kn/commands/service/list.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kn/commands/service/list.go b/pkg/kn/commands/service/list.go index 9b0030ae93..ff300304a1 100644 --- a/pkg/kn/commands/service/list.go +++ b/pkg/kn/commands/service/list.go @@ -32,7 +32,7 @@ func NewServiceListCommand(p *commands.KnParams) *cobra.Command { serviceListCommand := &cobra.Command{ Use: "list", - Short: "List available services", + Short: "List services", Example: ` # List all services kn service list From 6b8067dbdaf38442b3127b674a96bac4d86b933c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 14:53:07 +0200 Subject: [PATCH 11/20] Update pkg/kn/commands/route/route.go Co-authored-by: Navid Shaikh --- pkg/kn/commands/route/route.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kn/commands/route/route.go b/pkg/kn/commands/route/route.go index 7f9c907037..e1a4a24a0e 100644 --- a/pkg/kn/commands/route/route.go +++ b/pkg/kn/commands/route/route.go @@ -23,7 +23,7 @@ import ( func NewRouteCommand(p *commands.KnParams) *cobra.Command { routeCmd := &cobra.Command{ Use: "route", - Short: "List and show service routes", + Short: "List and describe service routes", } routeCmd.AddCommand(NewRouteListCommand(p)) routeCmd.AddCommand(NewRouteDescribeCommand(p)) From dd61c336b9110da44993602f3fdd07c8f3bfc61f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 14:53:20 +0200 Subject: [PATCH 12/20] Update pkg/kn/commands/revision/delete.go Co-authored-by: Navid Shaikh --- pkg/kn/commands/revision/delete.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kn/commands/revision/delete.go b/pkg/kn/commands/revision/delete.go index 536704506b..2c40e7a245 100644 --- a/pkg/kn/commands/revision/delete.go +++ b/pkg/kn/commands/revision/delete.go @@ -30,7 +30,7 @@ func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command { RevisionDeleteCommand := &cobra.Command{ Use: "delete NAME", - Short: "Delete a revision", + Short: "Delete revisions", Example: ` # Delete a revision 'svc1-abcde' in default namespace kn revision delete svc1-abcde`, From ea526fd713fde05ca43542619d752dfab0ecdb67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 14:53:41 +0200 Subject: [PATCH 13/20] Update pkg/kn/commands/plugin/plugin.go Co-authored-by: Navid Shaikh --- pkg/kn/commands/plugin/plugin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kn/commands/plugin/plugin.go b/pkg/kn/commands/plugin/plugin.go index 473516b064..4a82598366 100644 --- a/pkg/kn/commands/plugin/plugin.go +++ b/pkg/kn/commands/plugin/plugin.go @@ -24,7 +24,7 @@ func NewPluginCommand(p *commands.KnParams) *cobra.Command { pluginCmd := &cobra.Command{ Use: "plugin", Short: "Manage kn plugins", - Long: `Manage kn plugins. + Long: `Manage kn plugins Plugins provide extended functionality that is not part of the core kn command-line distribution. Please refer to the documentation and examples for more information about how to write your own plugins.`, From 8fa097fea44f7473eb59b69ad9dc2c3edd1d964a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 14:55:14 +0200 Subject: [PATCH 14/20] Update pkg/kn/commands/service/delete.go Co-authored-by: Navid Shaikh --- pkg/kn/commands/service/delete.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kn/commands/service/delete.go b/pkg/kn/commands/service/delete.go index 22ddf81b93..4d2597db47 100644 --- a/pkg/kn/commands/service/delete.go +++ b/pkg/kn/commands/service/delete.go @@ -31,7 +31,7 @@ func NewServiceDeleteCommand(p *commands.KnParams) *cobra.Command { serviceDeleteCommand := &cobra.Command{ Use: "delete NAME", - Short: "Delete a service", + Short: "Delete services", Example: ` # Delete a service 'svc1' in default namespace kn service delete svc1 From 377cf192a8afc147dd884c9dd3728ddf06eaa251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 14:55:37 +0200 Subject: [PATCH 15/20] Update pkg/kn/commands/revision/delete.go Co-authored-by: Navid Shaikh --- pkg/kn/commands/revision/delete.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kn/commands/revision/delete.go b/pkg/kn/commands/revision/delete.go index 2c40e7a245..78d101cabf 100644 --- a/pkg/kn/commands/revision/delete.go +++ b/pkg/kn/commands/revision/delete.go @@ -29,7 +29,7 @@ func NewRevisionDeleteCommand(p *commands.KnParams) *cobra.Command { var waitFlags commands.WaitFlags RevisionDeleteCommand := &cobra.Command{ - Use: "delete NAME", + Use: "delete NAME [NAME ...]", Short: "Delete revisions", Example: ` # Delete a revision 'svc1-abcde' in default namespace From 305d9ca7b97471cd53057ec2fca03be3b5944cbc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 14:55:55 +0200 Subject: [PATCH 16/20] Update pkg/kn/commands/service/delete.go Co-authored-by: Navid Shaikh --- pkg/kn/commands/service/delete.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kn/commands/service/delete.go b/pkg/kn/commands/service/delete.go index 4d2597db47..54953cf4e6 100644 --- a/pkg/kn/commands/service/delete.go +++ b/pkg/kn/commands/service/delete.go @@ -30,7 +30,7 @@ func NewServiceDeleteCommand(p *commands.KnParams) *cobra.Command { var waitFlags commands.WaitFlags serviceDeleteCommand := &cobra.Command{ - Use: "delete NAME", + Use: "delete NAME [NAME ...]", Short: "Delete services", Example: ` # Delete a service 'svc1' in default namespace From ee71d82d986a75985984e6d0cc82f5a31d0925c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 16:17:48 +0200 Subject: [PATCH 17/20] regen docs --- docs/cmd/kn.md | 2 +- docs/cmd/kn_plugin.md | 2 +- docs/cmd/kn_revision.md | 2 +- docs/cmd/kn_revision_delete.md | 6 +++--- docs/cmd/kn_route.md | 4 ++-- docs/cmd/kn_route_describe.md | 2 +- docs/cmd/kn_route_list.md | 2 +- docs/cmd/kn_service.md | 4 ++-- docs/cmd/kn_service_delete.md | 6 +++--- docs/cmd/kn_service_list.md | 4 ++-- docs/cmd/kn_source_apiserver.md | 2 +- docs/cmd/kn_source_apiserver_delete.md | 4 ++-- 12 files changed, 20 insertions(+), 20 deletions(-) diff --git a/docs/cmd/kn.md b/docs/cmd/kn.md index eecf628f83..60ec6e8ce6 100644 --- a/docs/cmd/kn.md +++ b/docs/cmd/kn.md @@ -23,7 +23,7 @@ kn is the command line interface for managing Knative Serving and Eventing resou * [kn options](kn_options.md) - Print the list of flags inherited by all commands * [kn plugin](kn_plugin.md) - Manage kn plugins * [kn revision](kn_revision.md) - Manage service revisions -* [kn route](kn_route.md) - List and show service routes +* [kn route](kn_route.md) - List and describe service routes * [kn service](kn_service.md) - Manage Knative services * [kn source](kn_source.md) - Manage event sources * [kn trigger](kn_trigger.md) - Manage event triggers diff --git a/docs/cmd/kn_plugin.md b/docs/cmd/kn_plugin.md index 2f0470884f..ead701a002 100644 --- a/docs/cmd/kn_plugin.md +++ b/docs/cmd/kn_plugin.md @@ -4,7 +4,7 @@ Manage kn plugins ### Synopsis -Manage kn plugins. +Manage kn plugins Plugins provide extended functionality that is not part of the core kn command-line distribution. Please refer to the documentation and examples for more information about how to write your own plugins. diff --git a/docs/cmd/kn_revision.md b/docs/cmd/kn_revision.md index d264d28385..d07e70aeb9 100644 --- a/docs/cmd/kn_revision.md +++ b/docs/cmd/kn_revision.md @@ -27,7 +27,7 @@ kn revision ### SEE ALSO * [kn](kn.md) - kn manages Knative Serving and Eventing resources -* [kn revision delete](kn_revision_delete.md) - Delete a revision +* [kn revision delete](kn_revision_delete.md) - Delete revisions * [kn revision describe](kn_revision_describe.md) - Show details of a revision * [kn revision list](kn_revision_list.md) - List revisions diff --git a/docs/cmd/kn_revision_delete.md b/docs/cmd/kn_revision_delete.md index 504747fb68..8f4776498b 100644 --- a/docs/cmd/kn_revision_delete.md +++ b/docs/cmd/kn_revision_delete.md @@ -1,13 +1,13 @@ ## kn revision delete -Delete a revision +Delete revisions ### Synopsis -Delete a revision +Delete revisions ``` -kn revision delete NAME +kn revision delete NAME [NAME ...] ``` ### Examples diff --git a/docs/cmd/kn_route.md b/docs/cmd/kn_route.md index 9a8f11e168..1e9e377568 100644 --- a/docs/cmd/kn_route.md +++ b/docs/cmd/kn_route.md @@ -1,10 +1,10 @@ ## kn route -List and show service routes +List and describe service routes ### Synopsis -List and show service routes +List and describe service routes ``` kn route diff --git a/docs/cmd/kn_route_describe.md b/docs/cmd/kn_route_describe.md index 946c468a71..dcfb3a5768 100644 --- a/docs/cmd/kn_route_describe.md +++ b/docs/cmd/kn_route_describe.md @@ -31,5 +31,5 @@ kn route describe NAME ### SEE ALSO -* [kn route](kn_route.md) - List and show service routes +* [kn route](kn_route.md) - List and describe service routes diff --git a/docs/cmd/kn_route_list.md b/docs/cmd/kn_route_list.md index b120f336fd..b5f62285a6 100644 --- a/docs/cmd/kn_route_list.md +++ b/docs/cmd/kn_route_list.md @@ -46,5 +46,5 @@ kn route list NAME ### SEE ALSO -* [kn route](kn_route.md) - List and show service routes +* [kn route](kn_route.md) - List and describe service routes diff --git a/docs/cmd/kn_service.md b/docs/cmd/kn_service.md index dc4f6f0519..7243d7e9dd 100644 --- a/docs/cmd/kn_service.md +++ b/docs/cmd/kn_service.md @@ -28,9 +28,9 @@ kn service * [kn](kn.md) - kn manages Knative Serving and Eventing resources * [kn service create](kn_service_create.md) - Create a service -* [kn service delete](kn_service_delete.md) - Delete a service +* [kn service delete](kn_service_delete.md) - Delete services * [kn service describe](kn_service_describe.md) - Show details of a service * [kn service export](kn_service_export.md) - Export a service and its revisions -* [kn service list](kn_service_list.md) - List available services +* [kn service list](kn_service_list.md) - List services * [kn service update](kn_service_update.md) - Update a service diff --git a/docs/cmd/kn_service_delete.md b/docs/cmd/kn_service_delete.md index c31fe4adeb..aa492868ed 100644 --- a/docs/cmd/kn_service_delete.md +++ b/docs/cmd/kn_service_delete.md @@ -1,13 +1,13 @@ ## kn service delete -Delete a service +Delete services ### Synopsis -Delete a service +Delete services ``` -kn service delete NAME +kn service delete NAME [NAME ...] ``` ### Examples diff --git a/docs/cmd/kn_service_list.md b/docs/cmd/kn_service_list.md index d9199e2c4c..70fdc12de5 100644 --- a/docs/cmd/kn_service_list.md +++ b/docs/cmd/kn_service_list.md @@ -1,10 +1,10 @@ ## kn service list -List available services +List services ### Synopsis -List available services +List services ``` kn service list diff --git a/docs/cmd/kn_source_apiserver.md b/docs/cmd/kn_source_apiserver.md index 78a285a6fb..8d3db4baf2 100644 --- a/docs/cmd/kn_source_apiserver.md +++ b/docs/cmd/kn_source_apiserver.md @@ -28,7 +28,7 @@ kn source apiserver COMMAND * [kn source](kn_source.md) - Manage event sources * [kn source apiserver create](kn_source_apiserver_create.md) - Create an api-server source -* [kn source apiserver delete](kn_source_apiserver_delete.md) - Delete api-server sources +* [kn source apiserver delete](kn_source_apiserver_delete.md) - Delete an api-server source * [kn source apiserver describe](kn_source_apiserver_describe.md) - Show details of an api-server source * [kn source apiserver list](kn_source_apiserver_list.md) - List api-server sources * [kn source apiserver update](kn_source_apiserver_update.md) - Update an api-server source diff --git a/docs/cmd/kn_source_apiserver_delete.md b/docs/cmd/kn_source_apiserver_delete.md index 4e9533c03c..2f3a69ff9a 100644 --- a/docs/cmd/kn_source_apiserver_delete.md +++ b/docs/cmd/kn_source_apiserver_delete.md @@ -1,10 +1,10 @@ ## kn source apiserver delete -Delete api-server sources +Delete an api-server source ### Synopsis -Delete api-server sources +Delete an api-server source ``` kn source apiserver delete NAME From 048aaf50d0f36312d1afba315f0f527274d47b46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Wed, 17 Jun 2020 17:35:38 +0200 Subject: [PATCH 18/20] chore: Update conventions doc --- conventions/cli.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/conventions/cli.md b/conventions/cli.md index 8b39ab76db..9148ae1146 100644 --- a/conventions/cli.md +++ b/conventions/cli.md @@ -51,6 +51,7 @@ be used: - `create` creates a resource. - `update` updates a resource. - `delete` deletes a resource. +- `apply` for an idempotent "create-or-update", much like `kubetl apply` For a given resource, create and update should use the same arguments as much as possible and where it makes sense. @@ -84,6 +85,7 @@ Flags are used for specifying the input for `kn` commands and can have different characteristics: - They can be _mandatory_ or _optional_ +- Mandatory flags are mentioned in the `Use` attribute of a command like in `service NAME --image IMAGE` for `ServiceCommand` - Optional flags can have _default values_ - Flag values can be _scalars_, _binary_, _lists_ or _maps_ (see below for details) From a30f9b41b6a0a1eb7c1682a26ebdf563efa239f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Thu, 18 Jun 2020 06:44:19 +0200 Subject: [PATCH 19/20] Move some direct configuration of rootcmd to NewRootCommand() --- pkg/kn/root/root.go | 10 ++++++++++ pkg/kn/root/root_test.go | 5 +++++ pkg/templates/command_groups.go | 6 ------ pkg/templates/command_groups_test.go | 8 +------- 4 files changed, 16 insertions(+), 13 deletions(-) diff --git a/pkg/kn/root/root.go b/pkg/kn/root/root.go index 2589b2a225..d738fb2b04 100644 --- a/pkg/kn/root/root.go +++ b/pkg/kn/root/root.go @@ -54,6 +54,11 @@ func NewRootCommand() (*cobra.Command, error) { // Disable docs header DisableAutoGenTag: true, + // Disable usage & error printing from cobra as we + // are handling all error output on our own + SilenceUsage: true, + SilenceErrors: true, + // Validate our boolean configs PersistentPreRunE: func(cmd *cobra.Command, args []string) error { return flags.ReconcileBoolFlags(cmd.Flags()) @@ -111,6 +116,11 @@ func NewRootCommand() (*cobra.Command, error) { return nil, err } + // Add some command context when flags can not be parsed + rootCmd.SetFlagErrorFunc(func(c *cobra.Command, err error) error { + return errors.Errorf("%s for '%s'", err.Error(), c.CommandPath()) + }) + // For glog parse error. TOO: Check why this is needed flag.CommandLine.Parse([]string{}) return rootCmd, nil diff --git a/pkg/kn/root/root_test.go b/pkg/kn/root/root_test.go index c2c6a1e0b6..7a32048628 100644 --- a/pkg/kn/root/root_test.go +++ b/pkg/kn/root/root_test.go @@ -15,6 +15,7 @@ package root import ( + "errors" "strings" "testing" @@ -43,6 +44,10 @@ func TestNewRootCommand(t *testing.T) { assert.Assert(t, rootCmd.PersistentFlags().Lookup("kubeconfig") != nil) assert.Assert(t, rootCmd.RunE == nil) + + fErrorFunc := rootCmd.FlagErrorFunc() + err = fErrorFunc(rootCmd, errors.New("test")) + assert.Equal(t, err.Error(), "test for 'kn'") } func TestSubCommands(t *testing.T) { diff --git a/pkg/templates/command_groups.go b/pkg/templates/command_groups.go index abac9d6e05..5866842379 100644 --- a/pkg/templates/command_groups.go +++ b/pkg/templates/command_groups.go @@ -15,7 +15,6 @@ package templates import ( - "github.com/pkg/errors" "github.com/spf13/cobra" ) @@ -47,11 +46,6 @@ func (g CommandGroups) SetRootUsage(rootCmd *cobra.Command) { CommandGroups: g, } setHelpFlagsToSubCommands(rootCmd) - rootCmd.SilenceUsage = true - rootCmd.SilenceErrors = true - rootCmd.SetFlagErrorFunc(func(c *cobra.Command, err error) error { - return errors.Errorf("%s for '%s'", err.Error(), c.CommandPath()) - }) rootCmd.SetUsageFunc(engine.usageFunc()) rootCmd.SetHelpFunc(engine.helpFunc()) } diff --git a/pkg/templates/command_groups_test.go b/pkg/templates/command_groups_test.go index 4e3cc02c7e..400d778513 100644 --- a/pkg/templates/command_groups_test.go +++ b/pkg/templates/command_groups_test.go @@ -15,7 +15,6 @@ package templates import ( - "errors" "fmt" "testing" @@ -54,14 +53,9 @@ func TestSetUsage(t *testing.T) { for _, cmd := range rootCmd.Commands() { assert.Assert(t, cmd.DisableFlagsInUseLine) } - assert.Assert(t, rootCmd.SilenceUsage) - assert.Assert(t, rootCmd.SilenceErrors) - fErrorFunc := rootCmd.FlagErrorFunc() - err := fErrorFunc(rootCmd, errors.New("test")) - assert.Equal(t, err.Error(), "test for 'root'") capture := commands.CaptureOutput(t) - err = (rootCmd.UsageFunc())(rootCmd) + err := (rootCmd.UsageFunc())(rootCmd) assert.NilError(t, err) stdOut, stdErr := capture.Close() assert.Equal(t, stdErr, "") From fdc970403df5316835e0cf0d84b7e44bd45fc355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Roland=20Hu=C3=9F?= Date: Thu, 18 Jun 2020 06:56:57 +0200 Subject: [PATCH 20/20] Moved CaptureOutput to "test" package for reuse --- cmd/kn/main_test.go | 6 +- lib/test/capture_output.go | 77 +++++++++++++++++++ pkg/kn/commands/completion/completion_test.go | 3 +- pkg/kn/commands/testing_helper.go | 43 ----------- pkg/kn/commands/testing_helper_test.go | 4 +- pkg/templates/command_groups_test.go | 6 +- pkg/templates/template_engine_test.go | 8 +- 7 files changed, 92 insertions(+), 55 deletions(-) create mode 100644 lib/test/capture_output.go diff --git a/cmd/kn/main_test.go b/cmd/kn/main_test.go index c41ba3cfec..278573788a 100644 --- a/cmd/kn/main_test.go +++ b/cmd/kn/main_test.go @@ -24,7 +24,7 @@ import ( "github.com/spf13/cobra" "gotest.tools/assert" - "knative.dev/client/pkg/kn/commands" + "knative.dev/client/lib/test" "knative.dev/client/pkg/kn/root" "knative.dev/client/pkg/util" ) @@ -243,7 +243,7 @@ func TestRunWithError(t *testing.T) { }, } for _, d := range data { - capture := commands.CaptureOutput(t) + capture := test.CaptureOutput(t) printError(errors.New(d.given)) stdOut, errOut := capture.Close() @@ -261,7 +261,7 @@ func TestRun(t *testing.T) { os.Args = oldArgs })() - capture := commands.CaptureOutput(t) + capture := test.CaptureOutput(t) err := run(os.Args[1:]) out, _ := capture.Close() diff --git a/lib/test/capture_output.go b/lib/test/capture_output.go new file mode 100644 index 0000000000..b70ba7dd42 --- /dev/null +++ b/lib/test/capture_output.go @@ -0,0 +1,77 @@ +// Copyright 2020 The Knative Authors + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// OutputCapture allows to capture any text written to standard out or standard error +// which is especially useful during testing. +// +// Call it like: +// +// capture := CaptureOutput(t) +// doSomeActionThatWritesToStdOutAndStdErr() +// stdOut, stdErr := capture.Close() +// +// CaptureOutpu() and capture.Close() should always come in pairs as Close() also +// restores the old streams +package test + +import ( + "io/ioutil" + "os" + "testing" + + "gotest.tools/assert" +) + +type OutputCapture struct { + outRead, outWrite *os.File + errorRead, errorWrite *os.File + t *testing.T + + oldStdout *os.File + oldStderr *os.File +} + +// CaptureOutput sets up standard our and standard error to capture any +// output which +func CaptureOutput(t *testing.T) OutputCapture { + ret := OutputCapture{ + oldStdout: os.Stdout, + oldStderr: os.Stderr, + t: t, + } + var err error + ret.outRead, ret.outWrite, err = os.Pipe() + assert.NilError(t, err) + os.Stdout = ret.outWrite + ret.errorRead, ret.errorWrite, err = os.Pipe() + assert.NilError(t, err) + os.Stderr = ret.errorWrite + return ret +} + +// Close return the output collected and restores the original standard out and error streams +// (i.e. those that were present before the call to CaptureOutput). +func (c OutputCapture) Close() (string, string) { + err := c.outWrite.Close() + assert.NilError(c.t, err) + err = c.errorWrite.Close() + assert.NilError(c.t, err) + outOutput, err := ioutil.ReadAll(c.outRead) + assert.NilError(c.t, err) + errOutput, err := ioutil.ReadAll(c.errorRead) + assert.NilError(c.t, err) + os.Stdout = c.oldStdout + os.Stderr = c.oldStderr + return string(outOutput), string(errOutput) +} diff --git a/pkg/kn/commands/completion/completion_test.go b/pkg/kn/commands/completion/completion_test.go index 7ca71708fb..122447b23c 100644 --- a/pkg/kn/commands/completion/completion_test.go +++ b/pkg/kn/commands/completion/completion_test.go @@ -17,6 +17,7 @@ package completion import ( "testing" + "knative.dev/client/lib/test" "knative.dev/client/pkg/kn/commands" "knative.dev/client/pkg/util" @@ -35,7 +36,7 @@ func TestCompletionUsage(t *testing.T) { func TestCompletionGeneration(t *testing.T) { for _, shell := range []string{"bash", "zsh"} { completionCmd := NewCompletionCommand(&commands.KnParams{}) - c := commands.CaptureOutput(t) + c := test.CaptureOutput(t) err := completionCmd.RunE(&cobra.Command{}, []string{shell}) assert.NilError(t, err) stdOut, stdErr := c.Close() diff --git a/pkg/kn/commands/testing_helper.go b/pkg/kn/commands/testing_helper.go index 4c8d2c76b9..5e8b36bce4 100644 --- a/pkg/kn/commands/testing_helper.go +++ b/pkg/kn/commands/testing_helper.go @@ -16,12 +16,9 @@ package commands import ( "bytes" - "io/ioutil" "os" - "testing" "github.com/spf13/cobra" - "gotest.tools/assert" "k8s.io/apimachinery/pkg/runtime" clienttesting "k8s.io/client-go/testing" servingv1fake "knative.dev/serving/pkg/client/clientset/versioned/typed/serving/v1/fake" @@ -93,46 +90,6 @@ func CreateDynamicTestKnCommand(cmd *cobra.Command, knParams *KnParams, objects } -type OutputCapture struct { - outRead, outWrite *os.File - errorRead, errorWrite *os.File - t *testing.T - - oldStdout *os.File - oldStderr *os.File -} - -func CaptureOutput(t *testing.T) OutputCapture { - ret := OutputCapture{ - oldStdout: os.Stdout, - oldStderr: os.Stderr, - t: t, - } - var err error - ret.outRead, ret.outWrite, err = os.Pipe() - assert.NilError(t, err) - os.Stdout = ret.outWrite - ret.errorRead, ret.errorWrite, err = os.Pipe() - assert.NilError(t, err) - os.Stderr = ret.errorWrite - return ret -} - -// CaptureOutput collects the current content of os.Stdout -func (c OutputCapture) Close() (string, string) { - err := c.outWrite.Close() - assert.NilError(c.t, err) - err = c.errorWrite.Close() - assert.NilError(c.t, err) - outOutput, err := ioutil.ReadAll(c.outRead) - assert.NilError(c.t, err) - errOutput, err := ioutil.ReadAll(c.errorRead) - assert.NilError(c.t, err) - os.Stdout = c.oldStdout - os.Stderr = c.oldStderr - return string(outOutput), string(errOutput) -} - // NewTestCommand can be used by tes func NewTestCommand(subCommand *cobra.Command, params *KnParams) *cobra.Command { rootCmd := &cobra.Command{ diff --git a/pkg/kn/commands/testing_helper_test.go b/pkg/kn/commands/testing_helper_test.go index fea84d3a78..b9b109b770 100644 --- a/pkg/kn/commands/testing_helper_test.go +++ b/pkg/kn/commands/testing_helper_test.go @@ -20,6 +20,8 @@ import ( "github.com/spf13/cobra" "gotest.tools/assert" + + "knative.dev/client/lib/test" ) func TestCreateTestKnCommand(t *testing.T) { @@ -56,7 +58,7 @@ func TestCreateDynamicTestKnCommand(t *testing.T) { } func TestCaptureStdout(t *testing.T) { - c := CaptureOutput(t) + c := test.CaptureOutput(t) fmt.Print("Hello World !") stdOut, stdErr := c.Close() assert.Equal(t, stdErr, "") diff --git a/pkg/templates/command_groups_test.go b/pkg/templates/command_groups_test.go index 400d778513..011241a447 100644 --- a/pkg/templates/command_groups_test.go +++ b/pkg/templates/command_groups_test.go @@ -21,7 +21,7 @@ import ( "github.com/spf13/cobra" "gotest.tools/assert" - "knative.dev/client/pkg/kn/commands" + "knative.dev/client/lib/test" "knative.dev/client/pkg/util" ) @@ -54,14 +54,14 @@ func TestSetUsage(t *testing.T) { assert.Assert(t, cmd.DisableFlagsInUseLine) } - capture := commands.CaptureOutput(t) + capture := test.CaptureOutput(t) err := (rootCmd.UsageFunc())(rootCmd) assert.NilError(t, err) stdOut, stdErr := capture.Close() assert.Equal(t, stdErr, "") assert.Assert(t, util.ContainsAll(stdOut, "header-1", "header-2")) - capture = commands.CaptureOutput(t) + capture = test.CaptureOutput(t) (rootCmd.HelpFunc())(rootCmd, nil) stdOut, stdErr = capture.Close() assert.Equal(t, stdErr, "") diff --git a/pkg/templates/template_engine_test.go b/pkg/templates/template_engine_test.go index b1ee05dfcc..2ce0b13c5d 100644 --- a/pkg/templates/template_engine_test.go +++ b/pkg/templates/template_engine_test.go @@ -23,7 +23,7 @@ import ( "github.com/spf13/cobra" "gotest.tools/assert" - "knative.dev/client/pkg/kn/commands" + "knative.dev/client/lib/test" "knative.dev/client/pkg/util" ) @@ -60,7 +60,7 @@ func TestUsageFunc(t *testing.T) { }, } for _, d := range data { - capture := commands.CaptureOutput(t) + capture := test.CaptureOutput(t) err := (engine.usageFunc())(d.cmd) assert.NilError(t, err) stdOut, stdErr := capture.Close() @@ -91,7 +91,7 @@ func TestHelpFunc(t *testing.T) { }, } for _, d := range data { - capture := commands.CaptureOutput(t) + capture := test.CaptureOutput(t) (engine.helpFunc())(d.cmd, []string{}) stdOut, stdErr := capture.Close() @@ -103,7 +103,7 @@ func TestHelpFunc(t *testing.T) { func TestOptionsFunc(t *testing.T) { rootCmd, _ := newTemplateEngine() subCmd := rootCmd.Commands()[0] - capture := commands.CaptureOutput(t) + capture := test.CaptureOutput(t) err := NewGlobalOptionsFunc()(subCmd) assert.NilError(t, err) stdOut, stdErr := capture.Close()