Repository: spf13/cobra (go)

Issue:
Short --version flag (-v/--version)
I know `--version` was implemented originally in #584 and later fixed in #595 .

Can we have the option to have a short flag in addition to the long flag?

I would like (*for consistency's sake*):

```#!bash
mycli -v
```

and:

```#!bash
mycli --version
```

Thanks!

Pull request:
Add short version flag -v when not otherwise set
Fixes #654 by adding a `-v` shorthand to the automatically-added `version` flag.

- It will not add the shorthand if another `-v` shorthand is already set
- It will not add the shorthand if another `--version` flag is already set

Signed-off-by: Dave Henderson <dhenderson@gmail.com>

Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
deleted file mode 100644
index 8194464..0000000
--- a/.circleci/config.yml
+++ /dev/null
@@ -1,53 +0,0 @@
-version: 2
-
-references:
-  workspace: &workspace
-    /go/src/github.com/spf13/cobra
-
-  run_tests: &run_tests
-    run:
-      name: "All Commands"
-      command: |
-        mkdir -p bin
-        curl -Lso bin/shellcheck https://github.com/caarlos0/shellcheck-docker/releases/download/v0.4.6/shellcheck
-        chmod +x bin/shellcheck
-        go get -t -v ./...
-        PATH=$PATH:$PWD/bin go test -v ./...
-        go build
-        if [ -z $NOVET ]; then
-          diff -u <(echo -n) <(go vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint');
-        fi
-
-jobs:
-  go-current:
-    docker:
-      - image: circleci/golang:1.12
-    working_directory: *workspace
-    steps:
-      - checkout
-      - *run_tests
-      - run:
-          name: "Check formatting"
-          command: diff -u <(echo -n) <(gofmt -d -s .)
-  go-previous:
-    docker:
-      - image: circleci/golang:1.11
-    working_directory: *workspace
-    steps:
-      - checkout
-      - *run_tests
-  go-latest:
-    docker:
-      - image: circleci/golang:latest
-    working_directory: *workspace
-    steps:
-      - checkout
-      - *run_tests
-
-workflows:
-  version: 2
-  main:
-    jobs:
-      - go-current
-      - go-previous
-      - go-latest
diff --git a/.gitignore b/.gitignore
index b2b848e..c7b459e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -32,8 +32,8 @@ Session.vim
 tags
 
 *.exe
-cobra
 cobra.test
+bin
 
 .idea/
 *.iml
diff --git a/.travis.yml b/.travis.yml
index fca1e69..a9bd4e5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,26 +3,27 @@ language: go
 stages:
   - diff
   - test
+  - build
 
 go:
-  - 1.10.x
-  - 1.11.x
   - 1.12.x
+  - 1.13.x
   - tip
 
+before_install:
+  - go get -u github.com/kyoh86/richgo
+  - go get -u github.com/mitchellh/gox
+
 matrix:
   allow_failures:
     - go: tip
   include:
     - stage: diff
-      go: 1.12.x
-      script: diff -u <(echo -n) <(gofmt -d -s .)
-
-before_install: go get -u github.com/kyoh86/richgo
+      go: 1.13.x
+      script: make fmt
+    - stage: build
+      go: 1.13.x
+      script: make cobra_generator
 
-script:
-  - richgo test -v ./...
-  - go build
-  - if [ -z $NOVET ]; then
-      diff -u <(echo -n) <(go vet . 2>&1 | grep -vE 'ExampleCommand|bash_completions.*Fprint');
-    fi
+script: 
+ - make test
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e9740d1
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,36 @@
+BIN="./bin"
+SRC=$(shell find . -name "*.go")
+
+ifeq (, $(shell which richgo))
+$(warning "could not find richgo in $(PATH), run: go get github.com/kyoh86/richgo")
+endif
+
+.PHONY: fmt vet test cobra_generator install_deps clean
+
+default: all
+
+all: fmt vet test cobra_generator	
+
+fmt:
+	$(info ******************** checking formatting ********************)
+	@test -z $(shell gofmt -l $(SRC)) || (gofmt -d $(SRC); exit 1)
+
+test: install_deps vet
+	$(info ******************** running tests ********************)
+	richgo test -v ./...
+
+cobra_generator: install_deps
+	$(info ******************** building generator ********************)
+	mkdir -p $(BIN)
+	make -C cobra all
+
+install_deps:
+	$(info ******************** downloading dependencies ********************)
+	go get -v ./...
+
+vet:
+	$(info ******************** vetting ********************)
+	go vet ./...
+
+clean:
+	rm -rf $(BIN)
diff --git a/README.md b/README.md
index 834f287..2f8175b 100644
--- a/README.md
+++ b/README.md
@@ -214,6 +214,7 @@ package cmd
 
 import (
 	"fmt"
+	"os"
 
 	homedir "github.com/mitchellh/go-homedir"
 	"github.com/spf13/cobra"
@@ -255,6 +256,11 @@ func init() {
 	rootCmd.AddCommand(initCmd)
 }
 
+func er(msg interface{}) {
+	fmt.Println("Error:", msg)
+	os.Exit(1)
+}
+
 func initConfig() {
 	if cfgFile != "" {
 		// Use config file from the flag.
diff --git a/bash_completions.go b/bash_completions.go
index 03ddda2..1e0e25c 100644
--- a/bash_completions.go
+++ b/bash_completions.go
@@ -61,6 +61,7 @@ __%[1]s_contains_word()
 __%[1]s_handle_reply()
 {
     __%[1]s_debug "${FUNCNAME[0]}"
+    local comp
     case $cur in
         -*)
             if [[ $(type -t compopt) = "builtin" ]]; then
@@ -72,8 +73,8 @@ __%[1]s_handle_reply()
             else
                 allflags=("${flags[*]} ${two_word_flags[*]}")
             fi
-            while IFS='' read -r c; do
-                COMPREPLY+=("$c")
+            while IFS='' read -r comp; do
+                COMPREPLY+=("$comp")
             done < <(compgen -W "${allflags[*]}" -- "$cur")
             if [[ $(type -t compopt) = "builtin" ]]; then
                 [[ "${COMPREPLY[0]}" == *= ]] || compopt +o nospace
@@ -124,13 +125,13 @@ __%[1]s_handle_reply()
     if [[ ${#must_have_one_flag[@]} -ne 0 ]]; then
         completions+=("${must_have_one_flag[@]}")
     fi
-    while IFS='' read -r c; do
-        COMPREPLY+=("$c")
+    while IFS='' read -r comp; do
+        COMPREPLY+=("$comp")
     done < <(compgen -W "${completions[*]}" -- "$cur")
 
     if [[ ${#COMPREPLY[@]} -eq 0 && ${#noun_aliases[@]} -gt 0 && ${#must_have_one_noun[@]} -ne 0 ]]; then
-        while IFS='' read -r c; do
-            COMPREPLY+=("$c")
+        while IFS='' read -r comp; do
+            COMPREPLY+=("$comp")
         done < <(compgen -W "${noun_aliases[*]}" -- "$cur")
     fi
 
diff --git a/cobra/Makefile b/cobra/Makefile
new file mode 100644
index 0000000..4995000
--- /dev/null
+++ b/cobra/Makefile
@@ -0,0 +1,23 @@
+XC_OS="linux darwin"
+XC_ARCH="amd64"
+XC_PARALLEL="2"
+BIN="../bin"
+SRC=$(shell find . -name "*.go")
+
+ifeq (, $(shell which gox))
+$(warning "could not find gox in $(PATH), run: go get github.com/mitchellh/gox")
+endif
+
+.PHONY: all build
+
+default: all
+
+all: build
+
+build:
+	gox \
+		-os=$(XC_OS) \
+		-arch=$(XC_ARCH) \
+		-parallel=$(XC_PARALLEL) \
+		-output=$(BIN)/{{.Dir}}_{{.OS}}_{{.Arch}} \
+		;
diff --git a/cobra/tpl/main.go b/cobra/tpl/main.go
index 5e5a0fa..4348e56 100644
--- a/cobra/tpl/main.go
+++ b/cobra/tpl/main.go
@@ -10,7 +10,7 @@ package main
 import "{{ .PkgName }}/cmd"
 
 func main() {
-  cmd.Execute()
+	cmd.Execute()
 }
 `)
 }
@@ -23,88 +23,87 @@ func RootTemplate() []byte {
 package cmd
 
 import (
-  "fmt"
-  "os"
-  "github.com/spf13/cobra"
+	"fmt"
+	"github.com/spf13/cobra"
+	"os"
 {{ if .Viper }}
-  homedir "github.com/mitchellh/go-homedir"
-  "github.com/spf13/viper"
-{{ end }}
+	homedir "github.com/mitchellh/go-homedir"
+	"github.com/spf13/viper"
+{{ end -}}
 )
 
-{{ if .Viper }}
+{{ if .Viper -}}
 var cfgFile string
-{{ end }}
+{{- end }}
 
 // rootCmd represents the base command when called without any subcommands
 var rootCmd = &cobra.Command{
-  Use:   "{{ .AppName }}",
-  Short: "A brief description of your application",
-  Long: ` + "`" + `A longer description that spans multiple lines and likely contains
+	Use:   "{{ .AppName }}",
+	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:
 
 Cobra is a CLI library for Go that empowers applications.
 This application is a tool to generate the needed files
 to quickly create a Cobra application.` + "`" + `,
-  // Uncomment the following line if your bare application
-  // has an action associated with it:
-  //	Run: func(cmd *cobra.Command, args []string) { },
+	// Uncomment the following line if your bare application
+	// has an action associated with it:
+	//	Run: func(cmd *cobra.Command, args []string) { },
 }
 
 // Execute adds all child commands to the root command and sets flags appropriately.
 // This is called by main.main(). It only needs to happen once to the rootCmd.
 func Execute() {
-  if err := rootCmd.Execute(); err != nil {
-    fmt.Println(err)
-    os.Exit(1)
-  }
+	if err := rootCmd.Execute(); err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
 }
 
 func init() {
 {{- if .Viper }}
-  cobra.OnInitialize(initConfig)
+	cobra.OnInitialize(initConfig)
 {{ end }}
-  // Here you will define your flags and configuration settings.
-  // Cobra supports persistent flags, which, if defined here,
-  // will be global for your application.
+	// Here you will define your flags and configuration settings.
+	// Cobra supports persistent flags, which, if defined here,
+	// will be global for your application.
 {{ if .Viper }}
-  rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)")
+	rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)")
 {{ else }}
-  // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)")
+	// rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.{{ .AppName }}.yaml)")
 {{ end }}
-
-  // Cobra also supports local flags, which will only run
-  // when this action is called directly.
-  rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+	// Cobra also supports local flags, which will only run
+	// when this action is called directly.
+	rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
 }
 
-{{ if .Viper }}
+{{ if .Viper -}}
 // initConfig reads in config file and ENV variables if set.
 func initConfig() {
-  if cfgFile != "" {
-    // Use config file from the flag.
-    viper.SetConfigFile(cfgFile)
-  } else {
-    // Find home directory.
-    home, err := homedir.Dir()
-    if err != nil {
-      fmt.Println(err)
-      os.Exit(1)
-    }
-
-    // Search config in home directory with name ".{{ .AppName }}" (without extension).
-    viper.AddConfigPath(home)
-    viper.SetConfigName(".{{ .AppName }}")
-  }
-
-  viper.AutomaticEnv() // read in environment variables that match
-
-  // If a config file is found, read it in.
-  if err := viper.ReadInConfig(); err == nil {
-    fmt.Println("Using config file:", viper.ConfigFileUsed())
-  }
+	if cfgFile != "" {
+		// Use config file from the flag.
+		viper.SetConfigFile(cfgFile)
+	} else {
+		// Find home directory.
+		home, err := homedir.Dir()
+		if err != nil {
+			fmt.Println(err)
+			os.Exit(1)
+		}
+
+		// Search config in home directory with name ".{{ .AppName }}" (without extension).
+		viper.AddConfigPath(home)
+		viper.SetConfigName(".{{ .AppName }}")
+	}
+
+	viper.AutomaticEnv() // read in environment variables that match
+
+	// If a config file is found, read it in.
+	if err := viper.ReadInConfig(); err == nil {
+		fmt.Println("Using config file:", viper.ConfigFileUsed())
+	}
 }
-{{ end }}
+{{- end }}
 `)
 }
 
diff --git a/command.go b/command.go
index 42e500d..55ddc50 100644
--- a/command.go
+++ b/command.go
@@ -17,6 +17,7 @@ package cobra
 
 import (
 	"bytes"
+	"context"
 	"errors"
 	"fmt"
 	"io"
@@ -83,7 +84,8 @@ type Command struct {
 
 	// Version defines the version for this command. If this value is non-empty and the command does not
 	// define a "version" flag, a "version" boolean flag will be added to the command and, if specified,
-	// will print content of the "Version" variable.
+	// will print content of the "Version" variable. A shorthand "v" flag will also be added if the
+	// command does not define one.
 	Version string
 
 	// The *Run functions are executed in the following order:
@@ -143,9 +145,11 @@ type Command struct {
 	// TraverseChildren parses flags on all parents before executing child command.
 	TraverseChildren bool
 
-	//FParseErrWhitelist flag parse errors to be ignored
+	// FParseErrWhitelist flag parse errors to be ignored
 	FParseErrWhitelist FParseErrWhitelist
 
+	ctx context.Context
+
 	// commands is the list of commands supported by this program.
 	commands []*Command
 	// parent is a parent command for this command.
@@ -205,6 +209,12 @@ type Command struct {
 	errWriter io.Writer
 }
 
+// Context returns underlying command context. If command wasn't
+// executed with ExecuteContext Context returns Background context.
+func (c *Command) Context() context.Context {
+	return c.ctx
+}
+
 // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
 // particularly useful when testing.
 func (c *Command) SetArgs(a []string) {
@@ -300,7 +310,7 @@ func (c *Command) ErrOrStderr() io.Writer {
 	return c.getErr(os.Stderr)
 }
 
-// InOrStdin returns output to stderr
+// InOrStdin returns input to stdin
 func (c *Command) InOrStdin() io.Reader {
 	return c.getIn(os.Stdin)
 }
@@ -372,7 +382,9 @@ func (c *Command) HelpFunc() func(*Command, []string) {
 	}
 	return func(c *Command, a []string) {
 		c.mergePersistentFlags()
-		err := tmpl(c.OutOrStderr(), c.HelpTemplate(), c)
+		// The help should be sent to stdout
+		// See https://github.com/spf13/cobra/issues/1002
+		err := tmpl(c.OutOrStdout(), c.HelpTemplate(), c)
 		if err != nil {
 			c.Println(err)
 		}
@@ -860,6 +872,13 @@ func (c *Command) preRun() {
 	}
 }
 
+// ExecuteContext is the same as Execute(), but sets the ctx on the command.
+// Retrieve ctx by calling cmd.Context() inside your *Run lifecycle functions.
+func (c *Command) ExecuteContext(ctx context.Context) error {
+	c.ctx = ctx
+	return c.Execute()
+}
+
 // Execute uses the args (os.Args[1:] by default)
 // and run through the command tree finding appropriate matches
 // for commands and then corresponding flags.
@@ -870,6 +889,10 @@ func (c *Command) Execute() error {
 
 // ExecuteC executes the command.
 func (c *Command) ExecuteC() (cmd *Command, err error) {
+	if c.ctx == nil {
+		c.ctx = context.Background()
+	}
+
 	// Regardless of what command execute is called on, run on Root only
 	if c.HasParent() {
 		return c.Root().ExecuteC()
@@ -914,6 +937,12 @@ func (c *Command) ExecuteC() (cmd *Command, err error) {
 		cmd.commandCalledAs.name = cmd.Name()
 	}
 
+	// We have to pass global context to children command
+	// if context is present on the parent command.
+	if cmd.ctx == nil {
+		cmd.ctx = c.ctx
+	}
+
 	err = cmd.execute(flags)
 	if err != nil {
 		// Always show help if requested, even if SilenceErrors is in
@@ -1005,7 +1034,11 @@ func (c *Command) InitDefaultVersionFlag() {
 		} else {
 			usage += c.Name()
 		}
-		c.Flags().Bool("version", false, usage)
+		if c.Flags().ShorthandLookup("v") == nil {
+			c.Flags().BoolP("version", "v", false, usage)
+		} else {
+			c.Flags().Bool("version", false, usage)
+		}
 	}
 }
 
@@ -1558,7 +1591,7 @@ func (c *Command) ParseFlags(args []string) error {
 	beforeErrorBufLen := c.flagErrorBuf.Len()
 	c.mergePersistentFlags()
 
-	//do it here after merging all flags and just before parse
+	// do it here after merging all flags and just before parse
 	c.Flags().ParseErrorsWhitelist = flag.ParseErrorsWhitelist(c.FParseErrWhitelist)
 
 	err := c.Flags().Parse(args)
diff --git a/doc/md_docs.md b/doc/md_docs.md
index 56ce9fe..5c87062 100644
--- a/doc/md_docs.md
+++ b/doc/md_docs.md
@@ -1,6 +1,6 @@
 # Generating Markdown Docs For Your Own cobra.Command
 
-Generating man pages from a cobra command is incredibly easy. An example is as follows:
+Generating Markdown pages from a cobra command is incredibly easy. An example is as follows:
 
 ```go
 package main


Test patch:
diff --git a/cobra/cmd/testdata/main.go.golden b/cobra/cmd/testdata/main.go.golden
index 4ad570c..0bf75c5 100644
--- a/cobra/cmd/testdata/main.go.golden
+++ b/cobra/cmd/testdata/main.go.golden
@@ -1,5 +1,5 @@
 /*
-Copyright © 2019 NAME HERE <EMAIL ADDRESS>
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -18,5 +18,5 @@ package main
 import "github.com/spf13/testproject/cmd"
 
 func main() {
-  cmd.Execute()
+	cmd.Execute()
 }
diff --git a/cobra/cmd/testdata/root.go.golden b/cobra/cmd/testdata/root.go.golden
index d3b889b..1db829c 100644
--- a/cobra/cmd/testdata/root.go.golden
+++ b/cobra/cmd/testdata/root.go.golden
@@ -1,5 +1,5 @@
 /*
-Copyright © 2019 NAME HERE <EMAIL ADDRESS>
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
 
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
@@ -16,82 +16,76 @@ limitations under the License.
 package cmd
 
 import (
-  "fmt"
-  "os"
-  "github.com/spf13/cobra"
-
-  homedir "github.com/mitchellh/go-homedir"
-  "github.com/spf13/viper"
+	"fmt"
+	"github.com/spf13/cobra"
+	"os"
 
+	homedir "github.com/mitchellh/go-homedir"
+	"github.com/spf13/viper"
 )
 
-
 var cfgFile string
 
-
 // rootCmd represents the base command when called without any subcommands
 var rootCmd = &cobra.Command{
-  Use:   "testproject",
-  Short: "A brief description of your application",
-  Long: `A longer description that spans multiple lines and likely contains
+	Use:   "testproject",
+	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:
 
 Cobra is a CLI library for Go that empowers applications.
 This application is a tool to generate the needed files
 to quickly create a Cobra application.`,
-  // Uncomment the following line if your bare application
-  // has an action associated with it:
-  //	Run: func(cmd *cobra.Command, args []string) { },
+	// Uncomment the following line if your bare application
+	// has an action associated with it:
+	//	Run: func(cmd *cobra.Command, args []string) { },
 }
 
 // Execute adds all child commands to the root command and sets flags appropriately.
 // This is called by main.main(). It only needs to happen once to the rootCmd.
 func Execute() {
-  if err := rootCmd.Execute(); err != nil {
-    fmt.Println(err)
-    os.Exit(1)
-  }
+	if err := rootCmd.Execute(); err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
 }
 
 func init() {
-  cobra.OnInitialize(initConfig)
+	cobra.OnInitialize(initConfig)
 
-  // Here you will define your flags and configuration settings.
-  // Cobra supports persistent flags, which, if defined here,
-  // will be global for your application.
+	// Here you will define your flags and configuration settings.
+	// 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/.testproject.yaml)")
 
-
-  // Cobra also supports local flags, which will only run
-  // when this action is called directly.
-  rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
+	// Cobra also supports local flags, which will only run
+	// when this action is called directly.
+	rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
 }
 
-
 // initConfig reads in config file and ENV variables if set.
 func initConfig() {
-  if cfgFile != "" {
-    // Use config file from the flag.
-    viper.SetConfigFile(cfgFile)
-  } else {
-    // Find home directory.
-    home, err := homedir.Dir()
-    if err != nil {
-      fmt.Println(err)
-      os.Exit(1)
-    }
-
-    // Search config in home directory with name ".testproject" (without extension).
-    viper.AddConfigPath(home)
-    viper.SetConfigName(".testproject")
-  }
-
-  viper.AutomaticEnv() // read in environment variables that match
-
-  // If a config file is found, read it in.
-  if err := viper.ReadInConfig(); err == nil {
-    fmt.Println("Using config file:", viper.ConfigFileUsed())
-  }
+	if cfgFile != "" {
+		// Use config file from the flag.
+		viper.SetConfigFile(cfgFile)
+	} else {
+		// Find home directory.
+		home, err := homedir.Dir()
+		if err != nil {
+			fmt.Println(err)
+			os.Exit(1)
+		}
+
+		// Search config in home directory with name ".testproject" (without extension).
+		viper.AddConfigPath(home)
+		viper.SetConfigName(".testproject")
+	}
+
+	viper.AutomaticEnv() // read in environment variables that match
+
+	// If a config file is found, read it in.
+	if err := viper.ReadInConfig(); err == nil {
+		fmt.Println("Using config file:", viper.ConfigFileUsed())
+	}
 }
-
diff --git a/cobra/cmd/testdata/test.go.golden b/cobra/cmd/testdata/test.go.golden
index fb8e0fa..3eef95f 100644
--- a/cobra/cmd/testdata/test.go.golden
+++ b/cobra/cmd/testdata/test.go.golden
@@ -1,5 +1,5 @@
 /*
-Copyright © 2019 NAME HERE <EMAIL ADDRESS>
+Copyright © 2020 NAME HERE <EMAIL ADDRESS>
 
 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/command_test.go b/command_test.go
index b26bd4a..1215593 100644
--- a/command_test.go
+++ b/command_test.go
@@ -2,6 +2,7 @@ package cobra
 
 import (
 	"bytes"
+	"context"
 	"fmt"
 	"os"
 	"reflect"
@@ -18,6 +19,16 @@ func executeCommand(root *Command, args ...string) (output string, err error) {
 	return output, err
 }
 
+func executeCommandWithContext(ctx context.Context, root *Command, args ...string) (output string, err error) {
+	buf := new(bytes.Buffer)
+	root.SetOutput(buf)
+	root.SetArgs(args)
+
+	err = root.ExecuteContext(ctx)
+
+	return buf.String(), err
+}
+
 func executeCommandC(root *Command, args ...string) (c *Command, output string, err error) {
 	buf := new(bytes.Buffer)
 	root.SetOutput(buf)
@@ -135,6 +146,62 @@ func TestSubcommandExecuteC(t *testing.T) {
 	}
 }
 
+func TestExecuteContext(t *testing.T) {
+	ctx := context.TODO()
+
+	ctxRun := func(cmd *Command, args []string) {
+		if cmd.Context() != ctx {
+			t.Errorf("Command %q must have context when called with ExecuteContext", cmd.Use)
+		}
+	}
+
+	rootCmd := &Command{Use: "root", Run: ctxRun, PreRun: ctxRun}
+	childCmd := &Command{Use: "child", Run: ctxRun, PreRun: ctxRun}
+	granchildCmd := &Command{Use: "grandchild", Run: ctxRun, PreRun: ctxRun}
+
+	childCmd.AddCommand(granchildCmd)
+	rootCmd.AddCommand(childCmd)
+
+	if _, err := executeCommandWithContext(ctx, rootCmd, ""); err != nil {
+		t.Errorf("Root command must not fail: %+v", err)
+	}
+
+	if _, err := executeCommandWithContext(ctx, rootCmd, "child"); err != nil {
+		t.Errorf("Subcommand must not fail: %+v", err)
+	}
+
+	if _, err := executeCommandWithContext(ctx, rootCmd, "child", "grandchild"); err != nil {
+		t.Errorf("Command child must not fail: %+v", err)
+	}
+}
+
+func TestExecute_NoContext(t *testing.T) {
+	run := func(cmd *Command, args []string) {
+		if cmd.Context() != context.Background() {
+			t.Errorf("Command %s must have background context", cmd.Use)
+		}
+	}
+
+	rootCmd := &Command{Use: "root", Run: run, PreRun: run}
+	childCmd := &Command{Use: "child", Run: run, PreRun: run}
+	granchildCmd := &Command{Use: "grandchild", Run: run, PreRun: run}
+
+	childCmd.AddCommand(granchildCmd)
+	rootCmd.AddCommand(childCmd)
+
+	if _, err := executeCommand(rootCmd, ""); err != nil {
+		t.Errorf("Root command must not fail: %+v", err)
+	}
+
+	if _, err := executeCommand(rootCmd, "child"); err != nil {
+		t.Errorf("Subcommand must not fail: %+v", err)
+	}
+
+	if _, err := executeCommand(rootCmd, "child", "grandchild"); err != nil {
+		t.Errorf("Command child must not fail: %+v", err)
+	}
+}
+
 func TestRootUnknownCommandSilenced(t *testing.T) {
 	rootCmd := &Command{Use: "root", Run: emptyRun}
 	rootCmd.SilenceErrors = true
@@ -854,6 +921,52 @@ func TestVersionFlagExecuted(t *testing.T) {
 	checkStringContains(t, output, "root version 1.0.0")
 }
 
+func TestVersionFlagExecutedWithNoName(t *testing.T) {
+	rootCmd := &Command{Version: "1.0.0", Run: emptyRun}
+
+	output, err := executeCommand(rootCmd, "--version", "arg1")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	checkStringContains(t, output, "version 1.0.0")
+}
+
+func TestShortAndLongVersionFlagInHelp(t *testing.T) {
+	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
+
+	output, err := executeCommand(rootCmd, "--help")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	checkStringContains(t, output, "-v, --version")
+}
+
+func TestLongVersionFlagOnlyInHelpWhenShortPredefined(t *testing.T) {
+	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
+	rootCmd.Flags().StringP("foo", "v", "", "not a version flag")
+
+	output, err := executeCommand(rootCmd, "--help")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	checkStringOmits(t, output, "-v, --version")
+	checkStringContains(t, output, "--version")
+}
+
+func TestShorthandVersionFlagExecuted(t *testing.T) {
+	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
+
+	output, err := executeCommand(rootCmd, "-v", "arg1")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	checkStringContains(t, output, "root version 1.0.0")
+}
+
 func TestVersionTemplate(t *testing.T) {
 	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
 	rootCmd.SetVersionTemplate(`customized version: {{.Version}}`)
@@ -866,6 +979,18 @@ func TestVersionTemplate(t *testing.T) {
 	checkStringContains(t, output, "customized version: 1.0.0")
 }
 
+func TestShorthandVersionTemplate(t *testing.T) {
+	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
+	rootCmd.SetVersionTemplate(`customized version: {{.Version}}`)
+
+	output, err := executeCommand(rootCmd, "-v", "arg1")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	checkStringContains(t, output, "customized version: 1.0.0")
+}
+
 func TestVersionFlagExecutedOnSubcommand(t *testing.T) {
 	rootCmd := &Command{Use: "root", Version: "1.0.0"}
 	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
@@ -878,6 +1003,18 @@ func TestVersionFlagExecutedOnSubcommand(t *testing.T) {
 	checkStringContains(t, output, "root version 1.0.0")
 }
 
+func TestShorthandVersionFlagExecutedOnSubcommand(t *testing.T) {
+	rootCmd := &Command{Use: "root", Version: "1.0.0"}
+	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
+
+	output, err := executeCommand(rootCmd, "-v", "sub")
+	if err != nil {
+		t.Errorf("Unexpected error: %v", err)
+	}
+
+	checkStringContains(t, output, "root version 1.0.0")
+}
+
 func TestVersionFlagOnlyAddedToRoot(t *testing.T) {
 	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
 	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
@@ -890,6 +1027,18 @@ func TestVersionFlagOnlyAddedToRoot(t *testing.T) {
 	checkStringContains(t, err.Error(), "unknown flag: --version")
 }
 
+func TestShortVersionFlagOnlyAddedToRoot(t *testing.T) {
+	rootCmd := &Command{Use: "root", Version: "1.0.0", Run: emptyRun}
+	rootCmd.AddCommand(&Command{Use: "sub", Run: emptyRun})
+
+	_, err := executeCommand(rootCmd, "sub", "-v")
+	if err == nil {
+		t.Errorf("Expected error")
+	}
+
+	checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v")
+}
+
 func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) {
 	rootCmd := &Command{Use: "root", Run: emptyRun}
 
@@ -900,6 +1049,39 @@ func TestVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) {
 	checkStringContains(t, err.Error(), "unknown flag: --version")
 }
 
+func TestShorthandVersionFlagOnlyExistsIfVersionNonEmpty(t *testing.T) {
+	rootCmd := &Command{Use: "root", Run: emptyRun}
+
+	_, err := executeCommand(rootCmd, "-v")
+	if err == nil {
+		t.Errorf("Expected error")
+	}
+	checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v")
+}
+
+func TestShorthandVersionFlagOnlyAddedIfShorthandNotDefined(t *testing.T) {
+	rootCmd := &Command{Use: "root", Run: emptyRun, Version: "1.2.3"}
+	rootCmd.Flags().StringP("notversion", "v", "", "not a version flag")
+
+	_, err := executeCommand(rootCmd, "-v")
+	if err == nil {
+		t.Errorf("Expected error")
+	}
+	check(t, rootCmd.Flags().ShorthandLookup("v").Name, "notversion")
+	checkStringContains(t, err.Error(), "flag needs an argument: 'v' in -v")
+}
+
+func TestShorthandVersionFlagOnlyAddedIfVersionNotDefined(t *testing.T) {
+	rootCmd := &Command{Use: "root", Run: emptyRun, Version: "1.2.3"}
+	rootCmd.Flags().Bool("version", false, "a different kind of version flag")
+
+	_, err := executeCommand(rootCmd, "-v")
+	if err == nil {
+		t.Errorf("Expected error")
+	}
+	checkStringContains(t, err.Error(), "unknown shorthand flag: 'v' in -v")
+}
+
 func TestUsageIsNotPrintedTwice(t *testing.T) {
 	var cmd = &Command{Use: "root"}
 	var sub = &Command{Use: "sub"}