Merge pull request #168 from MichaelMure/dependabot/dep/github.com/spf13/cobra-0.0.5

Michael Muré created

build(deps): bump github.com/spf13/cobra from 0.0.4 to 0.0.5

Change summary

Gopkg.lock                                              |   6 
Gopkg.toml                                              |   2 
doc/man/git-bug-bridge-rm.1                             |   2 
doc/md/git-bug_bridge_rm.md                             |   2 
git-bug.go                                              |   1 
misc/gen_bash_completion.go                             |   2 
misc/gen_powershell_completion.go                       |  24 
misc/gen_zsh_completion.go                              |   2 
misc/powershell_completion/git-bug                      | 207 +++++
misc/zsh_completion/git-bug                             | 442 +++++++++-
vendor/github.com/spf13/cobra/.gitignore                |   2 
vendor/github.com/spf13/cobra/README.md                 |   9 
vendor/github.com/spf13/cobra/bash_completions.go       |  48 -
vendor/github.com/spf13/cobra/command.go                |  97 ++
vendor/github.com/spf13/cobra/powershell_completions.go | 100 ++
vendor/github.com/spf13/cobra/powershell_completions.md |  14 
vendor/github.com/spf13/cobra/shell_completions.go      |  85 ++
vendor/github.com/spf13/cobra/zsh_completions.go        | 363 +++++++--
vendor/github.com/spf13/cobra/zsh_completions.md        |  39 
19 files changed, 1,254 insertions(+), 193 deletions(-)

Detailed changes

Gopkg.lock 🔗

@@ -268,15 +268,15 @@
   revision = "79abb63cd66e41cb1473e26d11ebdcd68b04c8e5"
 
 [[projects]]
-  digest = "1:2e72f9cdc8b6f94a145fa1c97e305e1654d40507d04d2fbb0c37bf461a4b85f7"
+  digest = "1:abe9f3f23399646a6263682cacc9e86969f6c7e768f0ef036449926aa24cbbef"
   name = "github.com/spf13/cobra"
   packages = [
     ".",
     "doc",
   ]
   pruneopts = "UT"
-  revision = "67fc4837d267bc9bfd6e47f77783fcc3dffc68de"
-  version = "v0.0.4"
+  revision = "f2b07da1e2c38d5f12845a4f607e2e1018cbb1f5"
+  version = "v0.0.5"
 
 [[projects]]
   digest = "1:9424f440bba8f7508b69414634aef3b2b3a877e522d8a4624692412805407bb7"

Gopkg.toml 🔗

@@ -50,7 +50,7 @@
 
 [[constraint]]
   name = "github.com/spf13/cobra"
-  version = "v0.0.4"
+  version = "v0.0.5"
 
 [[constraint]]
   name = "github.com/dustin/go-humanize"

doc/man/git-bug-bridge-rm.1 🔗

@@ -10,7 +10,7 @@ git\-bug\-bridge\-rm \- Delete a configured bridge.
 
 .SH SYNOPSIS
 .PP
-\fBgit\-bug bridge rm name <name> [flags]\fP
+\fBgit\-bug bridge rm <name> [flags]\fP
 
 
 .SH DESCRIPTION

doc/md/git-bug_bridge_rm.md 🔗

@@ -7,7 +7,7 @@ Delete a configured bridge.
 Delete a configured bridge.
 
 ```
-git-bug bridge rm name <name> [flags]
+git-bug bridge rm <name> [flags]
 ```
 
 ### Options

git-bug.go 🔗

@@ -1,6 +1,7 @@
 //go:generate go run doc/gen_markdown.go
 //go:generate go run doc/gen_manpage.go
 //go:generate go run misc/gen_bash_completion.go
+//go:generate go run misc/gen_powershell_completion.go
 //go:generate go run misc/gen_zsh_completion.go
 
 package main

misc/gen_bash_completion.go 🔗

@@ -15,7 +15,7 @@ func main() {
 	cwd, _ := os.Getwd()
 	dir := path.Join(cwd, "misc", "bash_completion", "git-bug")
 
-	fmt.Println("Generating bash completion file ...")
+	fmt.Println("Generating Bash completion file ...")
 
 	err := commands.RootCmd.GenBashCompletionFile(dir)
 	if err != nil {

misc/gen_powershell_completion.go 🔗

@@ -0,0 +1,24 @@
+// +build ignore
+
+package main
+
+import (
+	"fmt"
+	"log"
+	"os"
+	"path"
+
+	"github.com/MichaelMure/git-bug/commands"
+)
+
+func main() {
+	cwd, _ := os.Getwd()
+	filepath := path.Join(cwd, "misc", "powershell_completion", "git-bug")
+
+	fmt.Println("Generating PowerShell completion file ...")
+
+	err := commands.RootCmd.GenPowerShellCompletionFile(filepath)
+	if err != nil {
+		log.Fatal(err)
+	}
+}

misc/gen_zsh_completion.go 🔗

@@ -15,7 +15,7 @@ func main() {
 	cwd, _ := os.Getwd()
 	filepath := path.Join(cwd, "misc", "zsh_completion", "git-bug")
 
-	fmt.Println("Generating zsh completion file ...")
+	fmt.Println("Generating ZSH completion file ...")
 
 	err := commands.RootCmd.GenZshCompletionFile(filepath)
 	if err != nil {

misc/powershell_completion/git-bug 🔗

@@ -0,0 +1,207 @@
+using namespace System.Management.Automation
+using namespace System.Management.Automation.Language
+Register-ArgumentCompleter -Native -CommandName 'git-bug' -ScriptBlock {
+    param($wordToComplete, $commandAst, $cursorPosition)
+    $commandElements = $commandAst.CommandElements
+    $command = @(
+        'git-bug'
+        for ($i = 1; $i -lt $commandElements.Count; $i++) {
+            $element = $commandElements[$i]
+            if ($element -isnot [StringConstantExpressionAst] -or
+                $element.StringConstantType -ne [StringConstantType]::BareWord -or
+                $element.Value.StartsWith('-')) {
+                break
+            }
+            $element.Value
+        }
+    ) -join ';'
+    $completions = @(switch ($command) {
+        'git-bug' {
+            [CompletionResult]::new('add', 'add', [CompletionResultType]::ParameterValue, 'Create a new bug.')
+            [CompletionResult]::new('bridge', 'bridge', [CompletionResultType]::ParameterValue, 'Configure and use bridges to other bug trackers.')
+            [CompletionResult]::new('commands', 'commands', [CompletionResultType]::ParameterValue, 'Display available commands.')
+            [CompletionResult]::new('comment', 'comment', [CompletionResultType]::ParameterValue, 'Display or add comments to a bug.')
+            [CompletionResult]::new('deselect', 'deselect', [CompletionResultType]::ParameterValue, 'Clear the implicitly selected bug.')
+            [CompletionResult]::new('label', 'label', [CompletionResultType]::ParameterValue, 'Display, add or remove labels to/from a bug.')
+            [CompletionResult]::new('ls', 'ls', [CompletionResultType]::ParameterValue, 'List bugs.')
+            [CompletionResult]::new('ls-id', 'ls-id', [CompletionResultType]::ParameterValue, 'List bug identifiers.')
+            [CompletionResult]::new('ls-label', 'ls-label', [CompletionResultType]::ParameterValue, 'List valid labels.')
+            [CompletionResult]::new('pull', 'pull', [CompletionResultType]::ParameterValue, 'Pull bugs update from a git remote.')
+            [CompletionResult]::new('push', 'push', [CompletionResultType]::ParameterValue, 'Push bugs update to a git remote.')
+            [CompletionResult]::new('select', 'select', [CompletionResultType]::ParameterValue, 'Select a bug for implicit use in future commands.')
+            [CompletionResult]::new('show', 'show', [CompletionResultType]::ParameterValue, 'Display the details of a bug.')
+            [CompletionResult]::new('status', 'status', [CompletionResultType]::ParameterValue, 'Display or change a bug status.')
+            [CompletionResult]::new('termui', 'termui', [CompletionResultType]::ParameterValue, 'Launch the terminal UI.')
+            [CompletionResult]::new('title', 'title', [CompletionResultType]::ParameterValue, 'Display or change a title of a bug.')
+            [CompletionResult]::new('user', 'user', [CompletionResultType]::ParameterValue, 'Display or change the user identity.')
+            [CompletionResult]::new('version', 'version', [CompletionResultType]::ParameterValue, 'Show git-bug version information.')
+            [CompletionResult]::new('webui', 'webui', [CompletionResultType]::ParameterValue, 'Launch the web UI.')
+            break
+        }
+        'git-bug;add' {
+            [CompletionResult]::new('-t', 't', [CompletionResultType]::ParameterName, 'Provide a title to describe the issue')
+            [CompletionResult]::new('--title', 'title', [CompletionResultType]::ParameterName, 'Provide a title to describe the issue')
+            [CompletionResult]::new('-m', 'm', [CompletionResultType]::ParameterName, 'Provide a message to describe the issue')
+            [CompletionResult]::new('--message', 'message', [CompletionResultType]::ParameterName, 'Provide a message to describe the issue')
+            [CompletionResult]::new('-F', 'F', [CompletionResultType]::ParameterName, 'Take the message from the given file. Use - to read the message from the standard input')
+            [CompletionResult]::new('--file', 'file', [CompletionResultType]::ParameterName, 'Take the message from the given file. Use - to read the message from the standard input')
+            break
+        }
+        'git-bug;bridge' {
+            [CompletionResult]::new('configure', 'configure', [CompletionResultType]::ParameterValue, 'Configure a new bridge.')
+            [CompletionResult]::new('pull', 'pull', [CompletionResultType]::ParameterValue, 'Pull updates.')
+            [CompletionResult]::new('rm', 'rm', [CompletionResultType]::ParameterValue, 'Delete a configured bridge.')
+            break
+        }
+        'git-bug;bridge;configure' {
+            [CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'A distinctive name to identify the bridge')
+            [CompletionResult]::new('--name', 'name', [CompletionResultType]::ParameterName, 'A distinctive name to identify the bridge')
+            [CompletionResult]::new('-t', 't', [CompletionResultType]::ParameterName, 'The target of the bridge. Valid values are [github,launchpad-preview]')
+            [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'The target of the bridge. Valid values are [github,launchpad-preview]')
+            [CompletionResult]::new('-u', 'u', [CompletionResultType]::ParameterName, 'The URL of the target repository')
+            [CompletionResult]::new('--url', 'url', [CompletionResultType]::ParameterName, 'The URL of the target repository')
+            [CompletionResult]::new('-o', 'o', [CompletionResultType]::ParameterName, 'The owner of the target repository')
+            [CompletionResult]::new('--owner', 'owner', [CompletionResultType]::ParameterName, 'The owner of the target repository')
+            [CompletionResult]::new('-T', 'T', [CompletionResultType]::ParameterName, 'The authentication token for the API')
+            [CompletionResult]::new('--token', 'token', [CompletionResultType]::ParameterName, 'The authentication token for the API')
+            [CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'The name of the target repository')
+            [CompletionResult]::new('--project', 'project', [CompletionResultType]::ParameterName, 'The name of the target repository')
+            break
+        }
+        'git-bug;bridge;pull' {
+            break
+        }
+        'git-bug;bridge;rm' {
+            break
+        }
+        'git-bug;commands' {
+            [CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Output the command description as well as Markdown compatible comment')
+            [CompletionResult]::new('--pretty', 'pretty', [CompletionResultType]::ParameterName, 'Output the command description as well as Markdown compatible comment')
+            break
+        }
+        'git-bug;comment' {
+            [CompletionResult]::new('add', 'add', [CompletionResultType]::ParameterValue, 'Add a new comment to a bug.')
+            break
+        }
+        'git-bug;comment;add' {
+            [CompletionResult]::new('-F', 'F', [CompletionResultType]::ParameterName, 'Take the message from the given file. Use - to read the message from the standard input')
+            [CompletionResult]::new('--file', 'file', [CompletionResultType]::ParameterName, 'Take the message from the given file. Use - to read the message from the standard input')
+            [CompletionResult]::new('-m', 'm', [CompletionResultType]::ParameterName, 'Provide the new message from the command line')
+            [CompletionResult]::new('--message', 'message', [CompletionResultType]::ParameterName, 'Provide the new message from the command line')
+            break
+        }
+        'git-bug;deselect' {
+            break
+        }
+        'git-bug;label' {
+            [CompletionResult]::new('add', 'add', [CompletionResultType]::ParameterValue, 'Add a label to a bug.')
+            [CompletionResult]::new('rm', 'rm', [CompletionResultType]::ParameterValue, 'Remove a label from a bug.')
+            break
+        }
+        'git-bug;label;add' {
+            break
+        }
+        'git-bug;label;rm' {
+            break
+        }
+        'git-bug;ls' {
+            [CompletionResult]::new('-s', 's', [CompletionResultType]::ParameterName, 'Filter by status. Valid values are [open,closed]')
+            [CompletionResult]::new('--status', 'status', [CompletionResultType]::ParameterName, 'Filter by status. Valid values are [open,closed]')
+            [CompletionResult]::new('-a', 'a', [CompletionResultType]::ParameterName, 'Filter by author')
+            [CompletionResult]::new('--author', 'author', [CompletionResultType]::ParameterName, 'Filter by author')
+            [CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Filter by participant')
+            [CompletionResult]::new('--participant', 'participant', [CompletionResultType]::ParameterName, 'Filter by participant')
+            [CompletionResult]::new('-A', 'A', [CompletionResultType]::ParameterName, 'Filter by actor')
+            [CompletionResult]::new('--actor', 'actor', [CompletionResultType]::ParameterName, 'Filter by actor')
+            [CompletionResult]::new('-l', 'l', [CompletionResultType]::ParameterName, 'Filter by label')
+            [CompletionResult]::new('--label', 'label', [CompletionResultType]::ParameterName, 'Filter by label')
+            [CompletionResult]::new('-t', 't', [CompletionResultType]::ParameterName, 'Filter by title')
+            [CompletionResult]::new('--title', 'title', [CompletionResultType]::ParameterName, 'Filter by title')
+            [CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'Filter by absence of something. Valid values are [label]')
+            [CompletionResult]::new('--no', 'no', [CompletionResultType]::ParameterName, 'Filter by absence of something. Valid values are [label]')
+            [CompletionResult]::new('-b', 'b', [CompletionResultType]::ParameterName, 'Sort the results by a characteristic. Valid values are [id,creation,edit]')
+            [CompletionResult]::new('--by', 'by', [CompletionResultType]::ParameterName, 'Sort the results by a characteristic. Valid values are [id,creation,edit]')
+            [CompletionResult]::new('-d', 'd', [CompletionResultType]::ParameterName, 'Select the sorting direction. Valid values are [asc,desc]')
+            [CompletionResult]::new('--direction', 'direction', [CompletionResultType]::ParameterName, 'Select the sorting direction. Valid values are [asc,desc]')
+            break
+        }
+        'git-bug;ls-id' {
+            break
+        }
+        'git-bug;ls-label' {
+            break
+        }
+        'git-bug;pull' {
+            break
+        }
+        'git-bug;push' {
+            break
+        }
+        'git-bug;select' {
+            break
+        }
+        'git-bug;show' {
+            [CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'Select field to display. Valid values are [author,authorEmail,createTime,humanId,id,labels,shortId,status,title,actors,participants]')
+            [CompletionResult]::new('--field', 'field', [CompletionResultType]::ParameterName, 'Select field to display. Valid values are [author,authorEmail,createTime,humanId,id,labels,shortId,status,title,actors,participants]')
+            break
+        }
+        'git-bug;status' {
+            [CompletionResult]::new('close', 'close', [CompletionResultType]::ParameterValue, 'Mark a bug as closed.')
+            [CompletionResult]::new('open', 'open', [CompletionResultType]::ParameterValue, 'Mark a bug as open.')
+            break
+        }
+        'git-bug;status;close' {
+            break
+        }
+        'git-bug;status;open' {
+            break
+        }
+        'git-bug;termui' {
+            break
+        }
+        'git-bug;title' {
+            [CompletionResult]::new('edit', 'edit', [CompletionResultType]::ParameterValue, 'Edit a title of a bug.')
+            break
+        }
+        'git-bug;title;edit' {
+            [CompletionResult]::new('-t', 't', [CompletionResultType]::ParameterName, 'Provide a title to describe the issue')
+            [CompletionResult]::new('--title', 'title', [CompletionResultType]::ParameterName, 'Provide a title to describe the issue')
+            break
+        }
+        'git-bug;user' {
+            [CompletionResult]::new('-f', 'f', [CompletionResultType]::ParameterName, 'Select field to display. Valid values are [email,humanId,id,lastModification,lastModificationLamport,login,metadata,name]')
+            [CompletionResult]::new('--field', 'field', [CompletionResultType]::ParameterName, 'Select field to display. Valid values are [email,humanId,id,lastModification,lastModificationLamport,login,metadata,name]')
+            [CompletionResult]::new('adopt', 'adopt', [CompletionResultType]::ParameterValue, 'Adopt an existing identity as your own.')
+            [CompletionResult]::new('create', 'create', [CompletionResultType]::ParameterValue, 'Create a new identity.')
+            [CompletionResult]::new('ls', 'ls', [CompletionResultType]::ParameterValue, 'List identities.')
+            break
+        }
+        'git-bug;user;adopt' {
+            break
+        }
+        'git-bug;user;create' {
+            break
+        }
+        'git-bug;user;ls' {
+            break
+        }
+        'git-bug;version' {
+            [CompletionResult]::new('-n', 'n', [CompletionResultType]::ParameterName, 'Only show the version number')
+            [CompletionResult]::new('--number', 'number', [CompletionResultType]::ParameterName, 'Only show the version number')
+            [CompletionResult]::new('-c', 'c', [CompletionResultType]::ParameterName, 'Only show the commit hash')
+            [CompletionResult]::new('--commit', 'commit', [CompletionResultType]::ParameterName, 'Only show the commit hash')
+            [CompletionResult]::new('-a', 'a', [CompletionResultType]::ParameterName, 'Show all version informations')
+            [CompletionResult]::new('--all', 'all', [CompletionResultType]::ParameterName, 'Show all version informations')
+            break
+        }
+        'git-bug;webui' {
+            [CompletionResult]::new('--open', 'open', [CompletionResultType]::ParameterName, 'Automatically open the web UI in the default browser')
+            [CompletionResult]::new('--no-open', 'no-open', [CompletionResultType]::ParameterName, 'Prevent the automatic opening of the web UI in the default browser')
+            [CompletionResult]::new('-p', 'p', [CompletionResultType]::ParameterName, 'Port to listen to (default is random)')
+            [CompletionResult]::new('--port', 'port', [CompletionResultType]::ParameterName, 'Port to listen to (default is random)')
+            break
+        }
+    })
+    $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
+        Sort-Object -Property ListItemText
+}

misc/zsh_completion/git-bug 🔗

@@ -1,46 +1,396 @@
-#compdef git-bug
-
-_arguments \
-  '1: :->level1' \
-  '2: :->level2' \
-  '3: :_files'
-case $state in
-  level1)
-    case $words[1] in
-      git-bug)
-        _arguments '1: :(add bridge commands comment deselect label ls ls-id ls-label pull push select show status termui title user version webui)'
-      ;;
-      *)
-        _arguments '*: :_files'
-      ;;
-    esac
-  ;;
-  level2)
-    case $words[2] in
-      bridge)
-        _arguments '2: :(configure pull rm)'
-      ;;
-      comment)
-        _arguments '2: :(add)'
-      ;;
-      label)
-        _arguments '2: :(add rm)'
-      ;;
-      status)
-        _arguments '2: :(close open)'
-      ;;
-      title)
-        _arguments '2: :(edit)'
-      ;;
-      user)
-        _arguments '2: :(adopt create ls)'
-      ;;
-      *)
-        _arguments '*: :_files'
-      ;;
-    esac
-  ;;
-  *)
-    _arguments '*: :_files'
-  ;;
-esac
+#compdef _git-bug git-bug
+
+
+function _git-bug {
+  local -a commands
+
+  _arguments -C \
+    "1: :->cmnds" \
+    "*::arg:->args"
+
+  case $state in
+  cmnds)
+    commands=(
+      "add:Create a new bug."
+      "bridge:Configure and use bridges to other bug trackers."
+      "commands:Display available commands."
+      "comment:Display or add comments to a bug."
+      "deselect:Clear the implicitly selected bug."
+      "label:Display, add or remove labels to/from a bug."
+      "ls:List bugs."
+      "ls-id:List bug identifiers."
+      "ls-label:List valid labels."
+      "pull:Pull bugs update from a git remote."
+      "push:Push bugs update to a git remote."
+      "select:Select a bug for implicit use in future commands."
+      "show:Display the details of a bug."
+      "status:Display or change a bug status."
+      "termui:Launch the terminal UI."
+      "title:Display or change a title of a bug."
+      "user:Display or change the user identity."
+      "version:Show git-bug version information."
+      "webui:Launch the web UI."
+    )
+    _describe "command" commands
+    ;;
+  esac
+
+  case "$words[1]" in
+  add)
+    _git-bug_add
+    ;;
+  bridge)
+    _git-bug_bridge
+    ;;
+  commands)
+    _git-bug_commands
+    ;;
+  comment)
+    _git-bug_comment
+    ;;
+  deselect)
+    _git-bug_deselect
+    ;;
+  label)
+    _git-bug_label
+    ;;
+  ls)
+    _git-bug_ls
+    ;;
+  ls-id)
+    _git-bug_ls-id
+    ;;
+  ls-label)
+    _git-bug_ls-label
+    ;;
+  pull)
+    _git-bug_pull
+    ;;
+  push)
+    _git-bug_push
+    ;;
+  select)
+    _git-bug_select
+    ;;
+  show)
+    _git-bug_show
+    ;;
+  status)
+    _git-bug_status
+    ;;
+  termui)
+    _git-bug_termui
+    ;;
+  title)
+    _git-bug_title
+    ;;
+  user)
+    _git-bug_user
+    ;;
+  version)
+    _git-bug_version
+    ;;
+  webui)
+    _git-bug_webui
+    ;;
+  esac
+}
+
+function _git-bug_add {
+  _arguments \
+    '(-t --title)'{-t,--title}'[Provide a title to describe the issue]:' \
+    '(-m --message)'{-m,--message}'[Provide a message to describe the issue]:' \
+    '(-F --file)'{-F,--file}'[Take the message from the given file. Use - to read the message from the standard input]:'
+}
+
+
+function _git-bug_bridge {
+  local -a commands
+
+  _arguments -C \
+    "1: :->cmnds" \
+    "*::arg:->args"
+
+  case $state in
+  cmnds)
+    commands=(
+      "configure:Configure a new bridge."
+      "pull:Pull updates."
+      "rm:Delete a configured bridge."
+    )
+    _describe "command" commands
+    ;;
+  esac
+
+  case "$words[1]" in
+  configure)
+    _git-bug_bridge_configure
+    ;;
+  pull)
+    _git-bug_bridge_pull
+    ;;
+  rm)
+    _git-bug_bridge_rm
+    ;;
+  esac
+}
+
+function _git-bug_bridge_configure {
+  _arguments \
+    '(-n --name)'{-n,--name}'[A distinctive name to identify the bridge]:' \
+    '(-t --target)'{-t,--target}'[The target of the bridge. Valid values are [github,launchpad-preview]]:' \
+    '(-u --url)'{-u,--url}'[The URL of the target repository]:' \
+    '(-o --owner)'{-o,--owner}'[The owner of the target repository]:' \
+    '(-T --token)'{-T,--token}'[The authentication token for the API]:' \
+    '(-p --project)'{-p,--project}'[The name of the target repository]:'
+}
+
+function _git-bug_bridge_pull {
+  _arguments
+}
+
+function _git-bug_bridge_rm {
+  _arguments
+}
+
+function _git-bug_commands {
+  _arguments \
+    '(-p --pretty)'{-p,--pretty}'[Output the command description as well as Markdown compatible comment]'
+}
+
+
+function _git-bug_comment {
+  local -a commands
+
+  _arguments -C \
+    "1: :->cmnds" \
+    "*::arg:->args"
+
+  case $state in
+  cmnds)
+    commands=(
+      "add:Add a new comment to a bug."
+    )
+    _describe "command" commands
+    ;;
+  esac
+
+  case "$words[1]" in
+  add)
+    _git-bug_comment_add
+    ;;
+  esac
+}
+
+function _git-bug_comment_add {
+  _arguments \
+    '(-F --file)'{-F,--file}'[Take the message from the given file. Use - to read the message from the standard input]:' \
+    '(-m --message)'{-m,--message}'[Provide the new message from the command line]:'
+}
+
+function _git-bug_deselect {
+  _arguments
+}
+
+
+function _git-bug_label {
+  local -a commands
+
+  _arguments -C \
+    "1: :->cmnds" \
+    "*::arg:->args"
+
+  case $state in
+  cmnds)
+    commands=(
+      "add:Add a label to a bug."
+      "rm:Remove a label from a bug."
+    )
+    _describe "command" commands
+    ;;
+  esac
+
+  case "$words[1]" in
+  add)
+    _git-bug_label_add
+    ;;
+  rm)
+    _git-bug_label_rm
+    ;;
+  esac
+}
+
+function _git-bug_label_add {
+  _arguments
+}
+
+function _git-bug_label_rm {
+  _arguments
+}
+
+function _git-bug_ls {
+  _arguments \
+    '(*-s *--status)'{\*-s,\*--status}'[Filter by status. Valid values are [open,closed]]:' \
+    '(*-a *--author)'{\*-a,\*--author}'[Filter by author]:' \
+    '(*-p *--participant)'{\*-p,\*--participant}'[Filter by participant]:' \
+    '(*-A *--actor)'{\*-A,\*--actor}'[Filter by actor]:' \
+    '(*-l *--label)'{\*-l,\*--label}'[Filter by label]:' \
+    '(*-t *--title)'{\*-t,\*--title}'[Filter by title]:' \
+    '(*-n *--no)'{\*-n,\*--no}'[Filter by absence of something. Valid values are [label]]:' \
+    '(-b --by)'{-b,--by}'[Sort the results by a characteristic. Valid values are [id,creation,edit]]:' \
+    '(-d --direction)'{-d,--direction}'[Select the sorting direction. Valid values are [asc,desc]]:'
+}
+
+function _git-bug_ls-id {
+  _arguments
+}
+
+function _git-bug_ls-label {
+  _arguments
+}
+
+function _git-bug_pull {
+  _arguments
+}
+
+function _git-bug_push {
+  _arguments
+}
+
+function _git-bug_select {
+  _arguments
+}
+
+function _git-bug_show {
+  _arguments \
+    '(-f --field)'{-f,--field}'[Select field to display. Valid values are [author,authorEmail,createTime,humanId,id,labels,shortId,status,title,actors,participants]]:'
+}
+
+
+function _git-bug_status {
+  local -a commands
+
+  _arguments -C \
+    "1: :->cmnds" \
+    "*::arg:->args"
+
+  case $state in
+  cmnds)
+    commands=(
+      "close:Mark a bug as closed."
+      "open:Mark a bug as open."
+    )
+    _describe "command" commands
+    ;;
+  esac
+
+  case "$words[1]" in
+  close)
+    _git-bug_status_close
+    ;;
+  open)
+    _git-bug_status_open
+    ;;
+  esac
+}
+
+function _git-bug_status_close {
+  _arguments
+}
+
+function _git-bug_status_open {
+  _arguments
+}
+
+function _git-bug_termui {
+  _arguments
+}
+
+
+function _git-bug_title {
+  local -a commands
+
+  _arguments -C \
+    "1: :->cmnds" \
+    "*::arg:->args"
+
+  case $state in
+  cmnds)
+    commands=(
+      "edit:Edit a title of a bug."
+    )
+    _describe "command" commands
+    ;;
+  esac
+
+  case "$words[1]" in
+  edit)
+    _git-bug_title_edit
+    ;;
+  esac
+}
+
+function _git-bug_title_edit {
+  _arguments \
+    '(-t --title)'{-t,--title}'[Provide a title to describe the issue]:'
+}
+
+
+function _git-bug_user {
+  local -a commands
+
+  _arguments -C \
+    '(-f --field)'{-f,--field}'[Select field to display. Valid values are [email,humanId,id,lastModification,lastModificationLamport,login,metadata,name]]:' \
+    "1: :->cmnds" \
+    "*::arg:->args"
+
+  case $state in
+  cmnds)
+    commands=(
+      "adopt:Adopt an existing identity as your own."
+      "create:Create a new identity."
+      "ls:List identities."
+    )
+    _describe "command" commands
+    ;;
+  esac
+
+  case "$words[1]" in
+  adopt)
+    _git-bug_user_adopt
+    ;;
+  create)
+    _git-bug_user_create
+    ;;
+  ls)
+    _git-bug_user_ls
+    ;;
+  esac
+}
+
+function _git-bug_user_adopt {
+  _arguments
+}
+
+function _git-bug_user_create {
+  _arguments
+}
+
+function _git-bug_user_ls {
+  _arguments
+}
+
+function _git-bug_version {
+  _arguments \
+    '(-n --number)'{-n,--number}'[Only show the version number]' \
+    '(-c --commit)'{-c,--commit}'[Only show the commit hash]' \
+    '(-a --all)'{-a,--all}'[Show all version informations]'
+}
+
+function _git-bug_webui {
+  _arguments \
+    '--open[Automatically open the web UI in the default browser]' \
+    '--no-open[Prevent the automatic opening of the web UI in the default browser]' \
+    '(-p --port)'{-p,--port}'[Port to listen to (default is random)]:'
+}
+

vendor/github.com/spf13/cobra/README.md 🔗

@@ -23,6 +23,7 @@ Many of the most widely used Go projects are built using Cobra, such as:
 [Istio](https://istio.io),
 [Prototool](https://github.com/uber/prototool),
 [mattermost-server](https://github.com/mattermost/mattermost-server),
+[Gardener](https://github.com/gardener/gardenctl),
 etc.
 
 [![Build Status](https://travis-ci.org/spf13/cobra.svg "Travis CI status")](https://travis-ci.org/spf13/cobra)
@@ -48,6 +49,7 @@ etc.
   * [Suggestions when "unknown command" happens](#suggestions-when-unknown-command-happens)
   * [Generating documentation for your command](#generating-documentation-for-your-command)
   * [Generating bash completions](#generating-bash-completions)
+  * [Generating zsh completions](#generating-zsh-completions)
 - [Contributing](#contributing)
 - [License](#license)
 
@@ -336,7 +338,7 @@ rootCmd.PersistentFlags().BoolVarP(&Verbose, "verbose", "v", false, "verbose out
 A flag can also be assigned locally which will only apply to that specific command.
 
 ```go
-rootCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
+localCmd.Flags().StringVarP(&Source, "source", "s", "", "Source directory to read from")
 ```
 
 ### Local Flag on Parent Commands
@@ -719,6 +721,11 @@ Cobra can generate documentation based on subcommands, flags, etc. in the follow
 
 Cobra can generate a bash-completion file. If you add more information to your command, these completions can be amazingly powerful and flexible.  Read more about it in [Bash Completions](bash_completions.md).
 
+## Generating zsh completions
+
+Cobra can generate zsh-completion file. Read more about it in
+[Zsh Completions](zsh_completions.md).
+
 # Contributing
 
 1. Fork it

vendor/github.com/spf13/cobra/bash_completions.go 🔗

@@ -545,51 +545,3 @@ func (c *Command) GenBashCompletionFile(filename string) error {
 
 	return c.GenBashCompletion(outFile)
 }
-
-// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
-// and causes your command to report an error if invoked without the flag.
-func (c *Command) MarkFlagRequired(name string) error {
-	return MarkFlagRequired(c.Flags(), name)
-}
-
-// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists,
-// and causes your command to report an error if invoked without the flag.
-func (c *Command) MarkPersistentFlagRequired(name string) error {
-	return MarkFlagRequired(c.PersistentFlags(), name)
-}
-
-// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
-// and causes your command to report an error if invoked without the flag.
-func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
-	return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"})
-}
-
-// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists.
-// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
-func (c *Command) MarkFlagFilename(name string, extensions ...string) error {
-	return MarkFlagFilename(c.Flags(), name, extensions...)
-}
-
-// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists.
-// Generated bash autocompletion will call the bash function f for the flag.
-func (c *Command) MarkFlagCustom(name string, f string) error {
-	return MarkFlagCustom(c.Flags(), name, f)
-}
-
-// MarkPersistentFlagFilename adds the BashCompFilenameExt annotation to the named persistent flag, if it exists.
-// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
-func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
-	return MarkFlagFilename(c.PersistentFlags(), name, extensions...)
-}
-
-// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag in the flag set, if it exists.
-// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
-func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error {
-	return flags.SetAnnotation(name, BashCompFilenameExt, extensions)
-}
-
-// MarkFlagCustom adds the BashCompCustom annotation to the named flag in the flag set, if it exists.
-// Generated bash autocompletion will call the bash function f for the flag.
-func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error {
-	return flags.SetAnnotation(name, BashCompCustom, []string{f})
-}

vendor/github.com/spf13/cobra/command.go 🔗

@@ -177,8 +177,6 @@ type Command struct {
 	// that we can use on every pflag set and children commands
 	globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName
 
-	// output is an output writer defined by user.
-	output io.Writer
 	// usageFunc is usage func defined by user.
 	usageFunc func(*Command) error
 	// usageTemplate is usage template defined by user.
@@ -195,6 +193,13 @@ type Command struct {
 	helpCommand *Command
 	// versionTemplate is the version template defined by user.
 	versionTemplate string
+
+	// inReader is a reader defined by the user that replaces stdin
+	inReader io.Reader
+	// outWriter is a writer defined by the user that replaces stdout
+	outWriter io.Writer
+	// errWriter is a writer defined by the user that replaces stderr
+	errWriter io.Writer
 }
 
 // SetArgs sets arguments for the command. It is set to os.Args[1:] by default, if desired, can be overridden
@@ -205,8 +210,28 @@ func (c *Command) SetArgs(a []string) {
 
 // SetOutput sets the destination for usage and error messages.
 // If output is nil, os.Stderr is used.
+// Deprecated: Use SetOut and/or SetErr instead
 func (c *Command) SetOutput(output io.Writer) {
-	c.output = output
+	c.outWriter = output
+	c.errWriter = output
+}
+
+// SetOut sets the destination for usage messages.
+// If newOut is nil, os.Stdout is used.
+func (c *Command) SetOut(newOut io.Writer) {
+	c.outWriter = newOut
+}
+
+// SetErr sets the destination for error messages.
+// If newErr is nil, os.Stderr is used.
+func (c *Command) SetErr(newErr io.Writer) {
+	c.errWriter = newErr
+}
+
+// SetOut sets the source for input data
+// If newIn is nil, os.Stdin is used.
+func (c *Command) SetIn(newIn io.Reader) {
+	c.inReader = newIn
 }
 
 // SetUsageFunc sets usage function. Usage can be defined by application.
@@ -267,9 +292,19 @@ func (c *Command) OutOrStderr() io.Writer {
 	return c.getOut(os.Stderr)
 }
 
+// ErrOrStderr returns output to stderr
+func (c *Command) ErrOrStderr() io.Writer {
+	return c.getErr(os.Stderr)
+}
+
+// ErrOrStderr returns output to stderr
+func (c *Command) InOrStdin() io.Reader {
+	return c.getIn(os.Stdin)
+}
+
 func (c *Command) getOut(def io.Writer) io.Writer {
-	if c.output != nil {
-		return c.output
+	if c.outWriter != nil {
+		return c.outWriter
 	}
 	if c.HasParent() {
 		return c.parent.getOut(def)
@@ -277,6 +312,26 @@ func (c *Command) getOut(def io.Writer) io.Writer {
 	return def
 }
 
+func (c *Command) getErr(def io.Writer) io.Writer {
+	if c.errWriter != nil {
+		return c.errWriter
+	}
+	if c.HasParent() {
+		return c.parent.getErr(def)
+	}
+	return def
+}
+
+func (c *Command) getIn(def io.Reader) io.Reader {
+	if c.inReader != nil {
+		return c.inReader
+	}
+	if c.HasParent() {
+		return c.parent.getIn(def)
+	}
+	return def
+}
+
 // UsageFunc returns either the function set by SetUsageFunc for this command
 // or a parent, or it returns a default usage function.
 func (c *Command) UsageFunc() (f func(*Command) error) {
@@ -329,13 +384,22 @@ func (c *Command) Help() error {
 	return nil
 }
 
-// UsageString return usage string.
+// UsageString returns usage string.
 func (c *Command) UsageString() string {
-	tmpOutput := c.output
+	// Storing normal writers
+	tmpOutput := c.outWriter
+	tmpErr := c.errWriter
+
 	bb := new(bytes.Buffer)
-	c.SetOutput(bb)
+	c.outWriter = bb
+	c.errWriter = bb
+
 	c.Usage()
-	c.output = tmpOutput
+
+	// Setting things back to normal
+	c.outWriter = tmpOutput
+	c.errWriter = tmpErr
+
 	return bb.String()
 }
 
@@ -1068,6 +1132,21 @@ func (c *Command) Printf(format string, i ...interface{}) {
 	c.Print(fmt.Sprintf(format, i...))
 }
 
+// PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set.
+func (c *Command) PrintErr(i ...interface{}) {
+	fmt.Fprint(c.ErrOrStderr(), i...)
+}
+
+// PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set.
+func (c *Command) PrintErrln(i ...interface{}) {
+	c.Print(fmt.Sprintln(i...))
+}
+
+// PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set.
+func (c *Command) PrintErrf(format string, i ...interface{}) {
+	c.Print(fmt.Sprintf(format, i...))
+}
+
 // CommandPath returns the full path to this command.
 func (c *Command) CommandPath() string {
 	if c.HasParent() {

vendor/github.com/spf13/cobra/powershell_completions.go 🔗

@@ -0,0 +1,100 @@
+// PowerShell completions are based on the amazing work from clap:
+// https://github.com/clap-rs/clap/blob/3294d18efe5f264d12c9035f404c7d189d4824e1/src/completions/powershell.rs
+//
+// The generated scripts require PowerShell v5.0+ (which comes Windows 10, but
+// can be downloaded separately for windows 7 or 8.1).
+
+package cobra
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+
+	"github.com/spf13/pflag"
+)
+
+var powerShellCompletionTemplate = `using namespace System.Management.Automation
+using namespace System.Management.Automation.Language
+Register-ArgumentCompleter -Native -CommandName '%s' -ScriptBlock {
+    param($wordToComplete, $commandAst, $cursorPosition)
+    $commandElements = $commandAst.CommandElements
+    $command = @(
+        '%s'
+        for ($i = 1; $i -lt $commandElements.Count; $i++) {
+            $element = $commandElements[$i]
+            if ($element -isnot [StringConstantExpressionAst] -or
+                $element.StringConstantType -ne [StringConstantType]::BareWord -or
+                $element.Value.StartsWith('-')) {
+                break
+            }
+            $element.Value
+        }
+    ) -join ';'
+    $completions = @(switch ($command) {%s
+    })
+    $completions.Where{ $_.CompletionText -like "$wordToComplete*" } |
+        Sort-Object -Property ListItemText
+}`
+
+func generatePowerShellSubcommandCases(out io.Writer, cmd *Command, previousCommandName string) {
+	var cmdName string
+	if previousCommandName == "" {
+		cmdName = cmd.Name()
+	} else {
+		cmdName = fmt.Sprintf("%s;%s", previousCommandName, cmd.Name())
+	}
+
+	fmt.Fprintf(out, "\n        '%s' {", cmdName)
+
+	cmd.Flags().VisitAll(func(flag *pflag.Flag) {
+		if nonCompletableFlag(flag) {
+			return
+		}
+		usage := escapeStringForPowerShell(flag.Usage)
+		if len(flag.Shorthand) > 0 {
+			fmt.Fprintf(out, "\n            [CompletionResult]::new('-%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Shorthand, flag.Shorthand, usage)
+		}
+		fmt.Fprintf(out, "\n            [CompletionResult]::new('--%s', '%s', [CompletionResultType]::ParameterName, '%s')", flag.Name, flag.Name, usage)
+	})
+
+	for _, subCmd := range cmd.Commands() {
+		usage := escapeStringForPowerShell(subCmd.Short)
+		fmt.Fprintf(out, "\n            [CompletionResult]::new('%s', '%s', [CompletionResultType]::ParameterValue, '%s')", subCmd.Name(), subCmd.Name(), usage)
+	}
+
+	fmt.Fprint(out, "\n            break\n        }")
+
+	for _, subCmd := range cmd.Commands() {
+		generatePowerShellSubcommandCases(out, subCmd, cmdName)
+	}
+}
+
+func escapeStringForPowerShell(s string) string {
+	return strings.Replace(s, "'", "''", -1)
+}
+
+// GenPowerShellCompletion generates PowerShell completion file and writes to the passed writer.
+func (c *Command) GenPowerShellCompletion(w io.Writer) error {
+	buf := new(bytes.Buffer)
+
+	var subCommandCases bytes.Buffer
+	generatePowerShellSubcommandCases(&subCommandCases, c, "")
+	fmt.Fprintf(buf, powerShellCompletionTemplate, c.Name(), c.Name(), subCommandCases.String())
+
+	_, err := buf.WriteTo(w)
+	return err
+}
+
+// GenPowerShellCompletionFile generates PowerShell completion file.
+func (c *Command) GenPowerShellCompletionFile(filename string) error {
+	outFile, err := os.Create(filename)
+	if err != nil {
+		return err
+	}
+	defer outFile.Close()
+
+	return c.GenPowerShellCompletion(outFile)
+}

vendor/github.com/spf13/cobra/powershell_completions.md 🔗

@@ -0,0 +1,14 @@
+# Generating PowerShell Completions For Your Own cobra.Command
+
+Cobra can generate PowerShell completion scripts. Users need PowerShell version 5.0 or above, which comes with Windows 10 and can be downloaded separately for Windows 7 or 8.1. They can then write the completions to a file and source this file from their PowerShell profile, which is referenced by the `$Profile` environment variable. See `Get-Help about_Profiles` for more info about PowerShell profiles.
+
+# What's supported
+
+- Completion for subcommands using their `.Short` description
+- Completion for non-hidden flags using their `.Name` and `.Shorthand`
+
+# What's not yet supported
+
+- Command aliases
+- Required, filename or custom flags (they will work like normal flags)
+- Custom completion scripts

vendor/github.com/spf13/cobra/shell_completions.go 🔗

@@ -0,0 +1,85 @@
+package cobra
+
+import (
+	"github.com/spf13/pflag"
+)
+
+// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
+// and causes your command to report an error if invoked without the flag.
+func (c *Command) MarkFlagRequired(name string) error {
+	return MarkFlagRequired(c.Flags(), name)
+}
+
+// MarkPersistentFlagRequired adds the BashCompOneRequiredFlag annotation to the named persistent flag if it exists,
+// and causes your command to report an error if invoked without the flag.
+func (c *Command) MarkPersistentFlagRequired(name string) error {
+	return MarkFlagRequired(c.PersistentFlags(), name)
+}
+
+// MarkFlagRequired adds the BashCompOneRequiredFlag annotation to the named flag if it exists,
+// and causes your command to report an error if invoked without the flag.
+func MarkFlagRequired(flags *pflag.FlagSet, name string) error {
+	return flags.SetAnnotation(name, BashCompOneRequiredFlag, []string{"true"})
+}
+
+// MarkFlagFilename adds the BashCompFilenameExt annotation to the named flag, if it exists.
+// Generated bash autocompletion will select filenames for the flag, limiting to named extensions if provided.
+func (c *Command) MarkFlagFilename(name string, extensions ...string) error {
+	return MarkFlagFilename(c.Flags(), name, extensions...)
+}
+
+// MarkFlagCustom adds the BashCompCustom annotation to the named flag, if it exists.
+// Generated bash autocompletion will call the bash function f for the flag.
+func (c *Command) MarkFlagCustom(name string, f string) error {
+	return MarkFlagCustom(c.Flags(), name, f)
+}
+
+// MarkPersistentFlagFilename instructs the various shell completion
+// implementations to limit completions for this persistent flag to the
+// specified extensions (patterns).
+//
+// Shell Completion compatibility matrix: bash, zsh
+func (c *Command) MarkPersistentFlagFilename(name string, extensions ...string) error {
+	return MarkFlagFilename(c.PersistentFlags(), name, extensions...)
+}
+
+// MarkFlagFilename instructs the various shell completion implementations to
+// limit completions for this flag to the specified extensions (patterns).
+//
+// Shell Completion compatibility matrix: bash, zsh
+func MarkFlagFilename(flags *pflag.FlagSet, name string, extensions ...string) error {
+	return flags.SetAnnotation(name, BashCompFilenameExt, extensions)
+}
+
+// MarkFlagCustom instructs the various shell completion implementations to
+// limit completions for this flag to the specified extensions (patterns).
+//
+// Shell Completion compatibility matrix: bash, zsh
+func MarkFlagCustom(flags *pflag.FlagSet, name string, f string) error {
+	return flags.SetAnnotation(name, BashCompCustom, []string{f})
+}
+
+// MarkFlagDirname instructs the various shell completion implementations to
+// complete only directories with this named flag.
+//
+// Shell Completion compatibility matrix: zsh
+func (c *Command) MarkFlagDirname(name string) error {
+	return MarkFlagDirname(c.Flags(), name)
+}
+
+// MarkPersistentFlagDirname instructs the various shell completion
+// implementations to complete only directories with this persistent named flag.
+//
+// Shell Completion compatibility matrix: zsh
+func (c *Command) MarkPersistentFlagDirname(name string) error {
+	return MarkFlagDirname(c.PersistentFlags(), name)
+}
+
+// MarkFlagDirname instructs the various shell completion implementations to
+// complete only directories with this specified flag.
+//
+// Shell Completion compatibility matrix: zsh
+func MarkFlagDirname(flags *pflag.FlagSet, name string) error {
+	zshPattern := "-(/)"
+	return flags.SetAnnotation(name, zshCompDirname, []string{zshPattern})
+}

vendor/github.com/spf13/cobra/zsh_completions.go 🔗

@@ -1,14 +1,102 @@
 package cobra
 
 import (
-	"bytes"
+	"encoding/json"
 	"fmt"
 	"io"
 	"os"
 	"sort"
 	"strings"
+	"text/template"
+
+	"github.com/spf13/pflag"
+)
+
+const (
+	zshCompArgumentAnnotation   = "cobra_annotations_zsh_completion_argument_annotation"
+	zshCompArgumentFilenameComp = "cobra_annotations_zsh_completion_argument_file_completion"
+	zshCompArgumentWordComp     = "cobra_annotations_zsh_completion_argument_word_completion"
+	zshCompDirname              = "cobra_annotations_zsh_dirname"
+)
+
+var (
+	zshCompFuncMap = template.FuncMap{
+		"genZshFuncName":              zshCompGenFuncName,
+		"extractFlags":                zshCompExtractFlag,
+		"genFlagEntryForZshArguments": zshCompGenFlagEntryForArguments,
+		"extractArgsCompletions":      zshCompExtractArgumentCompletionHintsForRendering,
+	}
+	zshCompletionText = `
+{{/* should accept Command (that contains subcommands) as parameter */}}
+{{define "argumentsC" -}}
+{{ $cmdPath := genZshFuncName .}}
+function {{$cmdPath}} {
+  local -a commands
+
+  _arguments -C \{{- range extractFlags .}}
+    {{genFlagEntryForZshArguments .}} \{{- end}}
+    "1: :->cmnds" \
+    "*::arg:->args"
+
+  case $state in
+  cmnds)
+    commands=({{range .Commands}}{{if not .Hidden}}
+      "{{.Name}}:{{.Short}}"{{end}}{{end}}
+    )
+    _describe "command" commands
+    ;;
+  esac
+
+  case "$words[1]" in {{- range .Commands}}{{if not .Hidden}}
+  {{.Name}})
+    {{$cmdPath}}_{{.Name}}
+    ;;{{end}}{{end}}
+  esac
+}
+{{range .Commands}}{{if not .Hidden}}
+{{template "selectCmdTemplate" .}}
+{{- end}}{{end}}
+{{- end}}
+
+{{/* should accept Command without subcommands as parameter */}}
+{{define "arguments" -}}
+function {{genZshFuncName .}} {
+{{"  _arguments"}}{{range extractFlags .}} \
+    {{genFlagEntryForZshArguments . -}}
+{{end}}{{range extractArgsCompletions .}} \
+    {{.}}{{end}}
+}
+{{end}}
+
+{{/* dispatcher for commands with or without subcommands */}}
+{{define "selectCmdTemplate" -}}
+{{if .Hidden}}{{/* ignore hidden*/}}{{else -}}
+{{if .Commands}}{{template "argumentsC" .}}{{else}}{{template "arguments" .}}{{end}}
+{{- end}}
+{{- end}}
+
+{{/* template entry point */}}
+{{define "Main" -}}
+#compdef _{{.Name}} {{.Name}}
+
+{{template "selectCmdTemplate" .}}
+{{end}}
+`
 )
 
+// zshCompArgsAnnotation is used to encode/decode zsh completion for
+// arguments to/from Command.Annotations.
+type zshCompArgsAnnotation map[int]zshCompArgHint
+
+type zshCompArgHint struct {
+	// Indicates the type of the completion to use. One of:
+	// zshCompArgumentFilenameComp or zshCompArgumentWordComp
+	Tipe string `json:"type"`
+
+	// A value for the type above (globs for file completion or words)
+	Options []string `json:"options"`
+}
+
 // GenZshCompletionFile generates zsh completion file.
 func (c *Command) GenZshCompletionFile(filename string) error {
 	outFile, err := os.Create(filename)
@@ -20,116 +108,229 @@ func (c *Command) GenZshCompletionFile(filename string) error {
 	return c.GenZshCompletion(outFile)
 }
 
-// GenZshCompletion generates a zsh completion file and writes to the passed writer.
+// GenZshCompletion generates a zsh completion file and writes to the passed
+// writer. The completion always run on the root command regardless of the
+// command it was called from.
 func (c *Command) GenZshCompletion(w io.Writer) error {
-	buf := new(bytes.Buffer)
-
-	writeHeader(buf, c)
-	maxDepth := maxDepth(c)
-	writeLevelMapping(buf, maxDepth)
-	writeLevelCases(buf, maxDepth, c)
+	tmpl, err := template.New("Main").Funcs(zshCompFuncMap).Parse(zshCompletionText)
+	if err != nil {
+		return fmt.Errorf("error creating zsh completion template: %v", err)
+	}
+	return tmpl.Execute(w, c.Root())
+}
 
-	_, err := buf.WriteTo(w)
-	return err
+// MarkZshCompPositionalArgumentFile marks the specified argument (first
+// argument is 1) as completed by file selection. patterns (e.g. "*.txt") are
+// optional - if not provided the completion will search for all files.
+func (c *Command) MarkZshCompPositionalArgumentFile(argPosition int, patterns ...string) error {
+	if argPosition < 1 {
+		return fmt.Errorf("Invalid argument position (%d)", argPosition)
+	}
+	annotation, err := c.zshCompGetArgsAnnotations()
+	if err != nil {
+		return err
+	}
+	if c.zshcompArgsAnnotationnIsDuplicatePosition(annotation, argPosition) {
+		return fmt.Errorf("Duplicate annotation for positional argument at index %d", argPosition)
+	}
+	annotation[argPosition] = zshCompArgHint{
+		Tipe:    zshCompArgumentFilenameComp,
+		Options: patterns,
+	}
+	return c.zshCompSetArgsAnnotations(annotation)
 }
 
-func writeHeader(w io.Writer, cmd *Command) {
-	fmt.Fprintf(w, "#compdef %s\n\n", cmd.Name())
+// MarkZshCompPositionalArgumentWords marks the specified positional argument
+// (first argument is 1) as completed by the provided words. At east one word
+// must be provided, spaces within words will be offered completion with
+// "word\ word".
+func (c *Command) MarkZshCompPositionalArgumentWords(argPosition int, words ...string) error {
+	if argPosition < 1 {
+		return fmt.Errorf("Invalid argument position (%d)", argPosition)
+	}
+	if len(words) == 0 {
+		return fmt.Errorf("Trying to set empty word list for positional argument %d", argPosition)
+	}
+	annotation, err := c.zshCompGetArgsAnnotations()
+	if err != nil {
+		return err
+	}
+	if c.zshcompArgsAnnotationnIsDuplicatePosition(annotation, argPosition) {
+		return fmt.Errorf("Duplicate annotation for positional argument at index %d", argPosition)
+	}
+	annotation[argPosition] = zshCompArgHint{
+		Tipe:    zshCompArgumentWordComp,
+		Options: words,
+	}
+	return c.zshCompSetArgsAnnotations(annotation)
 }
 
-func maxDepth(c *Command) int {
-	if len(c.Commands()) == 0 {
-		return 0
+func zshCompExtractArgumentCompletionHintsForRendering(c *Command) ([]string, error) {
+	var result []string
+	annotation, err := c.zshCompGetArgsAnnotations()
+	if err != nil {
+		return nil, err
 	}
-	maxDepthSub := 0
-	for _, s := range c.Commands() {
-		subDepth := maxDepth(s)
-		if subDepth > maxDepthSub {
-			maxDepthSub = subDepth
+	for k, v := range annotation {
+		s, err := zshCompRenderZshCompArgHint(k, v)
+		if err != nil {
+			return nil, err
 		}
+		result = append(result, s)
 	}
-	return 1 + maxDepthSub
+	if len(c.ValidArgs) > 0 {
+		if _, positionOneExists := annotation[1]; !positionOneExists {
+			s, err := zshCompRenderZshCompArgHint(1, zshCompArgHint{
+				Tipe:    zshCompArgumentWordComp,
+				Options: c.ValidArgs,
+			})
+			if err != nil {
+				return nil, err
+			}
+			result = append(result, s)
+		}
+	}
+	sort.Strings(result)
+	return result, nil
 }
 
-func writeLevelMapping(w io.Writer, numLevels int) {
-	fmt.Fprintln(w, `_arguments \`)
-	for i := 1; i <= numLevels; i++ {
-		fmt.Fprintf(w, `  '%d: :->level%d' \`, i, i)
-		fmt.Fprintln(w)
+func zshCompRenderZshCompArgHint(i int, z zshCompArgHint) (string, error) {
+	switch t := z.Tipe; t {
+	case zshCompArgumentFilenameComp:
+		var globs []string
+		for _, g := range z.Options {
+			globs = append(globs, fmt.Sprintf(`-g "%s"`, g))
+		}
+		return fmt.Sprintf(`'%d: :_files %s'`, i, strings.Join(globs, " ")), nil
+	case zshCompArgumentWordComp:
+		var words []string
+		for _, w := range z.Options {
+			words = append(words, fmt.Sprintf("%q", w))
+		}
+		return fmt.Sprintf(`'%d: :(%s)'`, i, strings.Join(words, " ")), nil
+	default:
+		return "", fmt.Errorf("Invalid zsh argument completion annotation: %s", t)
 	}
-	fmt.Fprintf(w, `  '%d: :%s'`, numLevels+1, "_files")
-	fmt.Fprintln(w)
 }
 
-func writeLevelCases(w io.Writer, maxDepth int, root *Command) {
-	fmt.Fprintln(w, "case $state in")
-	defer fmt.Fprintln(w, "esac")
+func (c *Command) zshcompArgsAnnotationnIsDuplicatePosition(annotation zshCompArgsAnnotation, position int) bool {
+	_, dup := annotation[position]
+	return dup
+}
 
-	for i := 1; i <= maxDepth; i++ {
-		fmt.Fprintf(w, "  level%d)\n", i)
-		writeLevel(w, root, i)
-		fmt.Fprintln(w, "  ;;")
+func (c *Command) zshCompGetArgsAnnotations() (zshCompArgsAnnotation, error) {
+	annotation := make(zshCompArgsAnnotation)
+	annotationString, ok := c.Annotations[zshCompArgumentAnnotation]
+	if !ok {
+		return annotation, nil
+	}
+	err := json.Unmarshal([]byte(annotationString), &annotation)
+	if err != nil {
+		return annotation, fmt.Errorf("Error unmarshaling zsh argument annotation: %v", err)
 	}
-	fmt.Fprintln(w, "  *)")
-	fmt.Fprintln(w, "    _arguments '*: :_files'")
-	fmt.Fprintln(w, "  ;;")
+	return annotation, nil
 }
 
-func writeLevel(w io.Writer, root *Command, i int) {
-	fmt.Fprintf(w, "    case $words[%d] in\n", i)
-	defer fmt.Fprintln(w, "    esac")
-
-	commands := filterByLevel(root, i)
-	byParent := groupByParent(commands)
+func (c *Command) zshCompSetArgsAnnotations(annotation zshCompArgsAnnotation) error {
+	jsn, err := json.Marshal(annotation)
+	if err != nil {
+		return fmt.Errorf("Error marshaling zsh argument annotation: %v", err)
+	}
+	if c.Annotations == nil {
+		c.Annotations = make(map[string]string)
+	}
+	c.Annotations[zshCompArgumentAnnotation] = string(jsn)
+	return nil
+}
 
-	// sort the parents to keep a determinist order
-	parents := make([]string, len(byParent))
-	j := 0
-	for parent := range byParent {
-		parents[j] = parent
-		j++
+func zshCompGenFuncName(c *Command) string {
+	if c.HasParent() {
+		return zshCompGenFuncName(c.Parent()) + "_" + c.Name()
 	}
-	sort.StringSlice(parents).Sort()
+	return "_" + c.Name()
+}
+
+func zshCompExtractFlag(c *Command) []*pflag.Flag {
+	var flags []*pflag.Flag
+	c.LocalFlags().VisitAll(func(f *pflag.Flag) {
+		if !f.Hidden {
+			flags = append(flags, f)
+		}
+	})
+	c.InheritedFlags().VisitAll(func(f *pflag.Flag) {
+		if !f.Hidden {
+			flags = append(flags, f)
+		}
+	})
+	return flags
+}
 
-	for _, parent := range parents {
-		names := names(byParent[parent])
-		fmt.Fprintf(w, "      %s)\n", parent)
-		fmt.Fprintf(w, "        _arguments '%d: :(%s)'\n", i, strings.Join(names, " "))
-		fmt.Fprintln(w, "      ;;")
+// zshCompGenFlagEntryForArguments returns an entry that matches _arguments
+// zsh-completion parameters. It's too complicated to generate in a template.
+func zshCompGenFlagEntryForArguments(f *pflag.Flag) string {
+	if f.Name == "" || f.Shorthand == "" {
+		return zshCompGenFlagEntryForSingleOptionFlag(f)
 	}
-	fmt.Fprintln(w, "      *)")
-	fmt.Fprintln(w, "        _arguments '*: :_files'")
-	fmt.Fprintln(w, "      ;;")
+	return zshCompGenFlagEntryForMultiOptionFlag(f)
 }
 
-func filterByLevel(c *Command, l int) []*Command {
-	cs := make([]*Command, 0)
-	if l == 0 {
-		cs = append(cs, c)
-		return cs
+func zshCompGenFlagEntryForSingleOptionFlag(f *pflag.Flag) string {
+	var option, multiMark, extras string
+
+	if zshCompFlagCouldBeSpecifiedMoreThenOnce(f) {
+		multiMark = "*"
 	}
-	for _, s := range c.Commands() {
-		cs = append(cs, filterByLevel(s, l-1)...)
+
+	option = "--" + f.Name
+	if option == "--" {
+		option = "-" + f.Shorthand
 	}
-	return cs
+	extras = zshCompGenFlagEntryExtras(f)
+
+	return fmt.Sprintf(`'%s%s[%s]%s'`, multiMark, option, zshCompQuoteFlagDescription(f.Usage), extras)
 }
 
-func groupByParent(commands []*Command) map[string][]*Command {
-	m := make(map[string][]*Command)
-	for _, c := range commands {
-		parent := c.Parent()
-		if parent == nil {
-			continue
-		}
-		m[parent.Name()] = append(m[parent.Name()], c)
+func zshCompGenFlagEntryForMultiOptionFlag(f *pflag.Flag) string {
+	var options, parenMultiMark, curlyMultiMark, extras string
+
+	if zshCompFlagCouldBeSpecifiedMoreThenOnce(f) {
+		parenMultiMark = "*"
+		curlyMultiMark = "\\*"
 	}
-	return m
+
+	options = fmt.Sprintf(`'(%s-%s %s--%s)'{%s-%s,%s--%s}`,
+		parenMultiMark, f.Shorthand, parenMultiMark, f.Name, curlyMultiMark, f.Shorthand, curlyMultiMark, f.Name)
+	extras = zshCompGenFlagEntryExtras(f)
+
+	return fmt.Sprintf(`%s'[%s]%s'`, options, zshCompQuoteFlagDescription(f.Usage), extras)
 }
 
-func names(commands []*Command) []string {
-	ns := make([]string, len(commands))
-	for i, c := range commands {
-		ns[i] = c.Name()
+func zshCompGenFlagEntryExtras(f *pflag.Flag) string {
+	if f.NoOptDefVal != "" {
+		return ""
 	}
-	return ns
+
+	extras := ":" // allow options for flag (even without assistance)
+	for key, values := range f.Annotations {
+		switch key {
+		case zshCompDirname:
+			extras = fmt.Sprintf(":filename:_files -g %q", values[0])
+		case BashCompFilenameExt:
+			extras = ":filename:_files"
+			for _, pattern := range values {
+				extras = extras + fmt.Sprintf(` -g "%s"`, pattern)
+			}
+		}
+	}
+
+	return extras
+}
+
+func zshCompFlagCouldBeSpecifiedMoreThenOnce(f *pflag.Flag) bool {
+	return strings.Contains(f.Value.Type(), "Slice") ||
+		strings.Contains(f.Value.Type(), "Array")
+}
+
+func zshCompQuoteFlagDescription(s string) string {
+	return strings.Replace(s, "'", `'\''`, -1)
 }

vendor/github.com/spf13/cobra/zsh_completions.md 🔗

@@ -0,0 +1,39 @@
+## Generating Zsh Completion for your cobra.Command
+
+Cobra supports native Zsh completion generated from the root `cobra.Command`.
+The generated completion script should be put somewhere in your `$fpath` named
+`_<YOUR COMMAND>`.
+
+### What's Supported
+
+* Completion for all non-hidden subcommands using their `.Short` description.
+* Completion for all non-hidden flags using the following rules:
+  * Filename completion works by marking the flag with `cmd.MarkFlagFilename...`
+    family of commands.
+  * The requirement for argument to the flag is decided by the `.NoOptDefVal`
+    flag value - if it's empty then completion will expect an argument.
+  * Flags of one of the various `*Array` and `*Slice` types supports multiple
+    specifications (with or without argument depending on the specific type).
+* Completion of positional arguments using the following rules:
+  * Argument position for all options below starts at `1`. If argument position
+    `0` is requested it will raise an error.
+  * Use `command.MarkZshCompPositionalArgumentFile` to complete filenames. Glob
+    patterns (e.g. `"*.log"`) are optional - if not specified it will offer to
+    complete all file types.
+  * Use `command.MarkZshCompPositionalArgumentWords` to offer specific words for
+    completion. At least one word is required.
+  * It's possible to specify completion for some arguments and leave some
+    unspecified (e.g. offer words for second argument but nothing for first
+    argument). This will cause no completion for first argument but words
+    completion for second argument.
+  * If no argument completion was specified for 1st argument (but optionally was
+    specified for 2nd) and the command has `ValidArgs` it will be used as
+    completion options for 1st argument.
+  * Argument completions only offered for commands with no subcommands.
+
+### What's not yet Supported
+
+* Custom completion scripts are not supported yet (We should probably create zsh
+  specific one, doesn't make sense to re-use the bash one as the functions will
+  be different).
+* Whatever other feature you're looking for and doesn't exist :)