Skip to content

Commit ab31e74

Browse files
authored
Better help (#2733)
* Wrap command and flag descriptions for cleaner help output * Move help command to root, group commands * Add deprecation warnings, hide long deprecated commands * Wrap command and flag descriptions for cleaner help output * Move help command to root, group commands * Add deprecation warnings, hide long deprecated commands * Add subcommands to root command output * Deprecate history * Fix wrapping for unauthenticated message * tweak wording * Fix broken docker secrets docs url
1 parent a7afc1a commit ab31e74

File tree

16 files changed

+249
-247
lines changed

16 files changed

+249
-247
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ require (
3232
github.com/inancgumus/screen v0.0.0-20190314163918-06e984b86ed3
3333
github.com/jinzhu/copier v0.3.5
3434
github.com/jpillora/backoff v1.0.0
35+
github.com/kr/text v0.2.0
3536
github.com/loadsmart/calver-go v0.0.0-20230323142215-56cf73a68e8a
3637
github.com/logrusorgru/aurora v2.0.3+incompatible
3738
github.com/mattn/go-colorable v0.1.13

internal/cli/cli.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,22 @@ import (
55
"context"
66
"errors"
77
"fmt"
8+
"html/template"
9+
"os"
810
"runtime/debug"
11+
"strings"
912
"time"
1013

1114
"github.com/AlecAivazis/survey/v2/terminal"
15+
"github.com/MakeNowJust/heredoc/v2"
16+
"github.com/kr/text"
1217
"github.com/spf13/cobra"
18+
"github.com/spf13/pflag"
1319
"github.com/superfly/flyctl/internal/flag/flagnames"
1420
"github.com/superfly/flyctl/internal/flyerr"
1521
"github.com/superfly/flyctl/internal/metrics"
1622
"github.com/superfly/flyctl/internal/task"
23+
"golang.org/x/term"
1724

1825
"github.com/superfly/flyctl/iostreams"
1926
"github.com/superfly/graphql"
@@ -56,6 +63,14 @@ func Run(ctx context.Context, io *iostreams.IOStreams, args ...string) int {
5663
cmd.SetArgs(args)
5764
cmd.SilenceErrors = true
5865

66+
// configure help templates and helpers
67+
cobra.AddTemplateFuncs(template.FuncMap{
68+
"wrapFlagUsages": wrapFlagUsages,
69+
"wrapText": wrapText,
70+
})
71+
cmd.SetUsageTemplate(usageTemplate)
72+
cmd.SetHelpTemplate(helpTemplate)
73+
5974
cs := io.ColorScheme()
6075

6176
cmd, err = cmd.ExecuteContextC(ctx)
@@ -132,3 +147,66 @@ func printError(io *iostreams.IOStreams, cs *iostreams.ColorScheme, cmd *cobra.C
132147
func NewRootCommand() *cobra.Command {
133148
return root.New()
134149
}
150+
151+
func wrapFlagUsages(cmd *pflag.FlagSet) string {
152+
width := helpWidth()
153+
154+
return cmd.FlagUsagesWrapped(width - 1)
155+
}
156+
157+
func wrapText(s string) string {
158+
width := helpWidth()
159+
160+
return strings.TrimSpace(text.Wrap(heredoc.Doc(s), width-1))
161+
}
162+
163+
func helpWidth() int {
164+
fd := int(os.Stdout.Fd())
165+
width := 80
166+
167+
// Get the terminal width and dynamically set
168+
termWidth, _, err := term.GetSize(fd)
169+
if err == nil {
170+
width = termWidth
171+
}
172+
173+
return min(120, width)
174+
}
175+
176+
// identical to the default cobra help template, but utilizes wrapText
177+
// https://github.com/spf13/cobra/blob/fd865a44e3c48afeb6a6dbddadb8a5519173e029/command.go#L580-L582
178+
const helpTemplate = `{{with (or .Long .Short)}}{{. | trimTrailingWhitespaces | wrapText}}
179+
180+
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
181+
182+
// identical to the default cobra usage template, but utilizes wrapFlagUsages
183+
// https://github.com/spf13/cobra/blob/fd865a44e3c48afeb6a6dbddadb8a5519173e029/command.go#L539-L568
184+
const usageTemplate = `Usage:{{if .Runnable}}
185+
{{.UseLine}}{{end}}{{if .HasAvailableSubCommands}}
186+
{{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}}
187+
188+
Aliases:
189+
{{.NameAndAliases}}{{end}}{{if .HasExample}}
190+
191+
Examples:
192+
{{.Example}}{{end}}{{if .HasAvailableSubCommands}}{{$cmds := .Commands}}{{if eq (len .Groups) 0}}
193+
194+
Available Commands:{{range $cmds}}{{if (or .IsAvailableCommand (eq .Name "help"))}}
195+
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{else}}{{range $group := .Groups}}
196+
197+
{{.Title}}{{range $cmds}}{{if (and (eq .GroupID $group.ID) (or .IsAvailableCommand (eq .Name "help")))}}
198+
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if not .AllChildCommandsHaveGroup}}
199+
200+
Additional Commands:{{range $cmds}}{{if (and (eq .GroupID "") (or .IsAvailableCommand (eq .Name "help")))}}
201+
{{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}}
202+
203+
Flags:
204+
{{wrapFlagUsages .LocalFlags | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}}
205+
206+
Global Flags:
207+
{{wrapFlagUsages .InheritedFlags | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}}
208+
209+
Additional help topics:{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}}
210+
{{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}}
211+
212+
Use "{{.CommandPath}} [command] --help" for more information about a command.{{end}}`

internal/command/command.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"strconv"
1313
"time"
1414

15-
"github.com/MakeNowJust/heredoc/v2"
1615
"github.com/logrusorgru/aurora"
1716
"github.com/spf13/cobra"
1817
"github.com/superfly/flyctl/api"
@@ -39,7 +38,7 @@ func New(usage, short, long string, fn Runner, p ...preparers.Preparer) *cobra.C
3938
return &cobra.Command{
4039
Use: usage,
4140
Short: short,
42-
Long: heredoc.Doc(long),
41+
Long: long,
4342
RunE: newRunE(fn, p...),
4443
}
4544
}

internal/command/create/create.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ func New() (cmd *cobra.Command) {
1010
cmd = &cobra.Command{
1111
Use: "create",
1212
Hidden: true,
13-
Deprecated: "replaced by 'apps create'",
13+
Deprecated: "use `fly apps create` instead",
1414
}
1515

1616
flag.Add(cmd,

internal/command/curl/curl.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ func New() (cmd *cobra.Command) {
3737
cmd = command.New("curl <URL>", short, long, run,
3838
command.RequireSession,
3939
)
40+
cmd.Deprecated = "`fly curl` will be removed in a future release"
41+
cmd.Hidden = true
4042

4143
cmd.Args = cobra.ExactArgs(1)
4244

internal/command/destroy/destroy.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ from the Fly platform.
2020

2121
destroy := command.New(usage, short, long, apps.RunDestroy,
2222
command.RequireSession)
23+
destroy.Hidden = true
24+
destroy.Deprecated = "use `fly apps destroy` instead"
2325

2426
destroy.Args = cobra.ExactArgs(1)
2527

internal/command/dnsrecords/root.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ func New() *cobra.Command {
2424
long = "Manage DNS records within a domain"
2525
)
2626
cmd := command.New("dns-records", short, long, nil)
27+
cmd.Deprecated = "`fly dns-records` will be removed in a future release"
28+
cmd.Hidden = true
2729
cmd.AddCommand(
2830
newDNSRecordsList(),
2931
newDNSRecordsExport(),
@@ -40,6 +42,7 @@ func newDNSRecordsList() *cobra.Command {
4042
cmd := command.New("list <domain>", short, long, runDNSRecordsList,
4143
command.RequireSession,
4244
)
45+
cmd.Deprecated = "`fly dns-records list` will be removed in a future release"
4346
flag.Add(cmd,
4447
flag.JSONOutput(),
4548
)
@@ -55,6 +58,7 @@ func newDNSRecordsExport() *cobra.Command {
5558
cmd := command.New("export <domain> [filename]", short, long, runDNSRecordsExport,
5659
command.RequireSession,
5760
)
61+
cmd.Deprecated = "`fly dns-records export` will be removed in a future release"
5862
cmd.Args = cobra.RangeArgs(1, 2)
5963
return cmd
6064
}
@@ -67,6 +71,7 @@ func newDNSRecordsImport() *cobra.Command {
6771
cmd := command.New("import <domain> [filename]", short, long, runDNSRecordsImport,
6872
command.RequireSession,
6973
)
74+
cmd.Deprecated = "`fly dns-records import` will be removed in a future release"
7075
cmd.Args = cobra.RangeArgs(1, 2)
7176
return cmd
7277
}

internal/command/domains/root.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ Notice: this feature is deprecated and no longer supported.
2828
You can still view existing domains, but registration is no longer possible.`
2929
)
3030
cmd := command.New("domains", short, long, nil)
31+
cmd.Deprecated = "`fly domains` will be removed in a future release"
32+
cmd.Hidden = true
3133
cmd.AddCommand(
3234
newDomainsList(),
3335
newDomainsShow(),

internal/command/help/help.go

Lines changed: 0 additions & 166 deletions
This file was deleted.

internal/command/history/history.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ events and their results.
3030
command.RequireSession,
3131
command.RequireAppName,
3232
)
33+
cmd.Deprecated = "Use `flyctl apps releases` instead"
34+
cmd.Hidden = true
3335

3436
cmd.Args = cobra.NoArgs
3537

0 commit comments

Comments
 (0)