From 9b61d347608cd8d7989a9eee251bba97b346ebbd Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Wed, 12 Aug 2020 13:09:09 -0500 Subject: [PATCH 1/4] Move cmd to internal package --- cmd/coder/main.go | 73 +-------------------- {cmd/coder => internal/cmd}/auth.go | 2 +- {cmd/coder => internal/cmd}/ceapi.go | 2 +- internal/cmd/cmd.go | 80 ++++++++++++++++++++++++ {cmd/coder => internal/cmd}/configssh.go | 2 +- {cmd/coder => internal/cmd}/envs.go | 2 +- {cmd/coder => internal/cmd}/login.go | 2 +- {cmd/coder => internal/cmd}/logout.go | 2 +- {cmd/coder => internal/cmd}/secrets.go | 2 +- {cmd/coder => internal/cmd}/shell.go | 2 +- {cmd/coder => internal/cmd}/sync.go | 2 +- {cmd/coder => internal/cmd}/urls.go | 2 +- {cmd/coder => internal/cmd}/users.go | 2 +- 13 files changed, 94 insertions(+), 81 deletions(-) rename {cmd/coder => internal/cmd}/auth.go (98%) rename {cmd/coder => internal/cmd}/ceapi.go (99%) create mode 100644 internal/cmd/cmd.go rename {cmd/coder => internal/cmd}/configssh.go (99%) rename {cmd/coder => internal/cmd}/envs.go (99%) rename {cmd/coder => internal/cmd}/login.go (99%) rename {cmd/coder => internal/cmd}/logout.go (97%) rename {cmd/coder => internal/cmd}/secrets.go (99%) rename {cmd/coder => internal/cmd}/shell.go (99%) rename {cmd/coder => internal/cmd}/sync.go (99%) rename {cmd/coder => internal/cmd}/urls.go (99%) rename {cmd/coder => internal/cmd}/users.go (99%) diff --git a/cmd/coder/main.go b/cmd/coder/main.go index 5cf3454b..5ed4344b 100644 --- a/cmd/coder/main.go +++ b/cmd/coder/main.go @@ -9,8 +9,8 @@ import ( "os" "runtime" + "cdr.dev/coder-cli/internal/cmd" "cdr.dev/coder-cli/internal/x/xterminal" - "github.com/spf13/cobra" "go.coder.com/flog" ) @@ -35,78 +35,11 @@ func main() { } defer xterminal.Restore(os.Stdout.Fd(), stdoutState) - app := &cobra.Command{ - Use: "coder", - Short: "coder provides a CLI for working with an existing Coder Enterprise installation", - Version: fmt.Sprintf("%s %s %s/%s", version, runtime.Version(), runtime.GOOS, runtime.GOARCH), - } + app := cmd.Make() + app.Version = fmt.Sprintf("%s %s %s/%s", version, runtime.Version(), runtime.GOOS, runtime.GOARCH) - app.AddCommand( - makeLoginCmd(), - makeLogoutCmd(), - makeShellCmd(), - makeUsersCmd(), - makeConfigSSHCmd(), - makeSecretsCmd(), - makeEnvsCommand(), - makeSyncCmd(), - makeURLCmd(), - completionCmd, - ) err = app.ExecuteContext(ctx) if err != nil { os.Exit(1) } } - -// reference: https://github.com/spf13/cobra/blob/master/shell_completions.md -var completionCmd = &cobra.Command{ - Use: "completion [bash|zsh|fish|powershell]", - Short: "Generate completion script", - Long: `To load completions: - -Bash: - -$ source <(yourprogram completion bash) - -# To load completions for each session, execute once: -Linux: - $ yourprogram completion bash > /etc/bash_completion.d/yourprogram -MacOS: - $ yourprogram completion bash > /usr/local/etc/bash_completion.d/yourprogram - -Zsh: - -# If shell completion is not already enabled in your environment you will need -# to enable it. You can execute the following once: - -$ echo "autoload -U compinit; compinit" >> ~/.zshrc - -# To load completions for each session, execute once: -$ yourprogram completion zsh > "${fpath[1]}/_yourprogram" - -# You will need to start a new shell for this setup to take effect. - -Fish: - -$ yourprogram completion fish | source - -# To load completions for each session, execute once: -$ yourprogram completion fish > ~/.config/fish/completions/yourprogram.fish -`, - DisableFlagsInUseLine: true, - ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, - Args: cobra.ExactValidArgs(1), - Run: func(cmd *cobra.Command, args []string) { - switch args[0] { - case "bash": - cmd.Root().GenBashCompletion(os.Stdout) - case "zsh": - cmd.Root().GenZshCompletion(os.Stdout) - case "fish": - cmd.Root().GenFishCompletion(os.Stdout, true) - case "powershell": - cmd.Root().GenPowerShellCompletion(os.Stdout) - } - }, -} diff --git a/cmd/coder/auth.go b/internal/cmd/auth.go similarity index 98% rename from cmd/coder/auth.go rename to internal/cmd/auth.go index abd0e8d0..64bcfb23 100644 --- a/cmd/coder/auth.go +++ b/internal/cmd/auth.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "net/url" diff --git a/cmd/coder/ceapi.go b/internal/cmd/ceapi.go similarity index 99% rename from cmd/coder/ceapi.go rename to internal/cmd/ceapi.go index 823f36ff..b69788fc 100644 --- a/cmd/coder/ceapi.go +++ b/internal/cmd/ceapi.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "context" diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go new file mode 100644 index 00000000..ad28fa39 --- /dev/null +++ b/internal/cmd/cmd.go @@ -0,0 +1,80 @@ +package cmd + +import ( + "os" + + "github.com/spf13/cobra" +) + +func Make() *cobra.Command { + app := &cobra.Command{ + Use: "coder", + Short: "coder provides a CLI for working with an existing Coder Enterprise installation", + } + + app.AddCommand( + makeLoginCmd(), + makeLogoutCmd(), + makeShellCmd(), + makeUsersCmd(), + makeConfigSSHCmd(), + makeSecretsCmd(), + makeEnvsCommand(), + makeSyncCmd(), + makeURLCmd(), + completionCmd, + ) + return app +} + +// reference: https://github.com/spf13/cobra/blob/master/shell_completions.md +var completionCmd = &cobra.Command{ + Use: "completion [bash|zsh|fish|powershell]", + Short: "Generate completion script", + Long: `To load completions: + +Bash: + +$ source <(coder completion bash) + +# To load completions for each session, execute once: +Linux: + $ coder completion bash > /etc/bash_completion.d/coder +MacOS: + $ coder completion bash > /usr/local/etc/bash_completion.d/coder + +Zsh: + +# If shell completion is not already enabled in your environment you will need +# to enable it. You can execute the following once: + +$ echo "autoload -U compinit; compinit" >> ~/.zshrc + +# To load completions for each session, execute once: +$ coder completion zsh > "${fpath[1]}/_coder" + +# You will need to start a new shell for this setup to take effect. + +Fish: + +$ coder completion fish | source + +# To load completions for each session, execute once: +$ coder completion fish > ~/.config/fish/completions/coder.fish +`, + DisableFlagsInUseLine: true, + ValidArgs: []string{"bash", "zsh", "fish", "powershell"}, + Args: cobra.ExactValidArgs(1), + Run: func(cmd *cobra.Command, args []string) { + switch args[0] { + case "bash": + cmd.Root().GenBashCompletion(os.Stdout) + case "zsh": + cmd.Root().GenZshCompletion(os.Stdout) + case "fish": + cmd.Root().GenFishCompletion(os.Stdout, true) + case "powershell": + cmd.Root().GenPowerShellCompletion(os.Stdout) + } + }, +} diff --git a/cmd/coder/configssh.go b/internal/cmd/configssh.go similarity index 99% rename from cmd/coder/configssh.go rename to internal/cmd/configssh.go index 50b991d4..fc67ee1a 100644 --- a/cmd/coder/configssh.go +++ b/internal/cmd/configssh.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "context" diff --git a/cmd/coder/envs.go b/internal/cmd/envs.go similarity index 99% rename from cmd/coder/envs.go rename to internal/cmd/envs.go index 32d73245..4e3219b7 100644 --- a/cmd/coder/envs.go +++ b/internal/cmd/envs.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "encoding/json" diff --git a/cmd/coder/login.go b/internal/cmd/login.go similarity index 99% rename from cmd/coder/login.go rename to internal/cmd/login.go index ed8cb499..d81dac0e 100644 --- a/cmd/coder/login.go +++ b/internal/cmd/login.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "net" diff --git a/cmd/coder/logout.go b/internal/cmd/logout.go similarity index 97% rename from cmd/coder/logout.go rename to internal/cmd/logout.go index 079a2e56..621ed89e 100644 --- a/cmd/coder/logout.go +++ b/internal/cmd/logout.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "os" diff --git a/cmd/coder/secrets.go b/internal/cmd/secrets.go similarity index 99% rename from cmd/coder/secrets.go rename to internal/cmd/secrets.go index 9433588c..7303d8fa 100644 --- a/cmd/coder/secrets.go +++ b/internal/cmd/secrets.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "fmt" diff --git a/cmd/coder/shell.go b/internal/cmd/shell.go similarity index 99% rename from cmd/coder/shell.go rename to internal/cmd/shell.go index eca157e0..7cfee8b0 100644 --- a/cmd/coder/shell.go +++ b/internal/cmd/shell.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "context" diff --git a/cmd/coder/sync.go b/internal/cmd/sync.go similarity index 99% rename from cmd/coder/sync.go rename to internal/cmd/sync.go index 6cab1bc2..c41d06fd 100644 --- a/cmd/coder/sync.go +++ b/internal/cmd/sync.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "bytes" diff --git a/cmd/coder/urls.go b/internal/cmd/urls.go similarity index 99% rename from cmd/coder/urls.go rename to internal/cmd/urls.go index 7f29cdb8..ba6e5494 100644 --- a/cmd/coder/urls.go +++ b/internal/cmd/urls.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "context" diff --git a/cmd/coder/users.go b/internal/cmd/users.go similarity index 99% rename from cmd/coder/users.go rename to internal/cmd/users.go index d43d2f4b..c88dae47 100644 --- a/cmd/coder/users.go +++ b/internal/cmd/users.go @@ -1,4 +1,4 @@ -package main +package cmd import ( "encoding/json" From b9ebf97a834e6b21b8375eafed3d1733d62e6816 Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Wed, 12 Aug 2020 10:10:32 -0500 Subject: [PATCH 2/4] Link to auto-generated docs --- README.md | 8 ++++++-- docs/coder.md | 26 +++++++++++++++++++++++ docs/coder_config-ssh.md | 24 ++++++++++++++++++++++ docs/coder_envs.md | 20 ++++++++++++++++++ docs/coder_envs_ls.md | 29 ++++++++++++++++++++++++++ docs/coder_login.md | 22 ++++++++++++++++++++ docs/coder_logout.md | 22 ++++++++++++++++++++ docs/coder_secrets.md | 23 +++++++++++++++++++++ docs/coder_secrets_create.md | 40 ++++++++++++++++++++++++++++++++++++ docs/coder_secrets_ls.md | 28 +++++++++++++++++++++++++ docs/coder_secrets_rm.md | 34 ++++++++++++++++++++++++++++++ docs/coder_secrets_view.md | 34 ++++++++++++++++++++++++++++++ docs/coder_sh.md | 28 +++++++++++++++++++++++++ docs/coder_sync.md | 23 +++++++++++++++++++++ docs/coder_urls.md | 21 +++++++++++++++++++ docs/coder_urls_create.md | 24 ++++++++++++++++++++++ docs/coder_urls_ls.md | 23 +++++++++++++++++++++ docs/coder_urls_rm.md | 22 ++++++++++++++++++++ docs/coder_users.md | 19 +++++++++++++++++ docs/coder_users_ls.md | 30 +++++++++++++++++++++++++++ internal/cmd/cmd.go | 1 + 21 files changed, 499 insertions(+), 2 deletions(-) create mode 100644 docs/coder.md create mode 100644 docs/coder_config-ssh.md create mode 100644 docs/coder_envs.md create mode 100644 docs/coder_envs_ls.md create mode 100644 docs/coder_login.md create mode 100644 docs/coder_logout.md create mode 100644 docs/coder_secrets.md create mode 100644 docs/coder_secrets_create.md create mode 100644 docs/coder_secrets_ls.md create mode 100644 docs/coder_secrets_rm.md create mode 100644 docs/coder_secrets_view.md create mode 100644 docs/coder_sh.md create mode 100644 docs/coder_sync.md create mode 100644 docs/coder_urls.md create mode 100644 docs/coder_urls_create.md create mode 100644 docs/coder_urls_ls.md create mode 100644 docs/coder_urls_rm.md create mode 100644 docs/coder_users.md create mode 100644 docs/coder_users_ls.md diff --git a/README.md b/README.md index 427ad846..95b321a4 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,14 @@ `coder` is a command line utility for Coder Enterprise. -To view usage documentation, head over to [https://enterprise.coder.com](https://enterprise.coder.com/docs/getting-started). - To report bugs and request features, please [open an issue](https://github.com/cdr/coder-cli/issues/new). +## Usage + +View the `coder-cli` documentation [here](./docs/coder.md). + +You can find additional Coder Enterprise usage documentation on [https://enterprise.coder.com](https://enterprise.coder.com/docs/getting-started). + ## Install Release Download the latest [release](https://github.com/cdr/coder-cli/releases): diff --git a/docs/coder.md b/docs/coder.md new file mode 100644 index 00000000..518eb29a --- /dev/null +++ b/docs/coder.md @@ -0,0 +1,26 @@ +## coder + +coder provides a CLI for working with an existing Coder Enterprise installation + +### Synopsis + +coder provides a CLI for working with an existing Coder Enterprise installation + +### Options + +``` + -h, --help help for coder +``` + +### SEE ALSO + +* [coder config-ssh](coder_config-ssh.md) - Configure SSH to access Coder environments +* [coder envs](coder_envs.md) - Interact with Coder environments +* [coder login](coder_login.md) - Authenticate this client for future operations +* [coder logout](coder_logout.md) - Remove local authentication credentials if any exist +* [coder secrets](coder_secrets.md) - Interact with Coder Secrets +* [coder sh](coder_sh.md) - Open a shell and execute commands in a Coder environment +* [coder sync](coder_sync.md) - Establish a one way directory sync to a Coder environment +* [coder urls](coder_urls.md) - Interact with environment DevURLs +* [coder users](coder_users.md) - Interact with Coder user accounts + diff --git a/docs/coder_config-ssh.md b/docs/coder_config-ssh.md new file mode 100644 index 00000000..b4cb3c59 --- /dev/null +++ b/docs/coder_config-ssh.md @@ -0,0 +1,24 @@ +## coder config-ssh + +Configure SSH to access Coder environments + +### Synopsis + +Inject the proper OpenSSH configuration into your local SSH config file. + +``` +coder config-ssh [flags] +``` + +### Options + +``` + --filepath string overide the default path of your ssh config file (default "~/.ssh/config") + -h, --help help for config-ssh + --remove remove the auto-generated Coder Enterprise ssh config +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation + diff --git a/docs/coder_envs.md b/docs/coder_envs.md new file mode 100644 index 00000000..30657d19 --- /dev/null +++ b/docs/coder_envs.md @@ -0,0 +1,20 @@ +## coder envs + +Interact with Coder environments + +### Synopsis + +Perform operations on the Coder environments owned by the active user. + +### Options + +``` + -h, --help help for envs + --user string Specify the user whose resources to target (default "me") +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation +* [coder envs ls](coder_envs_ls.md) - list all environments owned by the active user + diff --git a/docs/coder_envs_ls.md b/docs/coder_envs_ls.md new file mode 100644 index 00000000..df0569ec --- /dev/null +++ b/docs/coder_envs_ls.md @@ -0,0 +1,29 @@ +## coder envs ls + +list all environments owned by the active user + +### Synopsis + +List all Coder environments owned by the active user. + +``` +coder envs ls [flags] +``` + +### Options + +``` + -h, --help help for ls + -o, --output string human | json (default "human") +``` + +### Options inherited from parent commands + +``` + --user string Specify the user whose resources to target (default "me") +``` + +### SEE ALSO + +* [coder envs](coder_envs.md) - Interact with Coder environments + diff --git a/docs/coder_login.md b/docs/coder_login.md new file mode 100644 index 00000000..8551f43b --- /dev/null +++ b/docs/coder_login.md @@ -0,0 +1,22 @@ +## coder login + +Authenticate this client for future operations + +### Synopsis + +Authenticate this client for future operations + +``` +coder login [Coder Enterprise URL eg. http://my.coder.domain/] [flags] +``` + +### Options + +``` + -h, --help help for login +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation + diff --git a/docs/coder_logout.md b/docs/coder_logout.md new file mode 100644 index 00000000..5c308147 --- /dev/null +++ b/docs/coder_logout.md @@ -0,0 +1,22 @@ +## coder logout + +Remove local authentication credentials if any exist + +### Synopsis + +Remove local authentication credentials if any exist + +``` +coder logout [flags] +``` + +### Options + +``` + -h, --help help for logout +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation + diff --git a/docs/coder_secrets.md b/docs/coder_secrets.md new file mode 100644 index 00000000..917e4cf9 --- /dev/null +++ b/docs/coder_secrets.md @@ -0,0 +1,23 @@ +## coder secrets + +Interact with Coder Secrets + +### Synopsis + +Interact with secrets objects owned by the active user. + +### Options + +``` + -h, --help help for secrets + --user string Specify the user whose resources to target (default "me") +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation +* [coder secrets create](coder_secrets_create.md) - Create a new secret +* [coder secrets ls](coder_secrets_ls.md) - List all secrets owned by the active user +* [coder secrets rm](coder_secrets_rm.md) - Remove one or more secrets by name +* [coder secrets view](coder_secrets_view.md) - View a secret by name + diff --git a/docs/coder_secrets_create.md b/docs/coder_secrets_create.md new file mode 100644 index 00000000..5dfe7e1a --- /dev/null +++ b/docs/coder_secrets_create.md @@ -0,0 +1,40 @@ +## coder secrets create + +Create a new secret + +### Synopsis + +Create a new secret object to store application secrets and access them securely from within your environments. + +``` +coder secrets create [secret_name] [flags] +``` + +### Examples + +``` +coder secrets create mysql-password --from-literal 123password +coder secrets create mysql-password --from-prompt +coder secrets create aws-credentials --from-file ./credentials.json +``` + +### Options + +``` + --description string a description of the secret + --from-file string a file from which to read the value of the secret + --from-literal string the value of the secret + --from-prompt enter the secret value through a terminal prompt + -h, --help help for create +``` + +### Options inherited from parent commands + +``` + --user string Specify the user whose resources to target (default "me") +``` + +### SEE ALSO + +* [coder secrets](coder_secrets.md) - Interact with Coder Secrets + diff --git a/docs/coder_secrets_ls.md b/docs/coder_secrets_ls.md new file mode 100644 index 00000000..49f7e8b7 --- /dev/null +++ b/docs/coder_secrets_ls.md @@ -0,0 +1,28 @@ +## coder secrets ls + +List all secrets owned by the active user + +### Synopsis + +List all secrets owned by the active user + +``` +coder secrets ls [flags] +``` + +### Options + +``` + -h, --help help for ls +``` + +### Options inherited from parent commands + +``` + --user string Specify the user whose resources to target (default "me") +``` + +### SEE ALSO + +* [coder secrets](coder_secrets.md) - Interact with Coder Secrets + diff --git a/docs/coder_secrets_rm.md b/docs/coder_secrets_rm.md new file mode 100644 index 00000000..d628b148 --- /dev/null +++ b/docs/coder_secrets_rm.md @@ -0,0 +1,34 @@ +## coder secrets rm + +Remove one or more secrets by name + +### Synopsis + +Remove one or more secrets by name + +``` +coder secrets rm [...secret_name] [flags] +``` + +### Examples + +``` +coder secrets rm mysql-password mysql-user +``` + +### Options + +``` + -h, --help help for rm +``` + +### Options inherited from parent commands + +``` + --user string Specify the user whose resources to target (default "me") +``` + +### SEE ALSO + +* [coder secrets](coder_secrets.md) - Interact with Coder Secrets + diff --git a/docs/coder_secrets_view.md b/docs/coder_secrets_view.md new file mode 100644 index 00000000..f8c18ee9 --- /dev/null +++ b/docs/coder_secrets_view.md @@ -0,0 +1,34 @@ +## coder secrets view + +View a secret by name + +### Synopsis + +View a secret by name + +``` +coder secrets view [secret_name] [flags] +``` + +### Examples + +``` +coder secrets view mysql-password +``` + +### Options + +``` + -h, --help help for view +``` + +### Options inherited from parent commands + +``` + --user string Specify the user whose resources to target (default "me") +``` + +### SEE ALSO + +* [coder secrets](coder_secrets.md) - Interact with Coder Secrets + diff --git a/docs/coder_sh.md b/docs/coder_sh.md new file mode 100644 index 00000000..e32ecd65 --- /dev/null +++ b/docs/coder_sh.md @@ -0,0 +1,28 @@ +## coder sh + +Open a shell and execute commands in a Coder environment + +### Synopsis + +Execute a remote command on the environment\nIf no command is specified, the default shell is opened. + +``` +coder sh [environment_name] [] [flags] +``` + +### Examples + +``` +coder sh backend-env +``` + +### Options + +``` + -h, --help help for sh +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation + diff --git a/docs/coder_sync.md b/docs/coder_sync.md new file mode 100644 index 00000000..cf03a01e --- /dev/null +++ b/docs/coder_sync.md @@ -0,0 +1,23 @@ +## coder sync + +Establish a one way directory sync to a Coder environment + +### Synopsis + +Establish a one way directory sync to a Coder environment + +``` +coder sync [local directory] [:] [flags] +``` + +### Options + +``` + -h, --help help for sync + --init do initial transfer and exit +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation + diff --git a/docs/coder_urls.md b/docs/coder_urls.md new file mode 100644 index 00000000..dd181999 --- /dev/null +++ b/docs/coder_urls.md @@ -0,0 +1,21 @@ +## coder urls + +Interact with environment DevURLs + +### Synopsis + +Interact with environment DevURLs + +### Options + +``` + -h, --help help for urls +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation +* [coder urls create](coder_urls_create.md) - Create a new devurl for an environment +* [coder urls ls](coder_urls_ls.md) - List all DevURLs for an environment +* [coder urls rm](coder_urls_rm.md) - Remove a dev url + diff --git a/docs/coder_urls_create.md b/docs/coder_urls_create.md new file mode 100644 index 00000000..8cf4c258 --- /dev/null +++ b/docs/coder_urls_create.md @@ -0,0 +1,24 @@ +## coder urls create + +Create a new devurl for an environment + +### Synopsis + +Create a new devurl for an environment + +``` +coder urls create [env_name] [port] [--access ] [--name ] [flags] +``` + +### Options + +``` + --access string Set DevURL access to [private | org | authed | public] (default "private") + -h, --help help for create + --name string DevURL name +``` + +### SEE ALSO + +* [coder urls](coder_urls.md) - Interact with environment DevURLs + diff --git a/docs/coder_urls_ls.md b/docs/coder_urls_ls.md new file mode 100644 index 00000000..f359529e --- /dev/null +++ b/docs/coder_urls_ls.md @@ -0,0 +1,23 @@ +## coder urls ls + +List all DevURLs for an environment + +### Synopsis + +List all DevURLs for an environment + +``` +coder urls ls [environment_name] [flags] +``` + +### Options + +``` + -h, --help help for ls + -o, --output string human|json (default "human") +``` + +### SEE ALSO + +* [coder urls](coder_urls.md) - Interact with environment DevURLs + diff --git a/docs/coder_urls_rm.md b/docs/coder_urls_rm.md new file mode 100644 index 00000000..4d88170b --- /dev/null +++ b/docs/coder_urls_rm.md @@ -0,0 +1,22 @@ +## coder urls rm + +Remove a dev url + +### Synopsis + +Remove a dev url + +``` +coder urls rm [environment_name] [port] [flags] +``` + +### Options + +``` + -h, --help help for rm +``` + +### SEE ALSO + +* [coder urls](coder_urls.md) - Interact with environment DevURLs + diff --git a/docs/coder_users.md b/docs/coder_users.md new file mode 100644 index 00000000..974edc27 --- /dev/null +++ b/docs/coder_users.md @@ -0,0 +1,19 @@ +## coder users + +Interact with Coder user accounts + +### Synopsis + +Interact with Coder user accounts + +### Options + +``` + -h, --help help for users +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation +* [coder users ls](coder_users_ls.md) - list all user accounts + diff --git a/docs/coder_users_ls.md b/docs/coder_users_ls.md new file mode 100644 index 00000000..a6b85a4c --- /dev/null +++ b/docs/coder_users_ls.md @@ -0,0 +1,30 @@ +## coder users ls + +list all user accounts + +### Synopsis + +list all user accounts + +``` +coder users ls [flags] +``` + +### Examples + +``` +coder users ls -o json +coder users ls -o json | jq .[] | jq -r .email +``` + +### Options + +``` + -h, --help help for ls + -o, --output string human | json (default "human") +``` + +### SEE ALSO + +* [coder users](coder_users.md) - Interact with Coder user accounts + diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index ad28fa39..f1fadf30 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -6,6 +6,7 @@ import ( "github.com/spf13/cobra" ) +// Make constructs the "coder" root command func Make() *cobra.Command { app := &cobra.Command{ Use: "coder", From 0e031d9e16b85e101b9ac3c22c34776c3c91701c Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Wed, 12 Aug 2020 21:51:29 -0500 Subject: [PATCH 3/4] Add gendocs ci step --- .github/workflows/test.yaml | 14 ++++++++ ci/steps/fmt.sh | 7 ++-- ci/steps/gendocs.sh | 25 ++++++++++++++ ci/steps/lint.sh | 4 ++- docs/coder.md | 2 +- docs/coder_completion.md | 63 ++++++++++++++++++++++++++++++++++++ docs/coder_config-ssh.md | 1 - docs/coder_envs.md | 1 - docs/coder_envs_ls.md | 1 - docs/coder_login.md | 1 - docs/coder_logout.md | 1 - docs/coder_secrets.md | 1 - docs/coder_secrets_create.md | 1 - docs/coder_secrets_ls.md | 1 - docs/coder_secrets_rm.md | 1 - docs/coder_secrets_view.md | 1 - docs/coder_sh.md | 1 - docs/coder_sync.md | 1 - docs/coder_urls.md | 1 - docs/coder_urls_create.md | 1 - docs/coder_urls_ls.md | 1 - docs/coder_urls_rm.md | 1 - docs/coder_users.md | 1 - docs/coder_users_ls.md | 1 - internal/cmd/cmd.go | 35 ++++++++++++++++---- internal/cmd/configssh.go | 27 ++++++++++------ 26 files changed, 157 insertions(+), 38 deletions(-) create mode 100755 ci/steps/gendocs.sh create mode 100644 docs/coder_completion.md diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 36397b7d..d7712b14 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -44,3 +44,17 @@ jobs: uses: ./ci/image with: args: go test ./internal/... ./cmd/... + gendocs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/cache@v1 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - name: generate-docs + uses: ./ci/image + with: + args: ./ci/steps/gendocs.sh diff --git a/ci/steps/fmt.sh b/ci/steps/fmt.sh index bb4b0d2c..c202dab9 100755 --- a/ci/steps/fmt.sh +++ b/ci/steps/fmt.sh @@ -1,16 +1,17 @@ #!/bin/bash + +set -euo pipefail + echo "Formatting..." go mod tidy gofmt -w -s . goimports -w "-local=$$(go list -m)" . -if [ "$CI" != "" ]; then - if [[ $(git ls-files --other --modified --exclude-standard) != "" ]]; then +if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then echo "Files need generation or are formatted incorrectly:" git -c color.ui=always status | grep --color=no '\e\[31m' echo "Please run the following locally:" echo " ./ci/steps/fmt.sh" exit 1 fi -fi \ No newline at end of file diff --git a/ci/steps/gendocs.sh b/ci/steps/gendocs.sh new file mode 100755 index 00000000..64a3776a --- /dev/null +++ b/ci/steps/gendocs.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +set -euo pipefail + +echo "Generating docs..." + +cd "$(dirname "$0")" +cd ../../ + +go run ./cmd/coder gen-docs ./docs + +# remove cobra footer from each file +for filename in ./docs/*.md; do + trimmed=$(head -n -1 "$filename") + echo "$trimmed" > $filename +done + + +if [[ ${CI-} && $(git ls-files --other --modified --exclude-standard) ]]; then + echo "Documentation needs generation:" + git -c color.ui=always status | grep --color=no '\e\[31m' + echo "Please run the following locally:" + echo " ./ci/steps/gendocs.sh" + exit 1 +fi diff --git a/ci/steps/lint.sh b/ci/steps/lint.sh index 51da081d..c3f72614 100755 --- a/ci/steps/lint.sh +++ b/ci/steps/lint.sh @@ -1,6 +1,8 @@ #!/bin/bash +set -euo pipefail + echo "Linting..." go vet ./... -golint -set_exit_status ./... \ No newline at end of file +golint -set_exit_status ./... diff --git a/docs/coder.md b/docs/coder.md index 518eb29a..378a9c66 100644 --- a/docs/coder.md +++ b/docs/coder.md @@ -14,6 +14,7 @@ coder provides a CLI for working with an existing Coder Enterprise installation ### SEE ALSO +* [coder completion](coder_completion.md) - Generate completion script * [coder config-ssh](coder_config-ssh.md) - Configure SSH to access Coder environments * [coder envs](coder_envs.md) - Interact with Coder environments * [coder login](coder_login.md) - Authenticate this client for future operations @@ -23,4 +24,3 @@ coder provides a CLI for working with an existing Coder Enterprise installation * [coder sync](coder_sync.md) - Establish a one way directory sync to a Coder environment * [coder urls](coder_urls.md) - Interact with environment DevURLs * [coder users](coder_users.md) - Interact with Coder user accounts - diff --git a/docs/coder_completion.md b/docs/coder_completion.md new file mode 100644 index 00000000..39b862af --- /dev/null +++ b/docs/coder_completion.md @@ -0,0 +1,63 @@ +## coder completion + +Generate completion script + +### Synopsis + +To load completions: + +Bash: + +$ source <(coder completion bash) + +To load completions for each session, execute once: +Linux: + $ coder completion bash > /etc/bash_completion.d/coder +MacOS: + $ coder completion bash > /usr/local/etc/bash_completion.d/coder + +Zsh: + +If shell completion is not already enabled in your environment you will need +to enable it. You can execute the following once: + +$ echo "autoload -U compinit; compinit" >> ~/.zshrc + +To load completions for each session, execute once: +$ coder completion zsh > "${fpath[1]}/_coder" + +You will need to start a new shell for this setup to take effect. + +Fish: + +$ coder completion fish | source + +To load completions for each session, execute once: +$ coder completion fish > ~/.config/fish/completions/coder.fish + + +``` +coder completion [bash|zsh|fish|powershell] +``` + +### Examples + +``` +coder completion fish > ~/.config/fish/completions/coder.fish +coder completion zsh > "${fpath[1]}/_coder" + +Linux: + $ coder completion bash > /etc/bash_completion.d/coder +MacOS: + $ coder completion bash > /usr/local/etc/bash_completion.d/coder +``` + +### Options + +``` + -h, --help help for completion +``` + +### SEE ALSO + +* [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation diff --git a/docs/coder_config-ssh.md b/docs/coder_config-ssh.md index b4cb3c59..41b697ef 100644 --- a/docs/coder_config-ssh.md +++ b/docs/coder_config-ssh.md @@ -21,4 +21,3 @@ coder config-ssh [flags] ### SEE ALSO * [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation - diff --git a/docs/coder_envs.md b/docs/coder_envs.md index 30657d19..a08c4b15 100644 --- a/docs/coder_envs.md +++ b/docs/coder_envs.md @@ -17,4 +17,3 @@ Perform operations on the Coder environments owned by the active user. * [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation * [coder envs ls](coder_envs_ls.md) - list all environments owned by the active user - diff --git a/docs/coder_envs_ls.md b/docs/coder_envs_ls.md index df0569ec..d3535af8 100644 --- a/docs/coder_envs_ls.md +++ b/docs/coder_envs_ls.md @@ -26,4 +26,3 @@ coder envs ls [flags] ### SEE ALSO * [coder envs](coder_envs.md) - Interact with Coder environments - diff --git a/docs/coder_login.md b/docs/coder_login.md index 8551f43b..9cd18ae8 100644 --- a/docs/coder_login.md +++ b/docs/coder_login.md @@ -19,4 +19,3 @@ coder login [Coder Enterprise URL eg. http://my.coder.domain/] [flags] ### SEE ALSO * [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation - diff --git a/docs/coder_logout.md b/docs/coder_logout.md index 5c308147..22bce303 100644 --- a/docs/coder_logout.md +++ b/docs/coder_logout.md @@ -19,4 +19,3 @@ coder logout [flags] ### SEE ALSO * [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation - diff --git a/docs/coder_secrets.md b/docs/coder_secrets.md index 917e4cf9..ebdd1af2 100644 --- a/docs/coder_secrets.md +++ b/docs/coder_secrets.md @@ -20,4 +20,3 @@ Interact with secrets objects owned by the active user. * [coder secrets ls](coder_secrets_ls.md) - List all secrets owned by the active user * [coder secrets rm](coder_secrets_rm.md) - Remove one or more secrets by name * [coder secrets view](coder_secrets_view.md) - View a secret by name - diff --git a/docs/coder_secrets_create.md b/docs/coder_secrets_create.md index 5dfe7e1a..c10a771e 100644 --- a/docs/coder_secrets_create.md +++ b/docs/coder_secrets_create.md @@ -37,4 +37,3 @@ coder secrets create aws-credentials --from-file ./credentials.json ### SEE ALSO * [coder secrets](coder_secrets.md) - Interact with Coder Secrets - diff --git a/docs/coder_secrets_ls.md b/docs/coder_secrets_ls.md index 49f7e8b7..40408e8e 100644 --- a/docs/coder_secrets_ls.md +++ b/docs/coder_secrets_ls.md @@ -25,4 +25,3 @@ coder secrets ls [flags] ### SEE ALSO * [coder secrets](coder_secrets.md) - Interact with Coder Secrets - diff --git a/docs/coder_secrets_rm.md b/docs/coder_secrets_rm.md index d628b148..d58dc6f0 100644 --- a/docs/coder_secrets_rm.md +++ b/docs/coder_secrets_rm.md @@ -31,4 +31,3 @@ coder secrets rm mysql-password mysql-user ### SEE ALSO * [coder secrets](coder_secrets.md) - Interact with Coder Secrets - diff --git a/docs/coder_secrets_view.md b/docs/coder_secrets_view.md index f8c18ee9..e5a9770a 100644 --- a/docs/coder_secrets_view.md +++ b/docs/coder_secrets_view.md @@ -31,4 +31,3 @@ coder secrets view mysql-password ### SEE ALSO * [coder secrets](coder_secrets.md) - Interact with Coder Secrets - diff --git a/docs/coder_sh.md b/docs/coder_sh.md index e32ecd65..6c88f203 100644 --- a/docs/coder_sh.md +++ b/docs/coder_sh.md @@ -25,4 +25,3 @@ coder sh backend-env ### SEE ALSO * [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation - diff --git a/docs/coder_sync.md b/docs/coder_sync.md index cf03a01e..03ca7a37 100644 --- a/docs/coder_sync.md +++ b/docs/coder_sync.md @@ -20,4 +20,3 @@ coder sync [local directory] [:] [flags] ### SEE ALSO * [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation - diff --git a/docs/coder_urls.md b/docs/coder_urls.md index dd181999..df4c3c70 100644 --- a/docs/coder_urls.md +++ b/docs/coder_urls.md @@ -18,4 +18,3 @@ Interact with environment DevURLs * [coder urls create](coder_urls_create.md) - Create a new devurl for an environment * [coder urls ls](coder_urls_ls.md) - List all DevURLs for an environment * [coder urls rm](coder_urls_rm.md) - Remove a dev url - diff --git a/docs/coder_urls_create.md b/docs/coder_urls_create.md index 8cf4c258..7afc8d8b 100644 --- a/docs/coder_urls_create.md +++ b/docs/coder_urls_create.md @@ -21,4 +21,3 @@ coder urls create [env_name] [port] [--access ] [--name ] [flags] ### SEE ALSO * [coder urls](coder_urls.md) - Interact with environment DevURLs - diff --git a/docs/coder_urls_ls.md b/docs/coder_urls_ls.md index f359529e..1d01c2e5 100644 --- a/docs/coder_urls_ls.md +++ b/docs/coder_urls_ls.md @@ -20,4 +20,3 @@ coder urls ls [environment_name] [flags] ### SEE ALSO * [coder urls](coder_urls.md) - Interact with environment DevURLs - diff --git a/docs/coder_urls_rm.md b/docs/coder_urls_rm.md index 4d88170b..2b69e2bb 100644 --- a/docs/coder_urls_rm.md +++ b/docs/coder_urls_rm.md @@ -19,4 +19,3 @@ coder urls rm [environment_name] [port] [flags] ### SEE ALSO * [coder urls](coder_urls.md) - Interact with environment DevURLs - diff --git a/docs/coder_users.md b/docs/coder_users.md index 974edc27..6482d76e 100644 --- a/docs/coder_users.md +++ b/docs/coder_users.md @@ -16,4 +16,3 @@ Interact with Coder user accounts * [coder](coder.md) - coder provides a CLI for working with an existing Coder Enterprise installation * [coder users ls](coder_users_ls.md) - list all user accounts - diff --git a/docs/coder_users_ls.md b/docs/coder_users_ls.md index a6b85a4c..6cf7ccd1 100644 --- a/docs/coder_users_ls.md +++ b/docs/coder_users_ls.md @@ -27,4 +27,3 @@ coder users ls -o json | jq .[] | jq -r .email ### SEE ALSO * [coder users](coder_users.md) - Interact with Coder user accounts - diff --git a/internal/cmd/cmd.go b/internal/cmd/cmd.go index f1fadf30..30e4af7d 100644 --- a/internal/cmd/cmd.go +++ b/internal/cmd/cmd.go @@ -4,6 +4,7 @@ import ( "os" "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" ) // Make constructs the "coder" root command @@ -24,21 +25,43 @@ func Make() *cobra.Command { makeSyncCmd(), makeURLCmd(), completionCmd, + genDocs(app), ) return app } +func genDocs(rootCmd *cobra.Command) *cobra.Command { + cmd := &cobra.Command{ + Use: "gen-docs [dir_path]", + Short: "Generate a markdown documentation tree for the root command.", + Example: "coder gen-docs ./docs", + Args: cobra.ExactArgs(1), + Hidden: true, + RunE: func(_ *cobra.Command, args []string) error { + return doc.GenMarkdownTree(rootCmd, args[0]) + }, + } + return cmd +} + // reference: https://github.com/spf13/cobra/blob/master/shell_completions.md var completionCmd = &cobra.Command{ Use: "completion [bash|zsh|fish|powershell]", Short: "Generate completion script", + Example: `coder completion fish > ~/.config/fish/completions/coder.fish +coder completion zsh > "${fpath[1]}/_coder" + +Linux: + $ coder completion bash > /etc/bash_completion.d/coder +MacOS: + $ coder completion bash > /usr/local/etc/bash_completion.d/coder`, Long: `To load completions: Bash: $ source <(coder completion bash) -# To load completions for each session, execute once: +To load completions for each session, execute once: Linux: $ coder completion bash > /etc/bash_completion.d/coder MacOS: @@ -46,21 +69,21 @@ MacOS: Zsh: -# If shell completion is not already enabled in your environment you will need -# to enable it. You can execute the following once: +If shell completion is not already enabled in your environment you will need +to enable it. You can execute the following once: $ echo "autoload -U compinit; compinit" >> ~/.zshrc -# To load completions for each session, execute once: +To load completions for each session, execute once: $ coder completion zsh > "${fpath[1]}/_coder" -# You will need to start a new shell for this setup to take effect. +You will need to start a new shell for this setup to take effect. Fish: $ coder completion fish | source -# To load completions for each session, execute once: +To load completions for each session, execute once: $ coder completion fish > ~/.config/fish/completions/coder.fish `, DisableFlagsInUseLine: true, diff --git a/internal/cmd/configssh.go b/internal/cmd/configssh.go index fc67ee1a..0e755ff1 100644 --- a/internal/cmd/configssh.go +++ b/internal/cmd/configssh.go @@ -7,6 +7,7 @@ import ( "net" "net/url" "os" + "os/user" "path/filepath" "strings" "time" @@ -29,13 +30,13 @@ func makeConfigSSHCmd() *cobra.Command { Long: "Inject the proper OpenSSH configuration into your local SSH config file.", RunE: configSSH(&configpath, &remove), } - cmd.Flags().StringVar(&configpath, "filepath", filepath.Join(os.Getenv("HOME"), ".ssh", "config"), "overide the default path of your ssh config file") + cmd.Flags().StringVar(&configpath, "filepath", filepath.Join("~", ".ssh", "config"), "overide the default path of your ssh config file") cmd.Flags().BoolVar(&remove, "remove", false, "remove the auto-generated Coder Enterprise ssh config") return cmd } -func configSSH(filepath *string, remove *bool) func(cmd *cobra.Command, _ []string) error { +func configSSH(configpath *string, remove *bool) func(cmd *cobra.Command, _ []string) error { startToken := "# ------------START-CODER-ENTERPRISE-----------" startMessage := `# The following has been auto-generated by "coder config-ssh" # to make accessing your Coder Enterprise environments easier. @@ -51,12 +52,20 @@ func configSSH(filepath *string, remove *bool) func(cmd *cobra.Command, _ []stri ctx, cancel := context.WithCancel(context.Background()) defer cancel() - currentConfig, err := readStr(*filepath) + if strings.HasPrefix(*configpath, "~") { + usr, err := user.Current() + if err != nil { + return xerrors.Errorf("get user home directory: %w", err) + } + *configpath = strings.Replace(*configpath, "~", usr.HomeDir, 1) + } + + currentConfig, err := readStr(*configpath) if os.IsNotExist(err) { // SSH configs are not always already there. currentConfig = "" } else if err != nil { - return xerrors.Errorf("read ssh config file %q: %w", filepath, err) + return xerrors.Errorf("read ssh config file %q: %w", configpath, err) } startIndex := strings.Index(currentConfig, startToken) @@ -68,9 +77,9 @@ func configSSH(filepath *string, remove *bool) func(cmd *cobra.Command, _ []stri } currentConfig = currentConfig[:startIndex-1] + currentConfig[endIndex+len(endToken)+1:] - err = writeStr(*filepath, currentConfig) + err = writeStr(*configpath, currentConfig) if err != nil { - return xerrors.Errorf("write to ssh config file %q: %v", *filepath, err) + return xerrors.Errorf("write to ssh config file %q: %v", *configpath, err) } return nil @@ -105,16 +114,16 @@ func configSSH(filepath *string, remove *bool) func(cmd *cobra.Command, _ []stri currentConfig = currentConfig[:startIndex-1] + currentConfig[endIndex+len(endToken)+1:] } - err = writeStr(*filepath, currentConfig+newConfig) + err = writeStr(*configpath, currentConfig+newConfig) if err != nil { - return xerrors.Errorf("write new configurations to ssh config file %q: %w", filepath, err) + return xerrors.Errorf("write new configurations to ssh config file %q: %w", *configpath, err) } err = writeSSHKey(ctx, entClient) if err != nil { return xerrors.Errorf("fetch and write ssh key: %w", err) } - fmt.Printf("An auto-generated ssh config was written to %q\n", *filepath) + fmt.Printf("An auto-generated ssh config was written to %q\n", *configpath) fmt.Printf("Your private ssh key was written to %q\n", privateKeyFilepath) fmt.Println("You should now be able to ssh into your environment") fmt.Printf("For example, try running\n\n\t$ ssh coder.%s\n\n", envs[0].Name) From f21d22465c42b8d5bc462ccfae508039f5ae0813 Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Thu, 13 Aug 2020 10:18:13 -0500 Subject: [PATCH 4/4] Abstract integration test container creation --- ci/integration/devurls_test.go | 33 ++----- ci/integration/integration_test.go | 127 +++++++++++++------------ ci/integration/secrets_test.go | 146 +++++++++++++---------------- ci/integration/ssh_test.go | 18 ++++ ci/integration/users_test.go | 70 ++++++-------- ci/steps/build.sh | 3 +- internal/cmd/configssh.go | 4 + 7 files changed, 198 insertions(+), 203 deletions(-) create mode 100644 ci/integration/ssh_test.go diff --git a/ci/integration/devurls_test.go b/ci/integration/devurls_test.go index 09f1c0e4..06553107 100644 --- a/ci/integration/devurls_test.go +++ b/ci/integration/devurls_test.go @@ -3,36 +3,23 @@ package integration import ( "context" "testing" - "time" "cdr.dev/coder-cli/ci/tcli" - "cdr.dev/slog/sloggers/slogtest/assert" ) func TestDevURLCLI(t *testing.T) { t.Parallel() - ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5) - defer cancel() - - c, err := tcli.NewContainerRunner(ctx, &tcli.ContainerConfig{ - Image: "codercom/enterprise-dev", - Name: "coder-cli-devurl-tests", - BindMounts: map[string]string{ - binpath: "/bin/coder", - }, + run(t, "coder-cli-devurl-tests", func(t *testing.T, ctx context.Context, c *tcli.ContainerRunner) { + c.Run(ctx, "which coder").Assert(t, + tcli.Success(), + tcli.StdoutMatches("/usr/sbin/coder"), + tcli.StderrEmpty(), + ) + + c.Run(ctx, "coder urls ls").Assert(t, + tcli.Error(), + ) }) - assert.Success(t, "new run container", err) - defer c.Close() - - c.Run(ctx, "which coder").Assert(t, - tcli.Success(), - tcli.StdoutMatches("/usr/sbin/coder"), - tcli.StderrEmpty(), - ) - - c.Run(ctx, "coder urls ls").Assert(t, - tcli.Error(), - ) // The following cannot be enabled nor verified until either the // integration testing dogfood target has environments created, or diff --git a/ci/integration/integration_test.go b/ci/integration/integration_test.go index 77a4ec91..eccf68a2 100644 --- a/ci/integration/integration_test.go +++ b/ci/integration/integration_test.go @@ -10,67 +10,78 @@ import ( "cdr.dev/slog/sloggers/slogtest/assert" ) +func run(t *testing.T, container string, execute func(t *testing.T, ctx context.Context, runner *tcli.ContainerRunner)) { + t.Run(container, func(t *testing.T) { + t.Parallel() + + ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5) + defer cancel() + + c, err := tcli.NewContainerRunner(ctx, &tcli.ContainerConfig{ + Image: "codercom/enterprise-dev", + Name: container, + BindMounts: map[string]string{ + binpath: "/bin/coder", + }, + }) + assert.Success(t, "new run container", err) + defer c.Close() + + execute(t, ctx, c) + }) +} + func TestCoderCLI(t *testing.T) { t.Parallel() - ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5) - defer cancel() - - c, err := tcli.NewContainerRunner(ctx, &tcli.ContainerConfig{ - Image: "codercom/enterprise-dev", - Name: "coder-cli-tests", - BindMounts: map[string]string{ - binpath: "/bin/coder", - }, + run(t, "test-coder-cli", func(t *testing.T, ctx context.Context, c *tcli.ContainerRunner) { + c.Run(ctx, "which coder").Assert(t, + tcli.Success(), + tcli.StdoutMatches("/usr/sbin/coder"), + tcli.StderrEmpty(), + ) + + c.Run(ctx, "coder --version").Assert(t, + tcli.StderrEmpty(), + tcli.Success(), + tcli.StdoutMatches("linux"), + ) + + c.Run(ctx, "coder --help").Assert(t, + tcli.Success(), + tcli.StdoutMatches("Available Commands"), + ) + + headlessLogin(ctx, t, c) + + c.Run(ctx, "coder envs").Assert(t, + tcli.Success(), + ) + + c.Run(ctx, "coder envs ls").Assert(t, + tcli.Success(), + ) + + c.Run(ctx, "coder urls").Assert(t, + tcli.Success(), + ) + + c.Run(ctx, "coder sync").Assert(t, + tcli.Error(), + ) + + c.Run(ctx, "coder sh").Assert(t, + tcli.Error(), + ) + + c.Run(ctx, "coder logout").Assert(t, + tcli.Success(), + ) + + c.Run(ctx, "coder envs ls").Assert(t, + tcli.Error(), + ) }) - assert.Success(t, "new run container", err) - defer c.Close() - - c.Run(ctx, "which coder").Assert(t, - tcli.Success(), - tcli.StdoutMatches("/usr/sbin/coder"), - tcli.StderrEmpty(), - ) - - c.Run(ctx, "coder --version").Assert(t, - tcli.StderrEmpty(), - tcli.Success(), - tcli.StdoutMatches("linux"), - ) - - c.Run(ctx, "coder --help").Assert(t, - tcli.Success(), - tcli.StdoutMatches("Available Commands"), - ) - - headlessLogin(ctx, t, c) - - c.Run(ctx, "coder envs").Assert(t, - tcli.Success(), - ) - - c.Run(ctx, "coder envs ls").Assert(t, - tcli.Success(), - ) - - c.Run(ctx, "coder urls").Assert(t, - tcli.Success(), - ) - - c.Run(ctx, "coder sync").Assert(t, - tcli.Error(), - ) - - c.Run(ctx, "coder sh").Assert(t, - tcli.Error(), - ) - - c.Run(ctx, "coder logout").Assert(t, - tcli.Success(), - ) - - c.Run(ctx, "coder envs ls").Assert(t, - tcli.Error(), - ) + } var seededRand = rand.New(rand.NewSource(time.Now().UnixNano())) diff --git a/ci/integration/secrets_test.go b/ci/integration/secrets_test.go index dc063b9b..fadcc84e 100644 --- a/ci/integration/secrets_test.go +++ b/ci/integration/secrets_test.go @@ -5,91 +5,77 @@ import ( "fmt" "regexp" "testing" - "time" "cdr.dev/coder-cli/ci/tcli" - "cdr.dev/slog/sloggers/slogtest/assert" ) func TestSecrets(t *testing.T) { t.Parallel() - ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5) - defer cancel() - - c, err := tcli.NewContainerRunner(ctx, &tcli.ContainerConfig{ - Image: "codercom/enterprise-dev", - Name: "secrets-cli-tests", - BindMounts: map[string]string{ - binpath: "/bin/coder", - }, + run(t, "secrets-cli-tests", func(t *testing.T, ctx context.Context, c *tcli.ContainerRunner) { + headlessLogin(ctx, t, c) + + c.Run(ctx, "coder secrets ls").Assert(t, + tcli.Success(), + ) + + name, value := randString(8), randString(8) + + c.Run(ctx, "coder secrets create").Assert(t, + tcli.Error(), + ) + + // this tests the "Value:" prompt fallback + c.Run(ctx, fmt.Sprintf("echo %s | coder secrets create %s --from-prompt", value, name)).Assert(t, + tcli.Success(), + tcli.StderrEmpty(), + ) + + c.Run(ctx, "coder secrets ls").Assert(t, + tcli.Success(), + tcli.StderrEmpty(), + tcli.StdoutMatches("Value"), + tcli.StdoutMatches(regexp.QuoteMeta(name)), + ) + + c.Run(ctx, "coder secrets view "+name).Assert(t, + tcli.Success(), + tcli.StderrEmpty(), + tcli.StdoutMatches(regexp.QuoteMeta(value)), + ) + + c.Run(ctx, "coder secrets rm").Assert(t, + tcli.Error(), + ) + c.Run(ctx, "coder secrets rm "+name).Assert(t, + tcli.Success(), + ) + c.Run(ctx, "coder secrets view "+name).Assert(t, + tcli.Error(), + tcli.StdoutEmpty(), + ) + + name, value = randString(8), randString(8) + + c.Run(ctx, fmt.Sprintf("coder secrets create %s --from-literal %s", name, value)).Assert(t, + tcli.Success(), + tcli.StderrEmpty(), + ) + + c.Run(ctx, "coder secrets view "+name).Assert(t, + tcli.Success(), + tcli.StdoutMatches(regexp.QuoteMeta(value)), + ) + + name, value = randString(8), randString(8) + c.Run(ctx, fmt.Sprintf("echo %s > ~/secret.json", value)).Assert(t, + tcli.Success(), + ) + c.Run(ctx, fmt.Sprintf("coder secrets create %s --from-file ~/secret.json", name)).Assert(t, + tcli.Success(), + ) + c.Run(ctx, "coder secrets view "+name).Assert(t, + tcli.Success(), + tcli.StdoutMatches(regexp.QuoteMeta(value)), + ) }) - assert.Success(t, "new run container", err) - defer c.Close() - - headlessLogin(ctx, t, c) - - c.Run(ctx, "coder secrets ls").Assert(t, - tcli.Success(), - ) - - name, value := randString(8), randString(8) - - c.Run(ctx, "coder secrets create").Assert(t, - tcli.Error(), - ) - - // this tests the "Value:" prompt fallback - c.Run(ctx, fmt.Sprintf("echo %s | coder secrets create %s --from-prompt", value, name)).Assert(t, - tcli.Success(), - tcli.StderrEmpty(), - ) - - c.Run(ctx, "coder secrets ls").Assert(t, - tcli.Success(), - tcli.StderrEmpty(), - tcli.StdoutMatches("Value"), - tcli.StdoutMatches(regexp.QuoteMeta(name)), - ) - - c.Run(ctx, "coder secrets view "+name).Assert(t, - tcli.Success(), - tcli.StderrEmpty(), - tcli.StdoutMatches(regexp.QuoteMeta(value)), - ) - - c.Run(ctx, "coder secrets rm").Assert(t, - tcli.Error(), - ) - c.Run(ctx, "coder secrets rm "+name).Assert(t, - tcli.Success(), - ) - c.Run(ctx, "coder secrets view "+name).Assert(t, - tcli.Error(), - tcli.StdoutEmpty(), - ) - - name, value = randString(8), randString(8) - - c.Run(ctx, fmt.Sprintf("coder secrets create %s --from-literal %s", name, value)).Assert(t, - tcli.Success(), - tcli.StderrEmpty(), - ) - - c.Run(ctx, "coder secrets view "+name).Assert(t, - tcli.Success(), - tcli.StdoutMatches(regexp.QuoteMeta(value)), - ) - - name, value = randString(8), randString(8) - c.Run(ctx, fmt.Sprintf("echo %s > ~/secret.json", value)).Assert(t, - tcli.Success(), - ) - c.Run(ctx, fmt.Sprintf("coder secrets create %s --from-file ~/secret.json", name)).Assert(t, - tcli.Success(), - ) - // - c.Run(ctx, "coder secrets view "+name).Assert(t, - tcli.Success(), - tcli.StdoutMatches(regexp.QuoteMeta(value)), - ) } diff --git a/ci/integration/ssh_test.go b/ci/integration/ssh_test.go new file mode 100644 index 00000000..273e3850 --- /dev/null +++ b/ci/integration/ssh_test.go @@ -0,0 +1,18 @@ +package integration + +import ( + "context" + "testing" + + "cdr.dev/coder-cli/ci/tcli" +) + +func TestSSH(t *testing.T) { + t.Parallel() + run(t, "ssh-coder-cli-tests", func(t *testing.T, ctx context.Context, c *tcli.ContainerRunner) { + headlessLogin(ctx, t, c) + c.Run(ctx, "coder config-ssh").Assert(t, + tcli.Success(), + ) + }) +} diff --git a/ci/integration/users_test.go b/ci/integration/users_test.go index 659ccc7a..e3c7e6f3 100644 --- a/ci/integration/users_test.go +++ b/ci/integration/users_test.go @@ -3,7 +3,6 @@ package integration import ( "context" "testing" - "time" "cdr.dev/coder-cli/ci/tcli" "cdr.dev/coder-cli/internal/entclient" @@ -12,45 +11,34 @@ import ( func TestUsers(t *testing.T) { t.Parallel() - ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5) - defer cancel() - - c, err := tcli.NewContainerRunner(ctx, &tcli.ContainerConfig{ - Image: "codercom/enterprise-dev", - Name: "users-cli-tests", - BindMounts: map[string]string{ - binpath: "/bin/coder", - }, + run(t, "users-cli-tests", func(t *testing.T, ctx context.Context, c *tcli.ContainerRunner) { + c.Run(ctx, "which coder").Assert(t, + tcli.Success(), + tcli.StdoutMatches("/usr/sbin/coder"), + tcli.StderrEmpty(), + ) + + headlessLogin(ctx, t, c) + + var user entclient.User + c.Run(ctx, `coder users ls --output json | jq -c '.[] | select( .username == "charlie")'`).Assert(t, + tcli.Success(), + tcli.StdoutJSONUnmarshal(&user), + ) + assert.Equal(t, "user email is as expected", "charlie@coder.com", user.Email) + assert.Equal(t, "username is as expected", "Charlie", user.Name) + + c.Run(ctx, "coder users ls --output human | grep charlie").Assert(t, + tcli.Success(), + tcli.StdoutMatches("charlie"), + ) + + c.Run(ctx, "coder logout").Assert(t, + tcli.Success(), + ) + + c.Run(ctx, "coder users ls").Assert(t, + tcli.Error(), + ) }) - assert.Success(t, "new run container", err) - defer c.Close() - - c.Run(ctx, "which coder").Assert(t, - tcli.Success(), - tcli.StdoutMatches("/usr/sbin/coder"), - tcli.StderrEmpty(), - ) - - headlessLogin(ctx, t, c) - - var user entclient.User - c.Run(ctx, `coder users ls --output json | jq -c '.[] | select( .username == "charlie")'`).Assert(t, - tcli.Success(), - tcli.StdoutJSONUnmarshal(&user), - ) - assert.Equal(t, "user email is as expected", "charlie@coder.com", user.Email) - assert.Equal(t, "username is as expected", "Charlie", user.Name) - - c.Run(ctx, "coder users ls --output human | grep charlie").Assert(t, - tcli.Success(), - tcli.StdoutMatches("charlie"), - ) - - c.Run(ctx, "coder logout").Assert(t, - tcli.Success(), - ) - - c.Run(ctx, "coder users ls").Assert(t, - tcli.Error(), - ) } diff --git a/ci/steps/build.sh b/ci/steps/build.sh index 8411ccde..8c3a2326 100755 --- a/ci/steps/build.sh +++ b/ci/steps/build.sh @@ -21,7 +21,8 @@ build(){ tar -czf "$tarname" coder popd - cp "$tmpdir/$tarname" ../bin + mkdir -p ../bin + cp "$tmpdir/$tarname" ../bin/$tarname rm -rf "$tmpdir" } diff --git a/internal/cmd/configssh.go b/internal/cmd/configssh.go index 0e755ff1..1d1c3c7b 100644 --- a/internal/cmd/configssh.go +++ b/internal/cmd/configssh.go @@ -114,6 +114,10 @@ func configSSH(configpath *string, remove *bool) func(cmd *cobra.Command, _ []st currentConfig = currentConfig[:startIndex-1] + currentConfig[endIndex+len(endToken)+1:] } + err = os.MkdirAll(filepath.Dir(*configpath), os.ModePerm) + if err != nil { + return xerrors.Errorf("make configuration directory: %w", err) + } err = writeStr(*configpath, currentConfig+newConfig) if err != nil { return xerrors.Errorf("write new configurations to ssh config file %q: %w", *configpath, err) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy