diff --git a/cli/root.go b/cli/root.go index 97e5e5620f674..a7c1b90ad751f 100644 --- a/cli/root.go +++ b/cli/root.go @@ -6,6 +6,7 @@ import ( "os" "strconv" "strings" + "text/template" "time" "golang.org/x/xerrors" @@ -28,7 +29,7 @@ var ( // Applied as annotations to workspace commands // so they display in a separated "help" section. workspaceCommand = map[string]string{ - "workspaces": " ", + "workspaces": "", } ) @@ -52,12 +53,8 @@ var ( ) func init() { - // Customizes the color of headings to make subcommands more visually - // appealing. - header := cliui.Styles.Placeholder - cobra.AddTemplateFunc("usageHeader", func(s string) string { - return header.Render(s) - }) + // Set cobra template functions in init to avoid conflicts in tests. + cobra.AddTemplateFuncs(templateFunctions) } func Root() *cobra.Command { @@ -311,6 +308,30 @@ func isTTYOut(cmd *cobra.Command) bool { return isatty.IsTerminal(file.Fd()) } +var templateFunctions = template.FuncMap{ + "usageHeader": usageHeader, + "isWorkspaceCommand": isWorkspaceCommand, +} + +func usageHeader(s string) string { + // Customizes the color of headings to make subcommands more visually + // appealing. + return cliui.Styles.Placeholder.Render(s) +} + +func isWorkspaceCommand(cmd *cobra.Command) bool { + if _, ok := cmd.Annotations["workspaces"]; ok { + return true + } + var ws bool + cmd.VisitParents(func(cmd *cobra.Command) { + if _, ok := cmd.Annotations["workspaces"]; ok { + ws = true + } + }) + return ws +} + func usageTemplate() string { // usageHeader is defined in init(). return `{{usageHeader "Usage:"}} @@ -331,19 +352,21 @@ func usageTemplate() string { {{.Example}} {{end}} +{{- $isRootHelp := (not .HasParent)}} {{- if .HasAvailableSubCommands}} {{usageHeader "Commands:"}} {{- range .Commands}} - {{- if (or (and .IsAvailableCommand (eq (len .Annotations) 0)) (eq .Name "help"))}} + {{- $isRootWorkspaceCommand := (and $isRootHelp (isWorkspaceCommand .))}} + {{- if (or (and .IsAvailableCommand (not $isRootWorkspaceCommand)) (eq .Name "help"))}} {{rpad .Name .NamePadding }} {{.Short}} {{- end}} {{- end}} {{end}} -{{- if and (not .HasParent) .HasAvailableSubCommands}} +{{- if (and $isRootHelp .HasAvailableSubCommands)}} {{usageHeader "Workspace Commands:"}} {{- range .Commands}} - {{- if (and .IsAvailableCommand (ne (index .Annotations "workspaces") ""))}} + {{- if (and .IsAvailableCommand (isWorkspaceCommand .))}} {{rpad .Name .NamePadding }} {{.Short}} {{- end}} {{- end}} @@ -351,12 +374,12 @@ func usageTemplate() string { {{- if .HasAvailableLocalFlags}} {{usageHeader "Flags:"}} -{{.LocalFlags.FlagUsagesWrapped 100}} +{{.LocalFlags.FlagUsagesWrapped 100 | trimTrailingWhitespaces}} {{end}} {{- if .HasAvailableInheritedFlags}} {{usageHeader "Global Flags:"}} -{{.InheritedFlags.FlagUsagesWrapped 100}} +{{.InheritedFlags.FlagUsagesWrapped 100 | trimTrailingWhitespaces}} {{end}} {{- if .HasHelpSubCommands}} diff --git a/cli/schedule.go b/cli/schedule.go index 1cd7cc65edca9..b583915baf7f7 100644 --- a/cli/schedule.go +++ b/cli/schedule.go @@ -17,12 +17,6 @@ import ( ) const ( - scheduleDescriptionLong = `Modify scheduled stop and start times for your workspace: - * schedule show: show workspace schedule - * schedule start: edit workspace start schedule - * schedule stop: edit workspace stop schedule - * schedule override-stop: edit stop time of active workspace -` scheduleShowDescriptionLong = `Shows the following information for the given workspace: * The automatic start schedule * The next scheduled start time @@ -64,24 +58,24 @@ func schedules() *cobra.Command { Annotations: workspaceCommand, Use: "schedule { show | start | stop | override } ", Short: "Modify scheduled stop and start times for your workspace", - Long: scheduleDescriptionLong, } - scheduleCmd.AddCommand(scheduleShow()) - scheduleCmd.AddCommand(scheduleStart()) - scheduleCmd.AddCommand(scheduleStop()) - scheduleCmd.AddCommand(scheduleOverride()) + scheduleCmd.AddCommand( + scheduleShow(), + scheduleStart(), + scheduleStop(), + scheduleOverride(), + ) return scheduleCmd } func scheduleShow() *cobra.Command { showCmd := &cobra.Command{ - Annotations: workspaceCommand, - Use: "show ", - Short: "Show workspace schedule", - Long: scheduleShowDescriptionLong, - Args: cobra.ExactArgs(1), + Use: "show ", + Short: "Show workspace schedule", + Long: scheduleShowDescriptionLong, + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { client, err := createClient(cmd) if err != nil { @@ -101,8 +95,7 @@ func scheduleShow() *cobra.Command { func scheduleStart() *cobra.Command { cmd := &cobra.Command{ - Annotations: workspaceCommand, - Use: "start { [day-of-week] [location] | manual }", + Use: "start { [day-of-week] [location] | manual }", Example: formatExamples( example{ Description: "Set the workspace to start at 9:30am (in Dublin) from Monday to Friday", @@ -153,9 +146,8 @@ func scheduleStart() *cobra.Command { func scheduleStop() *cobra.Command { return &cobra.Command{ - Annotations: workspaceCommand, - Args: cobra.ExactArgs(2), - Use: "stop { | manual }", + Args: cobra.ExactArgs(2), + Use: "stop { | manual }", Example: formatExamples( example{ Command: "coder schedule stop my-workspace 2h30m", @@ -200,9 +192,8 @@ func scheduleStop() *cobra.Command { func scheduleOverride() *cobra.Command { overrideCmd := &cobra.Command{ - Args: cobra.ExactArgs(2), - Annotations: workspaceCommand, - Use: "override-stop ", + Args: cobra.ExactArgs(2), + Use: "override-stop ", Example: formatExamples( example{ Command: "coder schedule override-stop my-workspace 90m",