fix: Standardize and wrap example descriptions at 80 chars (#2894)

This commit is contained in:
Mathias Fredriksson
2022-07-11 19:08:09 +03:00
committed by GitHub
parent 50e8a27d04
commit 749694b7de
12 changed files with 223 additions and 103 deletions

View File

@ -141,15 +141,16 @@ func configSSH() *cobra.Command {
Annotations: workspaceCommand, Annotations: workspaceCommand,
Use: "config-ssh", Use: "config-ssh",
Short: "Populate your SSH config with Host entries for all of your workspaces", Short: "Populate your SSH config with Host entries for all of your workspaces",
Example: ` Example: formatExamples(
- You can use -o (or --ssh-option) so set SSH options to be used for all your example{
workspaces. Description: "You can use -o (or --ssh-option) so set SSH options to be used for all your workspaces",
Command: "coder config-ssh -o ForwardAgent=yes",
` + cliui.Styles.Code.Render("$ coder config-ssh -o ForwardAgent=yes") + ` },
example{
- You can use --dry-run (or -n) to see the changes that would be made. Description: "You can use --dry-run (or -n) to see the changes that would be made",
Command: "coder config-ssh --dry-run",
` + cliui.Styles.Code.Render("$ coder config-ssh --dry-run"), },
),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd) client, err := createClient(cmd)
if err != nil { if err != nil {

View File

@ -18,14 +18,17 @@ import (
) )
func dotfiles() *cobra.Command { func dotfiles() *cobra.Command {
var ( var symlinkDir string
symlinkDir string
)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "dotfiles [git_repo_url]", Use: "dotfiles [git_repo_url]",
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Short: "Check out and install a dotfiles repository.", Short: "Check out and install a dotfiles repository.",
Example: "coder dotfiles [-y] git@github.com:example/dotfiles.git", Example: formatExamples(
example{
Description: "Check out and install a dotfiles repository without prompts",
Command: "coder dotfiles --yes git@github.com:example/dotfiles.git",
},
),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
var ( var (
dotfilesRepoDir = "dotfiles" dotfilesRepoDir = "dotfiles"

View File

@ -11,7 +11,11 @@ import (
func parameters() *cobra.Command { func parameters() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Short: "List parameters for a given scope", Short: "List parameters for a given scope",
Example: "coder parameters list workspace my-workspace", Example: formatExamples(
example{
Command: "coder parameters list workspace my-workspace",
},
),
Use: "parameters", Use: "parameters",
// Currently hidden as this shows parameter values, not parameter // Currently hidden as this shows parameter values, not parameter
// schemes. Until we have a good way to distinguish the two, it's better // schemes. Until we have a good way to distinguish the two, it's better

View File

@ -32,28 +32,28 @@ func portForward() *cobra.Command {
Short: "Forward one or more ports from the local machine to the remote workspace", Short: "Forward one or more ports from the local machine to the remote workspace",
Aliases: []string{"tunnel"}, Aliases: []string{"tunnel"},
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Example: ` Example: formatExamples(
- Port forward a single TCP port from 1234 in the workspace to port 5678 on example{
your local machine Description: "Port forward a single TCP port from 1234 in the workspace to port 5678 on your local machine",
Command: "coder port-forward <workspace> --tcp 5678:1234",
` + cliui.Styles.Code.Render("$ coder port-forward <workspace> --tcp 5678:1234") + ` },
example{
- Port forward a single UDP port from port 9000 to port 9000 on your local Description: "Port forward a single UDP port from port 9000 to port 9000 on your local machine",
machine Command: "coder port-forward <workspace> --udp 9000",
},
` + cliui.Styles.Code.Render("$ coder port-forward <workspace> --udp 9000") + ` example{
Description: "Forward a Unix socket in the workspace to a local Unix socket",
- Forward a Unix socket in the workspace to a local Unix socket Command: "coder port-forward <workspace> --unix ./local.sock:~/remote.sock",
},
` + cliui.Styles.Code.Render("$ coder port-forward <workspace> --unix ./local.sock:~/remote.sock") + ` example{
Description: "Forward a Unix socket in the workspace to a local TCP port",
- Forward a Unix socket in the workspace to a local TCP port Command: "coder port-forward <workspace> --unix 8080:~/remote.sock",
},
` + cliui.Styles.Code.Render("$ coder port-forward <workspace> --unix 8080:~/remote.sock") + ` example{
Description: "Port forward multiple TCP ports and a UDP port",
- Port forward multiple TCP ports and a UDP port Command: "coder port-forward <workspace> --tcp 8080:8080 --tcp 9000:3000 --udp 5353:53",
},
` + cliui.Styles.Code.Render("$ coder port-forward <workspace> --tcp 8080:8080 --tcp 9000:3000 --udp 5353:53"), ),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
specs, err := parsePortForwards(tcpForwards, udpForwards, unixForwards) specs, err := parsePortForwards(tcpForwards, udpForwards, unixForwards)
if err != nil { if err != nil {

View File

@ -101,12 +101,16 @@ func Root() *cobra.Command {
_, _ = fmt.Fprintln(cmd.ErrOrStderr()) _, _ = fmt.Fprintln(cmd.ErrOrStderr())
} }
}, },
Example: formatExamples(
Example: ` Start a Coder server. example{
` + cliui.Styles.Code.Render("$ coder server") + ` Description: "Start a Coder server",
Command: "coder server",
Get started by creating a template from an example. },
` + cliui.Styles.Code.Render("$ coder templates init"), example{
Description: "Get started by creating a template from an example",
Command: "coder templates init",
},
),
} }
cmd.AddCommand( cmd.AddCommand(
@ -160,7 +164,6 @@ func versionCmd() *cobra.Command {
return &cobra.Command{ return &cobra.Command{
Use: "version", Use: "version",
Short: "Show coder version", Short: "Show coder version",
Example: "coder version",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
var str strings.Builder var str strings.Builder
_, _ = str.WriteString(fmt.Sprintf("Coder %s", buildinfo.Version())) _, _ = str.WriteString(fmt.Sprintf("Coder %s", buildinfo.Version()))
@ -370,6 +373,34 @@ Use "{{.CommandPath}} [command] --help" for more information about a command.
{{end}}` {{end}}`
} }
// example represents a standard example for command usage, to be used
// with formatExamples.
type example struct {
Description string
Command string
}
// formatExamples formats the exampels as width wrapped bulletpoint
// descriptions with the command underneath.
func formatExamples(examples ...example) string {
wrap := cliui.Styles.Wrap.Copy()
wrap.PaddingLeft(4)
var sb strings.Builder
for i, e := range examples {
if len(e.Description) > 0 {
_, _ = sb.WriteString(" - " + wrap.Render(e.Description + ":")[4:] + "\n\n ")
}
// We add 1 space here because `cliui.Styles.Code` adds an extra
// space. This makes the code block align at an even 2 or 6
// spaces for symmetry.
_, _ = sb.WriteString(" " + cliui.Styles.Code.Render(fmt.Sprintf("$ %s", e.Command)))
if i < len(examples)-1 {
_, _ = sb.WriteString("\n\n")
}
}
return sb.String()
}
// FormatCobraError colorizes and adds "--help" docs to cobra commands. // FormatCobraError colorizes and adds "--help" docs to cobra commands.
func FormatCobraError(err error, cmd *cobra.Command) string { func FormatCobraError(err error, cmd *cobra.Command) string {
helpErrMsg := fmt.Sprintf("Run '%s --help' for usage.", cmd.CommandPath()) helpErrMsg := fmt.Sprintf("Run '%s --help' for usage.", cmd.CommandPath())

66
cli/root_internal_test.go Normal file
View File

@ -0,0 +1,66 @@
package cli
import (
"testing"
"github.com/stretchr/testify/require"
)
func Test_formatExamples(t *testing.T) {
t.Parallel()
tests := []struct {
name string
examples []example
wantMatches []string
}{
{
name: "No examples",
examples: nil,
wantMatches: nil,
},
{
name: "Output examples",
examples: []example{
{
Description: "Hello world",
Command: "echo hello",
},
{
Description: "Bye bye",
Command: "echo bye",
},
},
wantMatches: []string{
"Hello world", "echo hello",
"Bye bye", "echo bye",
},
},
{
name: "No description outputs commands",
examples: []example{
{
Command: "echo hello",
},
},
wantMatches: []string{
"echo hello",
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got := formatExamples(tt.examples...)
if len(tt.wantMatches) == 0 {
require.Empty(t, got)
} else {
for _, want := range tt.wantMatches {
require.Contains(t, got, want)
}
}
})
}
}

View File

@ -4,10 +4,9 @@ import (
"bytes" "bytes"
"testing" "testing"
"github.com/coder/coder/buildinfo"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/coder/coder/buildinfo"
"github.com/coder/coder/cli" "github.com/coder/coder/cli"
"github.com/coder/coder/cli/clitest" "github.com/coder/coder/cli/clitest"
) )

View File

@ -103,7 +103,12 @@ func scheduleStart() *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Annotations: workspaceCommand, Annotations: workspaceCommand,
Use: "start <workspace-name> { <start-time> [day-of-week] [location] | manual }", Use: "start <workspace-name> { <start-time> [day-of-week] [location] | manual }",
Example: `start my-workspace 9:30AM Mon-Fri Europe/Dublin`, Example: formatExamples(
example{
Description: "Set the workspace to start at 9:30am (in Dublin) from Monday to Friday",
Command: "coder schedule start my-workspace 9:30AM Mon-Fri Europe/Dublin",
},
),
Short: "Edit workspace start schedule", Short: "Edit workspace start schedule",
Long: scheduleStartDescriptionLong, Long: scheduleStartDescriptionLong,
Args: cobra.RangeArgs(2, 4), Args: cobra.RangeArgs(2, 4),
@ -151,7 +156,11 @@ func scheduleStop() *cobra.Command {
Annotations: workspaceCommand, Annotations: workspaceCommand,
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
Use: "stop <workspace-name> { <duration> | manual }", Use: "stop <workspace-name> { <duration> | manual }",
Example: `stop my-workspace 2h30m`, Example: formatExamples(
example{
Command: "coder schedule stop my-workspace 2h30m",
},
),
Short: "Edit workspace stop schedule", Short: "Edit workspace stop schedule",
Long: scheduleStopDescriptionLong, Long: scheduleStopDescriptionLong,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
@ -194,7 +203,11 @@ func scheduleOverride() *cobra.Command {
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
Annotations: workspaceCommand, Annotations: workspaceCommand,
Use: "override-stop <workspace-name> <duration from now>", Use: "override-stop <workspace-name> <duration from now>",
Example: "override-stop my-workspace 90m", Example: formatExamples(
example{
Command: "coder schedule override-stop my-workspace 90m",
},
),
Short: "Edit stop time of active workspace", Short: "Edit stop time of active workspace",
Long: scheduleOverrideDescriptionLong, Long: scheduleOverrideDescriptionLong,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {

View File

@ -16,18 +16,20 @@ func templates() *cobra.Command {
Use: "templates", Use: "templates",
Short: "Create, manage, and deploy templates", Short: "Create, manage, and deploy templates",
Aliases: []string{"template"}, Aliases: []string{"template"},
Example: ` Example: formatExamples(
- Create a template for developers to create workspaces example{
Description: "Create a template for developers to create workspaces",
` + cliui.Styles.Code.Render("$ coder templates create") + ` Command: "coder templates create",
},
- Make changes to your template, and plan the changes example{
Description: "Make changes to your template, and plan the changes",
` + cliui.Styles.Code.Render("$ coder templates plan <name>") + ` Command: "coder templates plan my-template",
},
- Update the template. Your developers can update their workspaces example{
Description: "Update the template. Your developers can update their workspaces",
` + cliui.Styles.Code.Render("$ coder templates update <name>"), Command: "coder templates update my-template",
},
),
} }
cmd.AddCommand( cmd.AddCommand(
templateCreate(), templateCreate(),

View File

@ -9,9 +9,7 @@ import (
) )
func userList() *cobra.Command { func userList() *cobra.Command {
var ( var columns []string
columns []string
)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "list", Use: "list",
Aliases: []string{"ls"}, Aliases: []string{"ls"},
@ -35,13 +33,15 @@ func userList() *cobra.Command {
} }
func userSingle() *cobra.Command { func userSingle() *cobra.Command {
var ( var columns []string
columns []string
)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "show <username|user_id|'me'>", Use: "show <username|user_id|'me'>",
Short: "Show a single user. Use 'me' to indicate the currently authenticated user.", Short: "Show a single user. Use 'me' to indicate the currently authenticated user.",
Example: "coder users show me", Example: formatExamples(
example{
Command: "coder users show me",
},
),
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd) client, err := createClient(cmd)

View File

@ -31,15 +31,17 @@ func createUserStatusCommand(sdkStatus codersdk.UserStatus) *cobra.Command {
panic(fmt.Sprintf("%s is not supported", sdkStatus)) panic(fmt.Sprintf("%s is not supported", sdkStatus))
} }
var ( var columns []string
columns []string
)
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: fmt.Sprintf("%s <username|user_id>", verb), Use: fmt.Sprintf("%s <username|user_id>", verb),
Short: short, Short: short,
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
Aliases: aliases, Aliases: aliases,
Example: fmt.Sprintf("coder users %s example_user", verb), Example: formatExamples(
example{
Command: fmt.Sprintf("coder users %s example_user", verb),
},
),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
client, err := createClient(cmd) client, err := createClient(cmd)
if err != nil { if err != nil {

View File

@ -37,21 +37,20 @@ func wireguardPortForward() *cobra.Command {
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
// Hide all wireguard commands for now while we test! // Hide all wireguard commands for now while we test!
Hidden: true, Hidden: true,
Example: ` Example: formatExamples(
- Port forward a single TCP port from 1234 in the workspace to port 5678 on example{
your local machine Description: "Port forward a single TCP port from 1234 in the workspace to port 5678 on your local machine",
Command: "coder wireguard-port-forward <workspace> --tcp 5678:1234",
` + cliui.Styles.Code.Render("$ coder port-forward <workspace> --tcp 5678:1234") + ` },
example{
- Port forward a single UDP port from port 9000 to port 9000 on your local Description: "Port forward a single UDP port from port 9000 to port 9000 on your local machine",
machine Command: "coder wireguard-port-forward <workspace> --udp 9000",
},
` + cliui.Styles.Code.Render("$ coder port-forward <workspace> --udp 9000") + ` example{
Description: "Port forward multiple TCP ports and a UDP port",
- Port forward multiple TCP ports and a UDP port Command: "coder wireguard-port-forward <workspace> --tcp 8080:8080 --tcp 9000:3000 --udp 5353:53",
},
` + cliui.Styles.Code.Render("$ coder port-forward <workspace> --tcp 8080:8080 --tcp 9000:3000 --udp 5353:53") + ` ),
`,
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
specs, err := parsePortForwards(tcpForwards, nil, nil) specs, err := parsePortForwards(tcpForwards, nil, nil)
if err != nil { if err != nil {