Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds autocompletion support for zsh and bash #341

Merged
merged 4 commits into from
Jan 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 61 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ The Temporal CLI is a command-line tool you can use to perform various tasks on
Documentation for the Temporal command line interface is located at our [main site](https://docs.temporal.io/docs/system-tools/tctl).

## Quick Start
Run `make` from the project root. You should see an executable file called `tctl`. Try a few example commands to
get started:
`./tctl` for help on top level commands and global options

Run `make` from the project root. You should see an executable file called `tctl`. Try a few example commands to
get started:
`./tctl` for help on top level commands and global options
`./tctl namespace` for help on namespace operations
`./tctl workflow` for help on workflow operations
`./tctl task-queue` for help on tasklist operations
Expand Down Expand Up @@ -35,6 +36,63 @@ To switch back to the stable v1, run
tctl config set version current
```

## Auto-completion

Running `tctl completion SHELL` will output the related completion SHELL code. See the following
sections for more details for each specific shell / OS and how to enable it.

### zsh auto-completion

Add the following to your `~/.zshrc` file:

```sh
source <(tctl completion zsh)
```

or from your terminal run:

```sh
echo 'source <(tctl completion zsh)' >> ~/.zshrc
```

Then run `source ~/.zshrc`.

### Bash auto-completion (linux)

Bash auto-completion relies on [bash-completion](https://github.com/scop/bash-completion#installation). Make sure
you follow the instruction [here](https://github.com/scop/bash-completion#installation) and install the software or
use a package manager to install it like `apt-get install bash-completion` or `yum install bash-completion`, etc. For example
on alpine linux:

- apk update
- apk add bash-completion
- source /etc/profile.d/bash_completion.sh

Verify that bash-completion is installed by running `type _init_completion` add the following to your `.bashrc`
file to enable completion for tctl

```
echo 'source <(tctl completion bash)' >>~/.bashrc
source ~/.bashrc
```

### Bash auto-completion (macos)

For macos you can install it via brew `brew install bash-completion@2` and add the following line to
your `~/.bashrc`:

```sh
[[ -r "/usr/local/etc/profile.d/bash_completion.sh" ]] && . "/usr/local/etc/profile.d/bash_completion.sh"
```

Verify that bash-completion is installed by running `type _init_completion` and add the following to your `.bashrc`
file to enable completion for tctl

```
echo 'source <(tctl completion bash)' >> ~/.bashrc
source ~/.bashrc
```

## License

MIT License, please see [LICENSE](https://github.com/temporalio/tctl/blob/master/LICENSE) for details.
1 change: 1 addition & 0 deletions cli/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func NewCliApp() *cli.App {
app.Name = "tctl"
app.Usage = "A command-line tool for Temporal users"
app.Version = "next"
app.EnableBashCompletion = true
app.Flags = []cli.Flag{
&cli.StringFlag{
Name: FlagAddress,
Expand Down
1 change: 1 addition & 0 deletions cli/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,5 @@ var tctlCommands = []*cli.Command{
Usage: "Create an alias for a command",
Subcommands: newAliasCommand(),
},
newCompletionCommand(),
}
53 changes: 53 additions & 0 deletions cli/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// The MIT License
//
// Copyright (c) 2022 Temporal Technologies Inc. All rights reserved.
//
// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cli

import (
"github.com/temporalio/tctl/completion"

"github.com/urfave/cli/v2"
)

func newCompletionCommand() *cli.Command {
var subCommands = []*cli.Command{}
for _, shell := range completion.CommandConfig.Shells {
cmd := &cli.Command{
Name: string(shell.Name),
Usage: shell.Usage,
Action: func(c *cli.Context) error {
shell.Print()
return nil
},

}
subCommands = append(subCommands, cmd)
}

return &cli.Command{
Name: completion.CommandConfig.Name,
Usage: completion.CommandConfig.Usage,
Subcommands: subCommands,
}
}
2 changes: 2 additions & 0 deletions cli_curr/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ func NewCliApp() *cli.App {
app.Name = "tctl"
app.Usage = "A command-line tool for Temporal users"
app.Version = headers.CLIVersion
app.EnableBashCompletion = true
app.Flags = []cli.Flag{
cli.StringFlag{
Name: FlagAddressWithAlias,
Expand Down Expand Up @@ -247,6 +248,7 @@ func NewCliApp() *cli.App {
Usage: "Configure tctl",
Subcommands: newConfigCommands(),
},
newCompletionCommand(),
}
app.Before = configureSDK
app.After = stopPlugins
Expand Down
53 changes: 53 additions & 0 deletions cli_curr/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// The MIT License
//
// Copyright (c) 2022 Temporal Technologies Inc. All rights reserved.
//
// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package cli_curr

import (
"github.com/temporalio/tctl/completion"
"github.com/urfave/cli"
)


func newCompletionCommand() cli.Command {
var subCommands = []cli.Command{}
for _, shell := range completion.CommandConfig.Shells {
cmd := cli.Command{
Name: string(shell.Name),
Usage: shell.Usage,
Action: func(c *cli.Context) error {
shell.Print()
return nil
},

}
subCommands = append(subCommands, cmd)
}

return cli.Command{
Name: completion.CommandConfig.Name,
Usage: completion.CommandConfig.Usage,
Subcommands: subCommands,
}
}
120 changes: 120 additions & 0 deletions completion/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// The MIT License
//
// Copyright (c) 2022 Temporal Technologies Inc. All rights reserved.
//
// Copyright (c) 2020 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

package completion

import (
"fmt"
"os"
)

// taken from https://github.com/urfave/cli/blob/master/autocomplete/zsh_autocomplete
var zsh_script = `
#compdef tctl

_cli_zsh_autocomplete() {

local -a opts
local cur
cur=${words[-1]}
if [[ "$cur" == "-"* ]]; then
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} ${cur} --generate-bash-completion)}")
else
opts=("${(@f)$(_CLI_ZSH_AUTOCOMPLETE_HACK=1 ${words[@]:0:#words[@]-1} --generate-bash-completion)}")
fi

if [[ "${opts[1]}" != "" ]]; then
_describe 'values' opts
else
_files
fi

return
}
compdef _cli_zsh_autocomplete tctl
`

var bash_script = `
#! /bin/bash

_cli_bash_autocomplete() {
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
local cur opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ "$cur" == "-"* ]]; then
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --generate-bash-completion )
else
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --generate-bash-completion )
fi
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
}

complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete tctl
`

var (
schellScriptMap = map[string]func() {
"bash": func() { fmt.Fprintln(os.Stdout, bash_script) },
"zsh": func() { fmt.Fprintln(os.Stdout, zsh_script) },
}
)

type Shell string

const (
BASH Shell = "bash"
ZSH Shell = "zsh"
)
type shellConfig struct {
Name Shell
Usage string
}

type commandConfig struct {
Name string
Usage string
Shells []shellConfig
}

func (s shellConfig) Print() {
schellScriptMap[string(s.Name)]()
}

var CommandConfig commandConfig = commandConfig{
Name: "completion",
Usage: "Output shell completion code for the specified shell (zsh, bash)",
Shells: []shellConfig {
{
Name: ZSH,
Usage: "zsh completion output",
},
{
Name: BASH,
Usage: "bash completion output",
},
},
}