Repository: spf13/cobra
Pull request #1473 (2021-08-15 13:00:16)

completions: fix mixed tab/spaces indentation
These templates use 4 spaces for indentation, but some lines used tabs.


thaJeztah: @jpmcb  @Luap99 ptal
Luap99: @marckhouzam PTAL
I think we should setup some linter for the generated files.
thaJeztah: > I think we should setup some linter for the generated files.

Once support for Go 1.15 is dropped, these templates could potentially stored as separate files (go template?), and included using `//go:embed`, which would (potentially) make validation/linting easier.

Patch:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..cc5fa07
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,12 @@
+version: 2
+updates:
+- package-ecosystem: gomod
+  directory: /
+  schedule:
+    interval: weekly
+  open-pull-requests-limit: 99
+- package-ecosystem: github-actions
+  directory: /
+  schedule:
+    interval: weekly
+  open-pull-requests-limit: 99
diff --git a/README.md b/README.md
index 074e397..1ade108 100644
--- a/README.md
+++ b/README.md
@@ -11,28 +11,6 @@ name a few. [This list](./projects_using_cobra.md) contains a more extensive lis
 [![Go Report Card](https://goreportcard.com/badge/github.com/spf13/cobra)](https://goreportcard.com/report/github.com/spf13/cobra)
 [![Slack](https://img.shields.io/badge/Slack-cobra-brightgreen)](https://gophers.slack.com/archives/CD3LP1199)
 
-# Table of Contents
-
-- [Overview](#overview)
-- [Concepts](#concepts)
-  * [Commands](#commands)
-  * [Flags](#flags)
-- [Installing](#installing)
-- [Usage](#usage)
-  * [Using the Cobra Generator](user_guide.md#using-the-cobra-generator)
-  * [Using the Cobra Library](user_guide.md#using-the-cobra-library)
-  * [Working with Flags](user_guide.md#working-with-flags)
-  * [Positional and Custom Arguments](user_guide.md#positional-and-custom-arguments)
-  * [Example](user_guide.md#example)
-  * [Help Command](user_guide.md#help-command)
-  * [Usage Message](user_guide.md#usage-message)
-  * [PreRun and PostRun Hooks](user_guide.md#prerun-and-postrun-hooks)
-  * [Suggestions when "unknown command" happens](user_guide.md#suggestions-when-unknown-command-happens)
-  * [Generating documentation for your command](user_guide.md#generating-documentation-for-your-command)
-  * [Generating shell completions](user_guide.md#generating-shell-completions)
-- [Contributing](CONTRIBUTING.md)
-- [License](#license)
-
 # Overview
 
 Cobra is a library providing a simple interface to create powerful modern CLI
@@ -46,7 +24,7 @@ Cobra provides:
 * Fully POSIX-compliant flags (including short & long versions)
 * Nested subcommands
 * Global, local and cascading flags
-* Easy generation of applications & commands with `cobra init appname` & `cobra add cmdname`
+* Easy generation of applications & commands with `cobra init` & `cobra add cmdname`
 * Intelligent suggestions (`app srver`... did you mean `app server`?)
 * Automatic help generation for commands and flags
 * Automatic help flag recognition of `-h`, `--help`, etc.
@@ -54,7 +32,7 @@ Cobra provides:
 * Automatically generated man pages for your application
 * Command aliases so you can change things without breaking them
 * The flexibility to define your own help, usage, etc.
-* Optional tight integration with [viper](http://github.com/spf13/viper) for 12-factor apps
+* Optional seamless integration with [viper](http://github.com/spf13/viper) for 12-factor apps
 
 # Concepts
 
@@ -88,7 +66,7 @@ have children commands and optionally run an action.
 
 In the example above, 'server' is the command.
 
-[More about cobra.Command](https://godoc.org/github.com/spf13/cobra#Command)
+[More about cobra.Command](https://pkg.go.dev/github.com/spf13/cobra#Command)
 
 ## Flags
 
@@ -117,8 +95,12 @@ import "github.com/spf13/cobra"
 ```
 
 # Usage
+Cobra provides its own program that will create your application and add any
+commands you want. It's the easiest way to incorporate Cobra into your application.
+
+For complete details on using the Cobra generator, please read [The Cobra Generator README](https://github.com/spf13/cobra/blob/master/cobra/README.md)
 
-See [User Guide](user_guide.md).
+For complete details on using the Cobra library, please read the [The Cobra User Guide](user_guide.md).
 
 # License
 
diff --git a/args.go b/args.go
index 70e9b26..20a022b 100644
--- a/args.go
+++ b/args.go
@@ -107,3 +107,15 @@ func RangeArgs(min int, max int) PositionalArgs {
 		return nil
 	}
 }
+
+// MatchAll allows combining several PositionalArgs to work in concert.
+func MatchAll(pargs ...PositionalArgs) PositionalArgs {
+	return func(cmd *Command, args []string) error {
+		for _, parg := range pargs {
+			if err := parg(cmd, args); err != nil {
+				return err
+			}
+		}
+		return nil
+	}
+}
diff --git a/bash_completions.go b/bash_completions.go
index 733f4d1..6c360c5 100644
--- a/bash_completions.go
+++ b/bash_completions.go
@@ -24,7 +24,7 @@ func writePreamble(buf io.StringWriter, name string) {
 	WriteStringAndCheck(buf, fmt.Sprintf(`
 __%[1]s_debug()
 {
-    if [[ -n ${BASH_COMP_DEBUG_FILE} ]]; then
+    if [[ -n ${BASH_COMP_DEBUG_FILE:-} ]]; then
         echo "$*" >> "${BASH_COMP_DEBUG_FILE}"
     fi
 }
@@ -134,7 +134,7 @@ __%[1]s_handle_go_custom_completion()
         $filteringCmd
     elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
         # File completion for directories only
-        local subDir
+        local subdir
         # Use printf to strip any trailing newline
         subdir=$(printf "%%s" "${out[0]}")
         if [ -n "$subdir" ]; then
@@ -187,13 +187,19 @@ __%[1]s_handle_reply()
                     PREFIX=""
                     cur="${cur#*=}"
                     ${flags_completion[${index}]}
-                    if [ -n "${ZSH_VERSION}" ]; then
+                    if [ -n "${ZSH_VERSION:-}" ]; then
                         # zsh completion needs --flag= prefix
                         eval "COMPREPLY=( \"\${COMPREPLY[@]/#/${flag}=}\" )"
                     fi
                 fi
             fi
-            return 0;
+
+            if [[ -z "${flag_parsing_disabled}" ]]; then
+                # If flag parsing is enabled, we have completed the flags and can return.
+                # If flag parsing is disabled, we may not know all (or any) of the flags, so we fallthrough
+                # to possibly call handle_go_custom_completion.
+                return 0;
+            fi
             ;;
     esac
 
@@ -232,13 +238,13 @@ __%[1]s_handle_reply()
     fi
 
     if [[ ${#COMPREPLY[@]} -eq 0 ]]; then
-		if declare -F __%[1]s_custom_func >/dev/null; then
-			# try command name qualified custom func
-			__%[1]s_custom_func
-		else
-			# otherwise fall back to unqualified for compatibility
-			declare -F __custom_func >/dev/null && __custom_func
-		fi
+        if declare -F __%[1]s_custom_func >/dev/null; then
+            # try command name qualified custom func
+            __%[1]s_custom_func
+        else
+            # otherwise fall back to unqualified for compatibility
+            declare -F __custom_func >/dev/null && __custom_func
+        fi
     fi
 
     # available in bash-completion >= 2, not always present on macOS
@@ -272,7 +278,7 @@ __%[1]s_handle_flag()
 
     # if a command required a flag, and we found it, unset must_have_one_flag()
     local flagname=${words[c]}
-    local flagvalue
+    local flagvalue=""
     # if the word contained an =
     if [[ ${words[c]} == *"="* ]]; then
         flagvalue=${flagname#*=} # take in as flagvalue after the =
@@ -291,7 +297,7 @@ __%[1]s_handle_flag()
 
     # keep flag value with flagname as flaghash
     # flaghash variable is an associative array which is only supported in bash > 3.
-    if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
+    if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then
         if [ -n "${flagvalue}" ] ; then
             flaghash[${flagname}]=${flagvalue}
         elif [ -n "${words[ $((c+1)) ]}" ] ; then
@@ -303,7 +309,7 @@ __%[1]s_handle_flag()
 
     # skip the argument to a two word flag
     if [[ ${words[c]} != *"="* ]] && __%[1]s_contains_word "${words[c]}" "${two_word_flags[@]}"; then
-			  __%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument"
+        __%[1]s_debug "${FUNCNAME[0]}: found a flag ${words[c]}, skip the next argument"
         c=$((c+1))
         # if we are looking for a flags value, don't show commands
         if [[ $c -eq $cword ]]; then
@@ -363,7 +369,7 @@ __%[1]s_handle_word()
         __%[1]s_handle_command
     elif __%[1]s_contains_word "${words[c]}" "${command_aliases[@]}"; then
         # aliashash variable is an associative array which is only supported in bash > 3.
-        if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then
+        if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then
             words[c]=${aliashash[${words[c]}]}
             __%[1]s_handle_command
         else
@@ -394,6 +400,7 @@ func writePostscript(buf io.StringWriter, name string) {
     fi
 
     local c=0
+    local flag_parsing_disabled=
     local flags=()
     local two_word_flags=()
     local local_nonpersistent_flags=()
@@ -403,8 +410,8 @@ func writePostscript(buf io.StringWriter, name string) {
     local command_aliases=()
     local must_have_one_flag=()
     local must_have_one_noun=()
-    local has_completion_function
-    local last_command
+    local has_completion_function=""
+    local last_command=""
     local nouns=()
     local noun_aliases=()
 
@@ -535,6 +542,11 @@ func writeFlags(buf io.StringWriter, cmd *Command) {
     flags_completion=()
 
 `)
+
+	if cmd.DisableFlagParsing {
+		WriteStringAndCheck(buf, "    flag_parsing_disabled=1\n")
+	}
+
 	localNonPersistentFlags := cmd.LocalNonPersistentFlags()
 	cmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
 		if nonCompletableFlag(flag) {
@@ -609,7 +621,7 @@ func writeCmdAliases(buf io.StringWriter, cmd *Command) {
 
 	sort.Strings(cmd.Aliases)
 
-	WriteStringAndCheck(buf, fmt.Sprint(`    if [[ -z "${BASH_VERSION}" || "${BASH_VERSINFO[0]}" -gt 3 ]]; then`, "\n"))
+	WriteStringAndCheck(buf, fmt.Sprint(`    if [[ -z "${BASH_VERSION:-}" || "${BASH_VERSINFO[0]:-}" -gt 3 ]]; then`, "\n"))
 	for _, value := range cmd.Aliases {
 		WriteStringAndCheck(buf, fmt.Sprintf("        command_aliases+=(%q)\n", value))
 		WriteStringAndCheck(buf, fmt.Sprintf("        aliashash[%q]=%q\n", value, cmd.Name()))
diff --git a/cobra/README.md b/cobra/README.md
index dcaf0c5..f1a6056 100644
--- a/cobra/README.md
+++ b/cobra/README.md
@@ -3,41 +3,78 @@
 Cobra provides its own program that will create your application and add any
 commands you want. It's the easiest way to incorporate Cobra into your application.
 
-In order to use the cobra command, compile it using the following command:
+Install the cobra generator with the command `go install github.com/spf13/cobra/cobra`. 
+Go will automatically install it in your `$GOPATH/bin` directory which should be in your $PATH. 
 
-    go get github.com/spf13/cobra/cobra
+Once installed you should have the `cobra` command available. Confirm by typing `cobra` at a 
+command line. 
 
-This will create the cobra executable under your `$GOPATH/bin` directory.
+There are only two operations currently supported by the Cobra generator: 
 
 ### cobra init
 
 The `cobra init [app]` command will create your initial application code
 for you. It is a very powerful application that will populate your program with
-the right structure so you can immediately enjoy all the benefits of Cobra. It
-will also automatically apply the license you specify to your application.
+the right structure so you can immediately enjoy all the benefits of Cobra. 
+It can also apply the license you specify to your application.
 
-Cobra init is pretty smart. You can either run it in your current application directory
-or you can specify a relative path to an existing project. If the directory does not exist, it will be created for you.
+With the introduction of Go modules, the Cobra generator has been simplified to
+take advantage of modules. The Cobra generator works from within a Go module. 
 
-Updates to the Cobra generator have now decoupled it from the GOPATH.
-As such `--pkg-name` is required.
+#### Initalizing a module
 
-**Note:** init will no longer fail on non-empty directories.
+__If you already have a module, skip this step.__
 
+If you want to initialize a new Go module: 
+
+ 1. Create a new directory 
+ 2. `cd` into that directory
+ 3. run `go mod init <MODNAME>`
+
+e.g. 
 ```
-mkdir -p newApp && cd newApp
-cobra init --pkg-name github.com/spf13/newApp
+cd $HOME/code 
+mkdir myapp
+cd myapp
+go mod init github.com/spf13/myapp
 ```
 
-or
+#### Initalizing an Cobra CLI application
+
+From within a Go module run `cobra init`. This will create a new barebones project
+for you to edit. 
+
+You should be able to run your new application immediately. Try it with 
+`go run main.go`. 
+
+You will want to open up and edit 'cmd/root.go' and provide your own description and logic. 
 
+e.g.
 ```
-cobra init --pkg-name github.com/spf13/newApp path/to/newApp
+cd $HOME/code/myapp
+cobra init
+go run main.go
 ```
 
-### cobra add
+Cobra init can also be run from a subdirectory such as how the [cobra generator itself is organized](https://github.com/spf13/cobra).
+This is useful if you want to keep your application code separate from your library code.
+
+#### Optional flags:
+You can provide it your author name with the `--author` flag. 
+e.g. `cobra init --author "Steve Francia spf@spf13.com"`
+
+You can provide a license to use with `--license` 
+e.g. `cobra init --license apache`
+
+Use the `--viper` flag to automatically setup [viper](https://github.com/spf13/viper)
+
+Viper is a companion to Cobra intended to provide easy handling of environment variables and config files and seamlessly connecting them to the application flags.
+
+### Add commands to a project
+
+Once a cobra application is initialized you can continue to use the Cobra generator to 
+add additional commands to your application. The command to do this is `cobra add`. 
 
-Once an application is initialized, Cobra can create additional commands for you.
 Let's say you created an app and you wanted the following commands for it:
 
 * app serve
@@ -52,6 +89,14 @@ cobra add config
 cobra add create -p 'configCmd'
 ```
 
+`cobra add` supports all the same optional flags as `cobra init` does (described above).
+
+You'll notice that this final command has a `-p` flag. This is used to assign a
+parent command to the newly added command. In this case, we want to assign the
+"create" command to the "config" command. All commands have a default parent of rootCmd if not specified.  
+
+By default `cobra` will append `Cmd` to the name provided and uses this name for the internal variable name. When specifying a parent, be sure to match the variable name used in the code. 
+
 *Note: Use camelCase (not snake_case/kebab-case) for command names.
 Otherwise, you will encounter errors.
 For example, `cobra add add-user` is incorrect, but `cobra add addUser` is valid.*
@@ -62,9 +107,10 @@ the following:
 ```
   ▾ app/
     ▾ cmd/
-        serve.go
         config.go
         create.go
+        serve.go
+        root.go
       main.go
 ```
 
@@ -72,8 +118,11 @@ At this point you can run `go run main.go` and it would run your app. `go run
 main.go serve`, `go run main.go config`, `go run main.go config create` along
 with `go run main.go help serve`, etc. would all work.
 
-Obviously you haven't added your own code to these yet. The commands are ready
-for you to give them their tasks. Have fun!
+You now have a basic Cobra-based application up and running. Next step is to edit the files in cmd and customize them for your application.
+
+For complete details on using the Cobra library, please read the [The Cobra User Guide](https://github.com/spf13/cobra/blob/master/user_guide.md#using-the-cobra-library).
+
+Have fun!
 
 ### Configuring the cobra generator
 
@@ -86,6 +135,7 @@ An example ~/.cobra.yaml file:
 ```yaml
 author: Steve Francia <spf@spf13.com>
 license: MIT
+viper: true
 ```
 
 You can also use built-in licenses. For example, **GPLv2**, **GPLv3**, **LGPL**,
diff --git a/cobra/cmd/init.go b/cobra/cmd/init.go
index 8c0e617..dbdc25b 100644
--- a/cobra/cmd/init.go
+++ b/cobra/cmd/init.go
@@ -1,4 +1,4 @@
-// Copyright © 2015 Steve Francia <spf@spf13.com>.
+// Copyright © 2021 Steve Francia <spf@spf13.com>.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -14,42 +14,41 @@
 package cmd
 
 import (
+	"encoding/json"
 	"fmt"
 	"os"
+	"os/exec"
 	"path"
+	"path/filepath"
+	"strings"
 
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 )
 
 var (
-	pkgName string
-
 	initCmd = &cobra.Command{
-		Use:     "init [name]",
+		Use:     "init [path]",
 		Aliases: []string{"initialize", "initialise", "create"},
 		Short:   "Initialize a Cobra Application",
 		Long: `Initialize (cobra init) will create a new application, with a license
 and the appropriate structure for a Cobra-based CLI application.
 
-  * If a name is provided, a directory with that name will be created in the current directory;
-  * If no name is provided, the current directory will be assumed;
+Cobra init must be run inside of a go module (please run "go mod init <MODNAME>" first)
 `,
 
 		Run: func(_ *cobra.Command, args []string) {
-
 			projectPath, err := initializeProject(args)
 			cobra.CheckErr(err)
+			cobra.CheckErr(goGet("github.com/spf13/cobra"))
+			if viper.GetBool("useViper") {
+				cobra.CheckErr(goGet("github.com/spf13/viper"))
+			}
 			fmt.Printf("Your Cobra application is ready at\n%s\n", projectPath)
 		},
 	}
 )
 
-func init() {
-	initCmd.Flags().StringVar(&pkgName, "pkg-name", "", "fully qualified pkg name")
-	cobra.CheckErr(initCmd.MarkFlagRequired("pkg-name"))
-}
-
 func initializeProject(args []string) (string, error) {
 	wd, err := os.Getwd()
 	if err != nil {
@@ -62,13 +61,15 @@ func initializeProject(args []string) (string, error) {
 		}
 	}
 
+	modName := getModImportPath()
+
 	project := &Project{
 		AbsolutePath: wd,
-		PkgName:      pkgName,
+		PkgName:      modName,
 		Legal:        getLicense(),
 		Copyright:    copyrightLine(),
 		Viper:        viper.GetBool("useViper"),
-		AppName:      path.Base(pkgName),
+		AppName:      path.Base(modName),
 	}
 
 	if err := project.Create(); err != nil {
@@ -77,3 +78,51 @@ func initializeProject(args []string) (string, error) {
 
 	return project.AbsolutePath, nil
 }
+
+func getModImportPath() string {
+	mod, cd := parseModInfo()
+	return path.Join(mod.Path, fileToURL(strings.TrimPrefix(cd.Dir, mod.Dir)))
+}
+
+func fileToURL(in string) string {
+	i := strings.Split(in, string(filepath.Separator))
+	return path.Join(i...)
+}
+
+func parseModInfo() (Mod, CurDir) {
+	var mod Mod
+	var dir CurDir
+
+	m := modInfoJSON("-m")
+	cobra.CheckErr(json.Unmarshal(m, &mod))
+
+	// Unsure why, but if no module is present Path is set to this string.
+	if mod.Path == "command-line-arguments" {
+		cobra.CheckErr("Please run `go mod init <MODNAME>` before `cobra init`")
+	}
+
+	e := modInfoJSON("-e")
+	cobra.CheckErr(json.Unmarshal(e, &dir))
+
+	return mod, dir
+}
+
+type Mod struct {
+	Path, Dir, GoMod string
+}
+
+type CurDir struct {
+	Dir string
+}
+
+func goGet(mod string) error {
+	return exec.Command("go", "get", mod).Run()
+}
+
+func modInfoJSON(args ...string) []byte {
+	cmdArgs := append([]string{"list", "-json"}, args...)
+	out, err := exec.Command("go", cmdArgs...).Output()
+	cobra.CheckErr(err)
+
+	return out
+}
diff --git a/cobra/cmd/license_agpl.go b/cobra/cmd/license_agpl.go
index bc22e97..f6ec0af 100644
--- a/cobra/cmd/license_agpl.go
+++ b/cobra/cmd/license_agpl.go
@@ -3,7 +3,7 @@ package cmd
 func initAgpl() {
 	Licenses["agpl"] = License{
 		Name:            "GNU Affero General Public License",
-		PossibleMatches: []string{"agpl", "affero gpl", "gnu agpl"},
+		PossibleMatches: []string{"AGPL-3.0", "agpl", "affero gpl", "gnu agpl"},
 		Header: `
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Affero General Public License as published by
diff --git a/cobra/cmd/license_apache_2.go b/cobra/cmd/license_apache_2.go
index 38393d5..8c43e58 100644
--- a/cobra/cmd/license_apache_2.go
+++ b/cobra/cmd/license_apache_2.go
@@ -18,7 +18,7 @@ package cmd
 func initApache2() {
 	Licenses["apache"] = License{
 		Name:            "Apache 2.0",
-		PossibleMatches: []string{"apache", "apache20", "apache 2.0", "apache2.0", "apache-2.0"},
+		PossibleMatches: []string{"Apache-2.0", "apache", "apache20", "apache 2.0", "apache2.0", "apache-2.0"},
 		Header: `
 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/cobra/cmd/license_bsd_clause_2.go b/cobra/cmd/license_bsd_clause_2.go
index 4a847e0..797c82e 100644
--- a/cobra/cmd/license_bsd_clause_2.go
+++ b/cobra/cmd/license_bsd_clause_2.go
@@ -18,7 +18,7 @@ package cmd
 func initBsdClause2() {
 	Licenses["freebsd"] = License{
 		Name: "Simplified BSD License",
-		PossibleMatches: []string{"freebsd", "simpbsd", "simple bsd", "2-clause bsd",
+		PossibleMatches: []string{"BSD-2-Clause", "freebsd", "simpbsd", "simple bsd", "2-clause bsd",
 			"2 clause bsd", "simplified bsd license"},
 		Header: `All rights reserved.
 
diff --git a/cobra/cmd/license_bsd_clause_3.go b/cobra/cmd/license_bsd_clause_3.go
index c7476b3..5c795f3 100644
--- a/cobra/cmd/license_bsd_clause_3.go
+++ b/cobra/cmd/license_bsd_clause_3.go
@@ -18,7 +18,7 @@ package cmd
 func initBsdClause3() {
 	Licenses["bsd"] = License{
 		Name:            "NewBSD",
-		PossibleMatches: []string{"bsd", "newbsd", "3 clause bsd", "3-clause bsd"},
+		PossibleMatches: []string{"BSD-3-Clause", "bsd", "newbsd", "3 clause bsd", "3-clause bsd"},
 		Header: `All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
diff --git a/cobra/cmd/license_gpl_2.go b/cobra/cmd/license_gpl_2.go
index 03e05b3..b20dddb 100644
--- a/cobra/cmd/license_gpl_2.go
+++ b/cobra/cmd/license_gpl_2.go
@@ -18,7 +18,7 @@ package cmd
 func initGpl2() {
 	Licenses["gpl2"] = License{
 		Name:            "GNU General Public License 2.0",
-		PossibleMatches: []string{"gpl2", "gnu gpl2", "gplv2"},
+		PossibleMatches: []string{"GPL-2.0", "gpl2", "gnu gpl2", "gplv2"},
 		Header: `
 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
@@ -30,7 +30,7 @@ but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
-You should have received a copy of the GNU Lesser General Public License
+You should have received a copy of the GNU General Public License
 along with this program. If not, see <http://www.gnu.org/licenses/>.`,
 		Text: `                    GNU GENERAL PUBLIC LICENSE
                        Version 2, June 1991
diff --git a/cobra/cmd/license_gpl_3.go b/cobra/cmd/license_gpl_3.go
index ce07679..8f9063e 100644
--- a/cobra/cmd/license_gpl_3.go
+++ b/cobra/cmd/license_gpl_3.go
@@ -18,7 +18,7 @@ package cmd
 func initGpl3() {
 	Licenses["gpl3"] = License{
 		Name:            "GNU General Public License 3.0",
-		PossibleMatches: []string{"gpl3", "gplv3", "gpl", "gnu gpl3", "gnu gpl"},
+		PossibleMatches: []string{"GPL-3.0", "gpl3", "gplv3", "gpl", "gnu gpl3", "gnu gpl"},
 		Header: `
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
diff --git a/cobra/cmd/license_lgpl.go b/cobra/cmd/license_lgpl.go
index 0f8b96c..350b889 100644
--- a/cobra/cmd/license_lgpl.go
+++ b/cobra/cmd/license_lgpl.go
@@ -3,7 +3,7 @@ package cmd
 func initLgpl() {
 	Licenses["lgpl"] = License{
 		Name:            "GNU Lesser General Public License",
-		PossibleMatches: []string{"lgpl", "lesser gpl", "gnu lgpl"},
+		PossibleMatches: []string{"LGPL-3.0", "lgpl", "lesser gpl", "gnu lgpl"},
 		Header: `
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
diff --git a/cobra/cmd/license_mit.go b/cobra/cmd/license_mit.go
index bd2d0c4..62a865d 100644
--- a/cobra/cmd/license_mit.go
+++ b/cobra/cmd/license_mit.go
@@ -18,7 +18,7 @@ package cmd
 func initMit() {
 	Licenses["mit"] = License{
 		Name:            "MIT License",
-		PossibleMatches: []string{"mit"},
+		PossibleMatches: []string{"MIT", "mit"},
 		Header: `
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/cobra/cmd/licenses.go b/cobra/cmd/licenses.go
index 2b3a424..30c7b24 100644
--- a/cobra/cmd/licenses.go
+++ b/cobra/cmd/licenses.go
@@ -1,4 +1,4 @@
-// Copyright © 2015 Steve Francia <spf@spf13.com>.
+// Copyright © 2021 Steve Francia <spf@spf13.com>.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@ func init() {
 }
 
 // getLicense returns license specified by user in flag or in config.
-// If user didn't specify the license, it returns Apache License 2.0.
+// If user didn't specify the license, it returns none
 //
 // TODO: Inspect project for existing license
 func getLicense() License {
@@ -73,8 +73,8 @@ func getLicense() License {
 		return findLicense(viper.GetString("license"))
 	}
 
-	// If user didn't set any license, use Apache 2.0 by default.
-	return Licenses["apache"]
+	// If user didn't set any license, use none by default
+	return Licenses["none"]
 }
 
 func copyrightLine() string {
diff --git a/cobra/cmd/root.go b/cobra/cmd/root.go
index 350df10..51bba2c 100644
--- a/cobra/cmd/root.go
+++ b/cobra/cmd/root.go
@@ -1,4 +1,4 @@
-// Copyright © 2015 Steve Francia <spf@spf13.com>.
+// Copyright © 2021 Steve Francia <spf@spf13.com>.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -46,11 +46,11 @@ func init() {
 	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cobra.yaml)")
 	rootCmd.PersistentFlags().StringP("author", "a", "YOUR NAME", "author name for copyright attribution")
 	rootCmd.PersistentFlags().StringVarP(&userLicense, "license", "l", "", "name of license for the project")
-	rootCmd.PersistentFlags().Bool("viper", true, "use Viper for configuration")
+	rootCmd.PersistentFlags().Bool("viper", false, "use Viper for configuration")
 	cobra.CheckErr(viper.BindPFlag("author", rootCmd.PersistentFlags().Lookup("author")))
 	cobra.CheckErr(viper.BindPFlag("useViper", rootCmd.PersistentFlags().Lookup("viper")))
 	viper.SetDefault("author", "NAME HERE <EMAIL ADDRESS>")
-	viper.SetDefault("license", "apache")
+	viper.SetDefault("license", "none")
 
 	rootCmd.AddCommand(addCmd)
 	rootCmd.AddCommand(initCmd)
diff --git a/cobra/tpl/main.go b/cobra/tpl/main.go
index ed3a98e..d2f7742 100644
--- a/cobra/tpl/main.go
+++ b/cobra/tpl/main.go
@@ -1,3 +1,16 @@
+// Copyright © 2021 Steve Francia <spf@spf13.com>.
+//
+// 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 tpl
 
 func MainTemplate() []byte {
@@ -23,10 +36,12 @@ func RootTemplate() []byte {
 package cmd
 
 import (
+{{- if .Viper }}
 	"fmt"
 	"os"
+{{ end }}
 	"github.com/spf13/cobra"
-{{ if .Viper }}
+{{- if .Viper }}
 	"github.com/spf13/viper"{{ end }}
 )
 
diff --git a/command_notwin.go b/command_notwin.go
index 6159c1c..bb5dad9 100644
--- a/command_notwin.go
+++ b/command_notwin.go
@@ -1,3 +1,4 @@
+//go:build !windows
 // +build !windows
 
 package cobra
diff --git a/command_win.go b/command_win.go
index 8768b17..a84f5a8 100644
--- a/command_win.go
+++ b/command_win.go
@@ -1,3 +1,4 @@
+//go:build windows
 // +build windows
 
 package cobra
diff --git a/completions.go b/completions.go
index b849b9c..1ed871f 100644
--- a/completions.go
+++ b/completions.go
@@ -266,6 +266,12 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
 		}
 	}
 
+	// We only remove the flags from the arguments if DisableFlagParsing is not set.
+	// This is important for commands which have requested to do their own flag completion.
+	if !finalCmd.DisableFlagParsing {
+		finalArgs = finalCmd.Flags().Args()
+	}
+
 	if flag != nil && flagCompletion {
 		// Check if we are completing a flag value subject to annotations
 		if validExts, present := flag.Annotations[BashCompFilenameExt]; present {
@@ -290,12 +296,16 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
 		}
 	}
 
+	var completions []string
+	var directive ShellCompDirective
+
+	// Note that we want to perform flagname completion even if finalCmd.DisableFlagParsing==true;
+	// doing this allows for completion of persistant flag names even for commands that disable flag parsing.
+	//
 	// When doing completion of a flag name, as soon as an argument starts with
 	// a '-' we know it is a flag.  We cannot use isFlagArg() here as it requires
 	// the flag name to be complete
 	if flag == nil && len(toComplete) > 0 && toComplete[0] == '-' && !strings.Contains(toComplete, "=") && flagCompletion {
-		var completions []string
-
 		// First check for required flags
 		completions = completeRequireFlags(finalCmd, toComplete)
 
@@ -322,86 +332,86 @@ func (c *Command) getCompletions(args []string) (*Command, []string, ShellCompDi
 			})
 		}
 
-		directive := ShellCompDirectiveNoFileComp
+		directive = ShellCompDirectiveNoFileComp
 		if len(completions) == 1 && strings.HasSuffix(completions[0], "=") {
 			// If there is a single completion, the shell usually adds a space
 			// after the completion.  We don't want that if the flag ends with an =
 			directive = ShellCompDirectiveNoSpace
 		}
-		return finalCmd, completions, directive, nil
-	}
-
-	// We only remove the flags from the arguments if DisableFlagParsing is not set.
-	// This is important for commands which have requested to do their own flag completion.
-	if !finalCmd.DisableFlagParsing {
-		finalArgs = finalCmd.Flags().Args()
-	}
 
-	var completions []string
-	directive := ShellCompDirectiveDefault
-	if flag == nil {
-		foundLocalNonPersistentFlag := false
-		// If TraverseChildren is true on the root command we don't check for
-		// local flags because we can use a local flag on a parent command
-		if !finalCmd.Root().TraverseChildren {
-			// Check if there are any local, non-persistent flags on the command-line
-			localNonPersistentFlags := finalCmd.LocalNonPersistentFlags()
-			finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
-				if localNonPersistentFlags.Lookup(flag.Name) != nil && flag.Changed {
-					foundLocalNonPersistentFlag = true
-				}
-			})
+		if !finalCmd.DisableFlagParsing {
+			// If DisableFlagParsing==false, we have completed the flags as known by Cobra;
+			// we can return what we found.
+			// If DisableFlagParsing==true, Cobra may not be aware of all flags, so we
+			// let the logic continue to see if ValidArgsFunction needs to be called.
+			return finalCmd, completions, directive, nil
 		}
+	} else {
+		directive = ShellCompDirectiveDefault
+		if flag == nil {
+			foundLocalNonPersistentFlag := false
+			// If TraverseChildren is true on the root command we don't check for
+			// local flags because we can use a local flag on a parent command
+			if !finalCmd.Root().TraverseChildren {
+				// Check if there are any local, non-persistent flags on the command-line
+				localNonPersistentFlags := finalCmd.LocalNonPersistentFlags()
+				finalCmd.NonInheritedFlags().VisitAll(func(flag *pflag.Flag) {
+					if localNonPersistentFlags.Lookup(flag.Name) != nil && flag.Changed {
+						foundLocalNonPersistentFlag = true
+					}
+				})
+			}
 
-		// Complete subcommand names, including the help command
-		if len(finalArgs) == 0 && !foundLocalNonPersistentFlag {
-			// We only complete sub-commands if:
-			// - there are no arguments on the command-line and
-			// - there are no local, non-persistent flags on the command-line or TraverseChildren is true
-			for _, subCmd := range finalCmd.Commands() {
-				if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand {
-					if strings.HasPrefix(subCmd.Name(), toComplete) {
-						completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
+			// Complete subcommand names, including the help command
+			if len(finalArgs) == 0 && !foundLocalNonPersistentFlag {
+				// We only complete sub-commands if:
+				// - there are no arguments on the command-line and
+				// - there are no local, non-persistent flags on the command-line or TraverseChildren is true
+				for _, subCmd := range finalCmd.Commands() {
+					if subCmd.IsAvailableCommand() || subCmd == finalCmd.helpCommand {
+						if strings.HasPrefix(subCmd.Name(), toComplete) {
+							completions = append(completions, fmt.Sprintf("%s\t%s", subCmd.Name(), subCmd.Short))
+						}
+						directive = ShellCompDirectiveNoFileComp
 					}
-					directive = ShellCompDirectiveNoFileComp
 				}
 			}
-		}
 
-		// Complete required flags even without the '-' prefix
-		completions = append(completions, completeRequireFlags(finalCmd, toComplete)...)
-
-		// Always complete ValidArgs, even if we are completing a subcommand name.
-		// This is for commands that have both subcommands and ValidArgs.
-		if len(finalCmd.ValidArgs) > 0 {
-			if len(finalArgs) == 0 {
-				// ValidArgs are only for the first argument
-				for _, validArg := range finalCmd.ValidArgs {
-					if strings.HasPrefix(validArg, toComplete) {
-						completions = append(completions, validArg)
+			// Complete required flags even without the '-' prefix
+			completions = append(completions, completeRequireFlags(finalCmd, toComplete)...)
+
+			// Always complete ValidArgs, even if we are completing a subcommand name.
+			// This is for commands that have both subcommands and ValidArgs.
+			if len(finalCmd.ValidArgs) > 0 {
+				if len(finalArgs) == 0 {
+					// ValidArgs are only for the first argument
+					for _, validArg := range finalCmd.ValidArgs {
+						if strings.HasPrefix(validArg, toComplete) {
+							completions = append(completions, validArg)
+						}
 					}
-				}
-				directive = ShellCompDirectiveNoFileComp
-
-				// If no completions were found within commands or ValidArgs,
-				// see if there are any ArgAliases that should be completed.
-				if len(completions) == 0 {
-					for _, argAlias := range finalCmd.ArgAliases {
-						if strings.HasPrefix(argAlias, toComplete) {
-							completions = append(completions, argAlias)
+					directive = ShellCompDirectiveNoFileComp
+
+					// If no completions were found within commands or ValidArgs,
+					// see if there are any ArgAliases that should be completed.
+					if len(completions) == 0 {
+						for _, argAlias := range finalCmd.ArgAliases {
+							if strings.HasPrefix(argAlias, toComplete) {
+								completions = append(completions, argAlias)
+							}
 						}
 					}
 				}
+
+				// If there are ValidArgs specified (even if they don't match), we stop completion.
+				// Only one of ValidArgs or ValidArgsFunction can be used for a single command.
+				return finalCmd, completions, directive, nil
 			}
 
-			// If there are ValidArgs specified (even if they don't match), we stop completion.
-			// Only one of ValidArgs or ValidArgsFunction can be used for a single command.
-			return finalCmd, completions, directive, nil
+			// Let the logic continue so as to add any ValidArgsFunction completions,
+			// even if we already found sub-commands.
+			// This is for commands that have subcommands but also specify a ValidArgsFunction.
 		}
-
-		// Let the logic continue so as to add any ValidArgsFunction completions,
-		// even if we already found sub-commands.
-		// This is for commands that have subcommands but also specify a ValidArgsFunction.
 	}
 
 	// Find the completion function for the flag or command
@@ -589,9 +599,8 @@ func (c *Command) initDefaultCompletionCmd() {
 
 	completionCmd := &Command{
 		Use:   compCmdName,
-		Short: "generate the autocompletion script for the specified shell",
-		Long: fmt.Sprintf(`
-Generate the autocompletion script for %[1]s for the specified shell.
+		Short: "Generate the autocompletion script for the specified shell",
+		Long: fmt.Sprintf(`Generate the autocompletion script for %[1]s for the specified shell.
 See each sub-command's help for details on how to use the generated script.
 `, c.Root().Name()),
 		Args:              NoArgs,
@@ -601,24 +610,28 @@ See each sub-command's help for details on how to use the generated script.
 
 	out := c.OutOrStdout()
 	noDesc := c.CompletionOptions.DisableDescriptions
-	shortDesc := "generate the autocompletion script for %s"
+	shortDesc := "Generate the autocompletion script for %s"
 	bash := &Command{
 		Use:   "bash",
 		Short: fmt.Sprintf(shortDesc, "bash"),
-		Long: fmt.Sprintf(`
-Generate the autocompletion script for the bash shell.
+		Long: fmt.Sprintf(`Generate the autocompletion script for the bash shell.
 
 This script depends on the 'bash-completion' package.
 If it is not installed already, you can install it via your OS's package manager.
 
 To load completions in your current shell session:
-$ source <(%[1]s completion bash)
+
+	source <(%[1]s completion bash)
 
 To load completions for every new session, execute once:
-Linux:
-  $ %[1]s completion bash > /etc/bash_completion.d/%[1]s
-MacOS:
-  $ %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
+
+#### Linux:
+
+	%[1]s completion bash > /etc/bash_completion.d/%[1]s
+
+#### macOS:
+
+	%[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
 
 You will need to start a new shell for this setup to take effect.
   `, c.Root().Name()),
@@ -636,19 +649,22 @@ You will need to start a new shell for this setup to take effect.
 	zsh := &Command{
 		Use:   "zsh",
 		Short: fmt.Sprintf(shortDesc, "zsh"),
-		Long: fmt.Sprintf(`
-Generate the autocompletion script for the zsh shell.
+		Long: fmt.Sprintf(`Generate the autocompletion script for the zsh shell.
 
 If shell completion is not already enabled in your environment you will need
 to enable it.  You can execute the following once:
 
-$ echo "autoload -U compinit; compinit" >> ~/.zshrc
+	echo "autoload -U compinit; compinit" >> ~/.zshrc
 
 To load completions for every new session, execute once:
-# Linux:
-$ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
-# macOS:
-$ %[1]s completion zsh > /usr/local/share/zsh/site-functions/_%[1]s
+
+#### Linux:
+
+	%[1]s completion zsh > "${fpath[1]}/_%[1]s"
+
+#### macOS:
+
+	%[1]s completion zsh > /usr/local/share/zsh/site-functions/_%[1]s
 
 You will need to start a new shell for this setup to take effect.
 `, c.Root().Name()),
@@ -668,14 +684,15 @@ You will need to start a new shell for this setup to take effect.
 	fish := &Command{
 		Use:   "fish",
 		Short: fmt.Sprintf(shortDesc, "fish"),
-		Long: fmt.Sprintf(`
-Generate the autocompletion script for the fish shell.
+		Long: fmt.Sprintf(`Generate the autocompletion script for the fish shell.
 
 To load completions in your current shell session:
-$ %[1]s completion fish | source
+
+	%[1]s completion fish | source
 
 To load completions for every new session, execute once:
-$ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
+
+	%[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
 
 You will need to start a new shell for this setup to take effect.
 `, c.Root().Name()),
@@ -692,11 +709,11 @@ You will need to start a new shell for this setup to take effect.
 	powershell := &Command{
 		Use:   "powershell",
 		Short: fmt.Sprintf(shortDesc, "powershell"),
-		Long: fmt.Sprintf(`
-Generate the autocompletion script for powershell.
+		Long: fmt.Sprintf(`Generate the autocompletion script for powershell.
 
 To load completions in your current shell session:
-PS C:\> %[1]s completion powershell | Out-String | Invoke-Expression
+
+	%[1]s completion powershell | Out-String | Invoke-Expression
 
 To load completions for every new session, add the output of the above command
 to your powershell profile.
diff --git a/go.mod b/go.mod
index b4c870e..97eab3c 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/spf13/cobra
 
-go 1.14
+go 1.15
 
 require (
 	github.com/cpuguy83/go-md2man/v2 v2.0.1
diff --git a/powershell_completions.go b/powershell_completions.go
index 59234c0..7644649 100644
--- a/powershell_completions.go
+++ b/powershell_completions.go
@@ -50,7 +50,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
     if ($Command.Length -gt $CursorPosition) {
         $Command=$Command.Substring(0,$CursorPosition)
     }
-	__%[1]s_debug "Truncated command: $Command"
+    __%[1]s_debug "Truncated command: $Command"
 
     $ShellCompDirectiveError=%[3]d
     $ShellCompDirectiveNoSpace=%[4]d
@@ -58,7 +58,7 @@ Register-ArgumentCompleter -CommandName '%[1]s' -ScriptBlock {
     $ShellCompDirectiveFilterFileExt=%[6]d
     $ShellCompDirectiveFilterDirs=%[7]d
 
-	# Prepare the command to request completions for the program.
+    # Prepare the command to request completions for the program.
     # Split the command at the first space to separate the program and arguments.
     $Program,$Arguments = $Command.Split(" ",2)
     $RequestComp="$Program %[2]s $Arguments"
diff --git a/projects_using_cobra.md b/projects_using_cobra.md
index 62bdbff..8410c99 100644
--- a/projects_using_cobra.md
+++ b/projects_using_cobra.md
@@ -4,6 +4,7 @@
 - [Bleve](http://www.blevesearch.com/)
 - [CockroachDB](http://www.cockroachlabs.com/)
 - [Cosmos SDK](https://github.com/cosmos/cosmos-sdk)
+- [Datree](https://github.com/datreeio/datree)
 - [Delve](https://github.com/derekparker/delve)
 - [Docker (distribution)](https://github.com/docker/distribution)
 - [Etcd](https://etcd.io/)
@@ -14,26 +15,36 @@
 - [GitHub Labeler](https://github.com/erdaltsksn/gh-label)
 - [Golangci-lint](https://golangci-lint.run)
 - [GopherJS](http://www.gopherjs.org/)
+- [GoReleaser](https://goreleaser.com)
 - [Helm](https://helm.sh)
 - [Hugo](https://gohugo.io)
+- [Infracost](https://github.com/infracost/infracost)
 - [Istio](https://istio.io)
 - [Kool](https://github.com/kool-dev/kool)
 - [Kubernetes](http://kubernetes.io/)
 - [Linkerd](https://linkerd.io/)
 - [Mattermost-server](https://github.com/mattermost/mattermost-server)
+- [Mercure](https://mercure.rocks/)
 - [Meroxa CLI](https://github.com/meroxa/cli)
 - [Metal Stack CLI](https://github.com/metal-stack/metalctl)
 - [Moby (former Docker)](https://github.com/moby/moby)
+- [Moldy](https://github.com/Moldy-Community/moldy)
+- [Multi-gitter](https://github.com/lindell/multi-gitter)
 - [Nanobox](https://github.com/nanobox-io/nanobox)/[Nanopack](https://github.com/nanopack)
+- [nFPM](https://nfpm.goreleaser.com)
 - [OpenShift](https://www.openshift.com/)
 - [Ory Hydra](https://github.com/ory/hydra)
 - [Ory Kratos](https://github.com/ory/kratos)
 - [Pouch](https://github.com/alibaba/pouch)
 - [ProjectAtomic (enterprise)](http://www.projectatomic.io/)
 - [Prototool](https://github.com/uber/prototool)
+- [QRcp](https://github.com/claudiodangelis/qrcp)
 - [Random](https://github.com/erdaltsksn/random)
 - [Rclone](https://rclone.org/)
+- [Scaleway CLI](https://github.com/scaleway/scaleway-cli)
 - [Skaffold](https://skaffold.dev/)
 - [Tendermint](https://github.com/tendermint/tendermint)
 - [Twitch CLI](https://github.com/twitchdev/twitch-cli)
+- [UpCloud CLI (`upctl`)](https://github.com/UpCloudLtd/upcloud-cli)
+- VMware's [Tanzu Community Edition](https://github.com/vmware-tanzu/community-edition) & [Tanzu Framework](https://github.com/vmware-tanzu/tanzu-framework)
 - [Werf](https://werf.io/)
diff --git a/shell_completions.md b/shell_completions.md
index 4ba06a1..03add86 100644
--- a/shell_completions.md
+++ b/shell_completions.md
@@ -28,17 +28,17 @@ and then modifying the generated `cmd/completion.go` file to look something like
 var completionCmd = &cobra.Command{
 	Use:   "completion [bash|zsh|fish|powershell]",
 	Short: "Generate completion script",
-	Long: `To load completions:
+	Long: fmt.Sprintf(`To load completions:
 
 Bash:
 
-  $ source <(yourprogram completion bash)
+  $ source <(%[1]s completion bash)
 
   # To load completions for each session, execute once:
   # Linux:
-  $ yourprogram completion bash > /etc/bash_completion.d/yourprogram
+  $ %[1]s completion bash > /etc/bash_completion.d/%[1]s
   # macOS:
-  $ yourprogram completion bash > /usr/local/etc/bash_completion.d/yourprogram
+  $ %[1]s completion bash > /usr/local/etc/bash_completion.d/%[1]s
 
 Zsh:
 
@@ -48,25 +48,25 @@ Zsh:
   $ echo "autoload -U compinit; compinit" >> ~/.zshrc
 
   # To load completions for each session, execute once:
-  $ yourprogram completion zsh > "${fpath[1]}/_yourprogram"
+  $ %[1]s completion zsh > "${fpath[1]}/_%[1]s"
 
   # You will need to start a new shell for this setup to take effect.
 
 fish:
 
-  $ yourprogram completion fish | source
+  $ %[1]s completion fish | source
 
   # To load completions for each session, execute once:
-  $ yourprogram completion fish > ~/.config/fish/completions/yourprogram.fish
+  $ %[1]s completion fish > ~/.config/fish/completions/%[1]s.fish
 
 PowerShell:
 
-  PS> yourprogram completion powershell | Out-String | Invoke-Expression
+  PS> %[1]s completion powershell | Out-String | Invoke-Expression
 
   # To load completions for every new session, run:
-  PS> yourprogram completion powershell > yourprogram.ps1
+  PS> %[1]s completion powershell > %[1]s.ps1
   # and source this file from your PowerShell profile.
-`,
+`,cmd.Root().Name()),
 	DisableFlagsInUseLine: true,
 	ValidArgs:             []string{"bash", "zsh", "fish", "powershell"},
 	Args:                  cobra.ExactValidArgs(1),
diff --git a/user_guide.md b/user_guide.md
index 311abce..e87cdf2 100644
--- a/user_guide.md
+++ b/user_guide.md
@@ -32,7 +32,7 @@ func main() {
 Cobra provides its own program that will create your application and add any
 commands you want. It's the easiest way to incorporate Cobra into your application.
 
-[Here](https://github.com/spf13/cobra/blob/master/cobra/README.md) you can find more information about it.
+For complete details on using the Cobra generator, please read [The Cobra Generator README](https://github.com/spf13/cobra/blob/master/cobra/README.md)
 
 ## Using the Cobra Library
 
@@ -281,7 +281,7 @@ func init() {
 
 In this example, the persistent flag `author` is bound with `viper`.
 **Note**: the variable `author` will not be set to the value from config,
-when the `--author` flag is not provided by user.
+when the `--author` flag is provided by user.
 
 More in [viper documentation](https://github.com/spf13/viper#working-with-flags).
 
@@ -315,6 +315,7 @@ The following validators are built in:
 - `ExactArgs(int)` - the command will report an error if there are not exactly N positional args.
 - `ExactValidArgs(int)` - the command will report an error if there are not exactly N positional args OR if there are any positional args that are not in the `ValidArgs` field of `Command`
 - `RangeArgs(min, max)` - the command will report an error if the number of args is not between the minimum and maximum number of expected args.
+- `MatchAll(pargs ...PositionalArgs)` - enables combining existing checks with arbitrary other checks (e.g. you want to check the ExactArgs length along with other qualities).
 
 An example of setting the custom validator:
 
diff --git a/zsh_completions.go b/zsh_completions.go
index 1afec30..624adab 100644
--- a/zsh_completions.go
+++ b/zsh_completions.go
@@ -202,7 +202,7 @@ _%[1]s()
         _arguments '*:filename:'"$filteringCmd"
     elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then
         # File completion for directories only
-        local subDir
+        local subdir
         subdir="${completions[1]}"
         if [ -n "$subdir" ]; then
             __%[1]s_debug "Listing directories in $subdir"
@@ -250,7 +250,7 @@ _%[1]s()
 
 # don't run the completion function when being source-ed or eval-ed
 if [ "$funcstack[1]" = "_%[1]s" ]; then
-	_%[1]s
+    _%[1]s
 fi
 `, name, compCmd,
 		ShellCompDirectiveError, ShellCompDirectiveNoSpace, ShellCompDirectiveNoFileComp,


Test patch:
diff --git a/.github/workflows/Test.yml b/.github/workflows/Test.yml
index c34c2fb..bc74803 100644
--- a/.github/workflows/Test.yml
+++ b/.github/workflows/Test.yml
@@ -18,29 +18,35 @@ jobs:
         - ubuntu
         - macOS
         go:
-        - 1.14.x
-        - 1.15.x
-    name: '${{ matrix.platform }} | ${{ matrix.go }}'
+        - 14
+        - 15
+        - 16
+        - 17
+    name: '${{ matrix.platform }} | 1.${{ matrix.go }}.x'
     runs-on: ${{ matrix.platform }}-latest
     steps:
 
     - uses: actions/setup-go@v2
       with:
-        go-version: ${{ matrix.go }}
+        go-version: 1.${{ matrix.go }}.x
 
     - uses: actions/checkout@v2
 
     - uses: actions/cache@v2
       with:
         path: ~/go/pkg/mod
-        key: ${{ runner.os }}-${{ matrix.go }}-${{ hashFiles('**/go.sum') }}
-        restore-keys: ${{ runner.os }}-${{ matrix.go }}-
+        key: ${{ runner.os }}-1.${{ matrix.go }}.x-${{ hashFiles('**/go.sum') }}
+        restore-keys: ${{ runner.os }}-1.${{ matrix.go }}.x-
 
     - run: |
         export GOBIN=$HOME/go/bin
         curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | bash -s -- -b $GOBIN latest
-        go install github.com/kyoh86/richgo
-        go install github.com/mitchellh/gox
+        case "${{ matrix.go }}" in
+          16|17) _version='@latest';;
+          *) _version='';;
+        esac
+        go install github.com/kyoh86/richgo"${_version}"
+        go install github.com/mitchellh/gox"${_version}"
 
     - run: PATH=$HOME/go/bin/:$PATH make
 
diff --git a/args_test.go b/args_test.go
index c81b212..ded3d0d 100644
--- a/args_test.go
+++ b/args_test.go
@@ -1,30 +1,47 @@
 package cobra
 
 import (
+	"fmt"
 	"strings"
 	"testing"
 )
 
-func TestNoArgs(t *testing.T) {
-	c := &Command{Use: "c", Args: NoArgs, Run: emptyRun}
+func getCommand(args PositionalArgs, withValid bool) *Command {
+	c := &Command{
+		Use:  "c",
+		Args: args,
+		Run:  emptyRun,
+	}
+	if withValid {
+		c.ValidArgs = []string{"one", "two", "three"}
+	}
+	return c
+}
 
-	output, err := executeCommand(c)
+func expectSuccess(output string, err error, t *testing.T) {
 	if output != "" {
-		t.Errorf("Unexpected string: %v", output)
+		t.Errorf("Unexpected output: %v", output)
 	}
 	if err != nil {
 		t.Fatalf("Unexpected error: %v", err)
 	}
 }
 
-func TestNoArgsWithArgs(t *testing.T) {
-	c := &Command{Use: "c", Args: NoArgs, Run: emptyRun}
-
-	_, err := executeCommand(c, "illegal")
+func validWithInvalidArgs(err error, t *testing.T) {
 	if err == nil {
 		t.Fatal("Expected an error")
 	}
+	got := err.Error()
+	expected := `invalid argument "a" for "c"`
+	if got != expected {
+		t.Errorf("Expected: %q, got: %q", expected, got)
+	}
+}
 
+func noArgsWithArgs(err error, t *testing.T) {
+	if err == nil {
+		t.Fatal("Expected an error")
+	}
 	got := err.Error()
 	expected := `unknown command "illegal" for "c"`
 	if got != expected {
@@ -32,202 +49,144 @@ func TestNoArgsWithArgs(t *testing.T) {
 	}
 }
 
-func TestOnlyValidArgs(t *testing.T) {
-	c := &Command{
-		Use:       "c",
-		Args:      OnlyValidArgs,
-		ValidArgs: []string{"one", "two"},
-		Run:       emptyRun,
+func minimumNArgsWithLessArgs(err error, t *testing.T) {
+	if err == nil {
+		t.Fatal("Expected an error")
 	}
+	got := err.Error()
+	expected := "requires at least 2 arg(s), only received 1"
+	if got != expected {
+		t.Fatalf("Expected %q, got %q", expected, got)
+	}
+}
 
-	output, err := executeCommand(c, "one", "two")
-	if output != "" {
-		t.Errorf("Unexpected output: %v", output)
+func maximumNArgsWithMoreArgs(err error, t *testing.T) {
+	if err == nil {
+		t.Fatal("Expected an error")
 	}
-	if err != nil {
-		t.Fatalf("Unexpected error: %v", err)
+	got := err.Error()
+	expected := "accepts at most 2 arg(s), received 3"
+	if got != expected {
+		t.Fatalf("Expected %q, got %q", expected, got)
 	}
 }
 
-func TestOnlyValidArgsWithInvalidArgs(t *testing.T) {
-	c := &Command{
-		Use:       "c",
-		Args:      OnlyValidArgs,
-		ValidArgs: []string{"one", "two"},
-		Run:       emptyRun,
+func exactArgsWithInvalidCount(err error, t *testing.T) {
+	if err == nil {
+		t.Fatal("Expected an error")
 	}
+	got := err.Error()
+	expected := "accepts 2 arg(s), received 3"
+	if got != expected {
+		t.Fatalf("Expected %q, got %q", expected, got)
+	}
+}
 
-	_, err := executeCommand(c, "three")
+func rangeArgsWithInvalidCount(err error, t *testing.T) {
 	if err == nil {
 		t.Fatal("Expected an error")
 	}
-
 	got := err.Error()
-	expected := `invalid argument "three" for "c"`
+	expected := "accepts between 2 and 4 arg(s), received 1"
 	if got != expected {
-		t.Errorf("Expected: %q, got: %q", expected, got)
+		t.Fatalf("Expected %q, got %q", expected, got)
 	}
 }
 
+func TestNoArgs(t *testing.T) {
+	c := getCommand(NoArgs, false)
+	output, err := executeCommand(c)
+	expectSuccess(output, err, t)
+}
+
+func TestNoArgsWithArgs(t *testing.T) {
+	c := getCommand(NoArgs, false)
+	_, err := executeCommand(c, "illegal")
+	noArgsWithArgs(err, t)
+}
+
+func TestOnlyValidArgs(t *testing.T) {
+	c := getCommand(OnlyValidArgs, true)
+	output, err := executeCommand(c, "one", "two")
+	expectSuccess(output, err, t)
+}
+
+func TestOnlyValidArgsWithInvalidArgs(t *testing.T) {
+	c := getCommand(OnlyValidArgs, true)
+	_, err := executeCommand(c, "a")
+	validWithInvalidArgs(err, t)
+}
+
 func TestArbitraryArgs(t *testing.T) {
-	c := &Command{Use: "c", Args: ArbitraryArgs, Run: emptyRun}
+	c := getCommand(ArbitraryArgs, false)
 	output, err := executeCommand(c, "a", "b")
-	if output != "" {
-		t.Errorf("Unexpected output: %v", output)
-	}
-	if err != nil {
-		t.Errorf("Unexpected error: %v", err)
-	}
+	expectSuccess(output, err, t)
 }
 
 func TestMinimumNArgs(t *testing.T) {
-	c := &Command{Use: "c", Args: MinimumNArgs(2), Run: emptyRun}
+	c := getCommand(MinimumNArgs(2), false)
 	output, err := executeCommand(c, "a", "b", "c")
-	if output != "" {
-		t.Errorf("Unexpected output: %v", output)
-	}
-	if err != nil {
-		t.Errorf("Unexpected error: %v", err)
-	}
+	expectSuccess(output, err, t)
 }
 
 func TestMinimumNArgsWithLessArgs(t *testing.T) {
-	c := &Command{Use: "c", Args: MinimumNArgs(2), Run: emptyRun}
+	c := getCommand(MinimumNArgs(2), false)
 	_, err := executeCommand(c, "a")
-
-	if err == nil {
-		t.Fatal("Expected an error")
-	}
-
-	got := err.Error()
-	expected := "requires at least 2 arg(s), only received 1"
-	if got != expected {
-		t.Fatalf("Expected %q, got %q", expected, got)
-	}
+	minimumNArgsWithLessArgs(err, t)
 }
 
 func TestMaximumNArgs(t *testing.T) {
-	c := &Command{Use: "c", Args: MaximumNArgs(3), Run: emptyRun}
+	c := getCommand(MaximumNArgs(3), false)
 	output, err := executeCommand(c, "a", "b")
-	if output != "" {
-		t.Errorf("Unexpected output: %v", output)
-	}
-	if err != nil {
-		t.Errorf("Unexpected error: %v", err)
-	}
+	expectSuccess(output, err, t)
 }
 
 func TestMaximumNArgsWithMoreArgs(t *testing.T) {
-	c := &Command{Use: "c", Args: MaximumNArgs(2), Run: emptyRun}
+	c := getCommand(MaximumNArgs(2), false)
 	_, err := executeCommand(c, "a", "b", "c")
-
-	if err == nil {
-		t.Fatal("Expected an error")
-	}
-
-	got := err.Error()
-	expected := "accepts at most 2 arg(s), received 3"
-	if got != expected {
-		t.Fatalf("Expected %q, got %q", expected, got)
-	}
+	maximumNArgsWithMoreArgs(err, t)
 }
 
 func TestExactArgs(t *testing.T) {
-	c := &Command{Use: "c", Args: ExactArgs(3), Run: emptyRun}
+	c := getCommand(ExactArgs(3), false)
 	output, err := executeCommand(c, "a", "b", "c")
-	if output != "" {
-		t.Errorf("Unexpected output: %v", output)
-	}
-	if err != nil {
-		t.Errorf("Unexpected error: %v", err)
-	}
+	expectSuccess(output, err, t)
 }
 
 func TestExactArgsWithInvalidCount(t *testing.T) {
-	c := &Command{Use: "c", Args: ExactArgs(2), Run: emptyRun}
+	c := getCommand(ExactArgs(2), false)
 	_, err := executeCommand(c, "a", "b", "c")
-
-	if err == nil {
-		t.Fatal("Expected an error")
-	}
-
-	got := err.Error()
-	expected := "accepts 2 arg(s), received 3"
-	if got != expected {
-		t.Fatalf("Expected %q, got %q", expected, got)
-	}
+	exactArgsWithInvalidCount(err, t)
 }
 
 func TestExactValidArgs(t *testing.T) {
-	c := &Command{Use: "c", Args: ExactValidArgs(3), ValidArgs: []string{"a", "b", "c"}, Run: emptyRun}
-	output, err := executeCommand(c, "a", "b", "c")
-	if output != "" {
-		t.Errorf("Unexpected output: %v", output)
-	}
-	if err != nil {
-		t.Errorf("Unexpected error: %v", err)
-	}
+	c := getCommand(ExactValidArgs(3), true)
+	output, err := executeCommand(c, "three", "one", "two")
+	expectSuccess(output, err, t)
 }
 
 func TestExactValidArgsWithInvalidCount(t *testing.T) {
-	c := &Command{Use: "c", Args: ExactValidArgs(2), Run: emptyRun}
-	_, err := executeCommand(c, "a", "b", "c")
-
-	if err == nil {
-		t.Fatal("Expected an error")
-	}
-
-	got := err.Error()
-	expected := "accepts 2 arg(s), received 3"
-	if got != expected {
-		t.Fatalf("Expected %q, got %q", expected, got)
-	}
+	c := getCommand(ExactValidArgs(2), false)
+	_, err := executeCommand(c, "three", "one", "two")
+	exactArgsWithInvalidCount(err, t)
 }
 
 func TestExactValidArgsWithInvalidArgs(t *testing.T) {
-	c := &Command{
-		Use:       "c",
-		Args:      ExactValidArgs(1),
-		ValidArgs: []string{"one", "two"},
-		Run:       emptyRun,
-	}
-
-	_, err := executeCommand(c, "three")
-	if err == nil {
-		t.Fatal("Expected an error")
-	}
-
-	got := err.Error()
-	expected := `invalid argument "three" for "c"`
-	if got != expected {
-		t.Errorf("Expected: %q, got: %q", expected, got)
-	}
+	c := getCommand(ExactValidArgs(3), true)
+	_, err := executeCommand(c, "three", "a", "two")
+	validWithInvalidArgs(err, t)
 }
 
 func TestRangeArgs(t *testing.T) {
-	c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun}
+	c := getCommand(RangeArgs(2, 4), false)
 	output, err := executeCommand(c, "a", "b", "c")
-	if output != "" {
-		t.Errorf("Unexpected output: %v", output)
-	}
-	if err != nil {
-		t.Errorf("Unexpected error: %v", err)
-	}
+	expectSuccess(output, err, t)
 }
 
 func TestRangeArgsWithInvalidCount(t *testing.T) {
-	c := &Command{Use: "c", Args: RangeArgs(2, 4), Run: emptyRun}
+	c := getCommand(RangeArgs(2, 4), false)
 	_, err := executeCommand(c, "a")
-
-	if err == nil {
-		t.Fatal("Expected an error")
-	}
-
-	got := err.Error()
-	expected := "accepts between 2 and 4 arg(s), received 1"
-	if got != expected {
-		t.Fatalf("Expected %q, got %q", expected, got)
-	}
+	rangeArgsWithInvalidCount(err, t)
 }
 
 func TestRootTakesNoArgs(t *testing.T) {
@@ -285,3 +244,51 @@ func TestChildTakesArgs(t *testing.T) {
 		t.Fatalf("Unexpected error: %v", err)
 	}
 }
+
+func TestMatchAll(t *testing.T) {
+	// Somewhat contrived example check that ensures there are exactly 3
+	// arguments, and each argument is exactly 2 bytes long.
+	pargs := MatchAll(
+		ExactArgs(3),
+		func(cmd *Command, args []string) error {
+			for _, arg := range args {
+				if len([]byte(arg)) != 2 {
+					return fmt.Errorf("expected to be exactly 2 bytes long")
+				}
+			}
+			return nil
+		},
+	)
+
+	testCases := map[string]struct {
+		args []string
+		fail bool
+	}{
+		"happy path": {
+			[]string{"aa", "bb", "cc"},
+			false,
+		},
+		"incorrect number of args": {
+			[]string{"aa", "bb", "cc", "dd"},
+			true,
+		},
+		"incorrect number of bytes in one arg": {
+			[]string{"aa", "bb", "abc"},
+			true,
+		},
+	}
+
+	rootCmd := &Command{Use: "root", Args: pargs, Run: emptyRun}
+
+	for name, tc := range testCases {
+		t.Run(name, func(t *testing.T) {
+			_, err := executeCommand(rootCmd, tc.args...)
+			if err != nil && !tc.fail {
+				t.Errorf("unexpected: %v\n", err)
+			}
+			if err == nil && tc.fail {
+				t.Errorf("expected error")
+			}
+		})
+	}
+}
diff --git a/cobra/cmd/add_test.go b/cobra/cmd/add_test.go
index 0b32ca6..20bc34f 100644
--- a/cobra/cmd/add_test.go
+++ b/cobra/cmd/add_test.go
@@ -4,9 +4,13 @@ import (
 	"fmt"
 	"os"
 	"testing"
+
+	"github.com/spf13/viper"
 )
 
 func TestGoldenAddCmd(t *testing.T) {
+	viper.Set("useViper", true)
+	viper.Set("license", "apache")
 	command := &Command{
 		CmdName:   "test",
 		CmdParent: parentName,
diff --git a/cobra/cmd/golden_test.go b/cobra/cmd/golden_test.go
index 99b92e3..832ea53 100644
--- a/cobra/cmd/golden_test.go
+++ b/cobra/cmd/golden_test.go
@@ -43,7 +43,7 @@ func compareFiles(pathA, pathB string) error {
 			// Don't execute diff if it can't be found.
 			return nil
 		}
-		diffCmd := exec.Command(diffPath, "-u", pathA, pathB)
+		diffCmd := exec.Command(diffPath, "-u", "--strip-trailing-cr", pathA, pathB)
 		diffCmd.Stdout = output
 		diffCmd.Stderr = output
 
diff --git a/cobra/cmd/init_test.go b/cobra/cmd/init_test.go
index e364f40..930313c 100644
--- a/cobra/cmd/init_test.go
+++ b/cobra/cmd/init_test.go
@@ -16,8 +16,8 @@ func getProject() *Project {
 		AbsolutePath: fmt.Sprintf("%s/testproject", wd),
 		Legal:        getLicense(),
 		Copyright:    copyrightLine(),
-		AppName:      "testproject",
-		PkgName:      "github.com/spf13/testproject",
+		AppName:      "cmd",
+		PkgName:      "github.com/spf13/cobra/cobra/cmd/cmd",
 		Viper:        true,
 	}
 }
@@ -37,30 +37,18 @@ func TestGoldenInitCmd(t *testing.T) {
 		expectErr bool
 	}{
 		{
-			name:      "successfully creates a project with name",
+			name:      "successfully creates a project based on module",
 			args:      []string{"testproject"},
 			pkgName:   "github.com/spf13/testproject",
 			expectErr: false,
 		},
-		{
-			name:      "returns error when passing an absolute path for project",
-			args:      []string{dir},
-			pkgName:   "github.com/spf13/testproject",
-			expectErr: true,
-		},
-		{
-			name:      "returns error when passing a relative path for project",
-			args:      []string{"github.com/spf13/testproject"},
-			pkgName:   "github.com/spf13/testproject",
-			expectErr: true,
-		},
 	}
 
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 
-			assertNoErr(t, initCmd.Flags().Set("pkg-name", tt.pkgName))
 			viper.Set("useViper", true)
+			viper.Set("license", "apache")
 			projectPath, err := initializeProject(tt.args)
 			defer func() {
 				if projectPath != "" {
diff --git a/cobra/cmd/testdata/main.go.golden b/cobra/cmd/testdata/main.go.golden
index f69d34a..0af77e1 100644
--- a/cobra/cmd/testdata/main.go.golden
+++ b/cobra/cmd/testdata/main.go.golden
@@ -15,7 +15,7 @@ limitations under the License.
 */
 package main
 
-import "github.com/spf13/testproject/cmd"
+import "github.com/spf13/cobra/cobra/cmd/cmd"
 
 func main() {
 	cmd.Execute()
diff --git a/cobra/cmd/testdata/root.go.golden b/cobra/cmd/testdata/root.go.golden
index 32c1529..2adeaea 100644
--- a/cobra/cmd/testdata/root.go.golden
+++ b/cobra/cmd/testdata/root.go.golden
@@ -18,8 +18,8 @@ package cmd
 import (
 	"fmt"
 	"os"
-	"github.com/spf13/cobra"
 
+	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 )
 
@@ -27,7 +27,7 @@ var cfgFile string
 
 // rootCmd represents the base command when called without any subcommands
 var rootCmd = &cobra.Command{
-	Use:   "testproject",
+	Use:   "cmd",
 	Short: "A brief description of your application",
 	Long: `A longer description that spans multiple lines and likely contains
 examples and usage of using your application. For example:
@@ -53,7 +53,7 @@ func init() {
 	// Cobra supports persistent flags, which, if defined here,
 	// will be global for your application.
 
-	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.testproject.yaml)")
+	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.cmd.yaml)")
 
 	// Cobra also supports local flags, which will only run
 	// when this action is called directly.
@@ -70,10 +70,10 @@ func initConfig() {
 		home, err := os.UserHomeDir()
 		cobra.CheckErr(err)
 
-		// Search config in home directory with name ".testproject" (without extension).
+		// Search config in home directory with name ".cmd" (without extension).
 		viper.AddConfigPath(home)
 		viper.SetConfigType("yaml")
-		viper.SetConfigName(".testproject")
+		viper.SetConfigName(".cmd")
 	}
 
 	viper.AutomaticEnv() // read in environment variables that match
diff --git a/completions_test.go b/completions_test.go
index 70c455a..48f1730 100644
--- a/completions_test.go
+++ b/completions_test.go
@@ -125,7 +125,7 @@ func TestCmdNameCompletionInGo(t *testing.T) {
 
 	expected = strings.Join([]string{
 		"aliased\tA command with aliases",
-		"completion\tgenerate the autocompletion script for the specified shell",
+		"completion\tGenerate the autocompletion script for the specified shell",
 		"firstChild\tFirst command",
 		"help\tHelp about any command",
 		"secondChild",
@@ -580,7 +580,7 @@ func TestFlagNameCompletionInGoWithDesc(t *testing.T) {
 
 	expected := strings.Join([]string{
 		"childCmd\tfirst command",
-		"completion\tgenerate the autocompletion script for the specified shell",
+		"completion\tGenerate the autocompletion script for the specified shell",
 		"help\tHelp about any command",
 		":4",
 		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
@@ -2543,3 +2543,64 @@ func TestMultipleShorthandFlagCompletion(t *testing.T) {
 		t.Errorf("expected: %q, got: %q", expected, output)
 	}
 }
+
+func TestCompleteWithDisableFlagParsing(t *testing.T) {
+
+	flagValidArgs := func(cmd *Command, args []string, toComplete string) ([]string, ShellCompDirective) {
+		return []string{"--flag", "-f"}, ShellCompDirectiveNoFileComp
+	}
+
+	rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun}
+	childCmd := &Command{
+		Use:                "child",
+		Run:                emptyRun,
+		DisableFlagParsing: true,
+		ValidArgsFunction:  flagValidArgs,
+	}
+	rootCmd.AddCommand(childCmd)
+
+	rootCmd.PersistentFlags().StringP("persistent", "p", "", "persistent flag")
+	childCmd.Flags().StringP("nonPersistent", "n", "", "non-persistent flag")
+
+	// Test that when DisableFlagParsing==true, ValidArgsFunction is called to complete flag names,
+	// after Cobra tried to complete the flags it knows about.
+	childCmd.DisableFlagParsing = true
+	output, err := executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child", "-")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	expected := strings.Join([]string{
+		"--persistent",
+		"-p",
+		"--nonPersistent",
+		"-n",
+		"--flag",
+		"-f",
+		":4",
+		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+
+	// Test that when DisableFlagParsing==false, Cobra completes the flags itself and ValidArgsFunction is not called
+	childCmd.DisableFlagParsing = false
+	output, err = executeCommand(rootCmd, ShellCompNoDescRequestCmd, "child", "-")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	// Cobra was not told of any flags, so it returns nothing
+	expected = strings.Join([]string{
+		"--persistent",
+		"-p",
+		"--nonPersistent",
+		"-n",
+		":4",
+		"Completion ended with directive: ShellCompDirectiveNoFileComp", ""}, "\n")
+
+	if output != expected {
+		t.Errorf("expected: %q, got: %q", expected, output)
+	}
+}