From 0a2bb14df4cb8c0ce695ffe9d1f2d2a09b0657ab Mon Sep 17 00:00:00 2001 From: Michael Dwan Date: Thu, 24 Aug 2023 18:27:36 -0600 Subject: [PATCH] Move help command to root, group commands --- internal/command/help/help.go | 166 -------------------------- internal/command/root/root.go | 217 ++++++++++++++++++++++------------ 2 files changed, 141 insertions(+), 242 deletions(-) delete mode 100644 internal/command/help/help.go diff --git a/internal/command/help/help.go b/internal/command/help/help.go deleted file mode 100644 index 50580124aa..0000000000 --- a/internal/command/help/help.go +++ /dev/null @@ -1,166 +0,0 @@ -package help - -import ( - "context" - "fmt" - - "github.com/spf13/cobra" - "github.com/superfly/flyctl/client" - "github.com/superfly/flyctl/internal/command" - "github.com/superfly/flyctl/internal/flag" - - "github.com/olekukonko/tablewriter" -) - -var deprecatedCommands = map[string]bool{ - "completion": true, - "curl": true, - "dns-records": true, - "domains": true, -} - -func New(root *cobra.Command) *cobra.Command { - cmd := command.New("help", "Help on flyctl commands", "", Help(root)) - - list := command.New("commands", "All flyctl commands", "", HelpCommands(root)) - flag.Add(list, flag.Bool{ - Name: "all", - Shorthand: "a", - Default: false, - Description: "show all commands, even the ones we secretly hate.", - }) - - cmd.AddCommand(list) - - return cmd -} - -// the output of `flyctl`, run by itself with no args -func NewRootHelp() *cobra.Command { - return command.New("", "", "", func(ctx context.Context) error { - auth := ` - -It doesn't look like you're logged in. Try "flyctl auth signup" to create an account, -or "flyctl auth login" to log in to an existing account.` - - if client.FromContext(ctx).Authenticated() { - auth = "" - } - - fmt.Printf(`This is flyctl, the Fly.io command line interface.%s - -Here's a few commands to get you started: - fly launch Launch a new application - fly apps Create and manage apps - fly postgres Create and manage Postgres databases - fly mysql Create and manage PlanetScale MySQL databases - fly redis Create and manage Upstash Redis databases - fly machines Create and manage individual Fly.io machines - -If you need help along the way: - fly help Display a complete list of commands - fly help Display help for a specific command, e.g. 'fly help launch' - -Visit https://fly.io/docs for additional documentation & guides -`, auth) - return nil - }) -} - -// the output of `flyctl help`, possibly with more arguments -func Help(root *cobra.Command) func(ctx context.Context) error { - return func(ctx context.Context) error { - if cmd, _, err := root.Find(flag.Args(ctx)); err == nil && cmd != root { - return cmd.Help() - } - - commands := map[string]*cobra.Command{} - - for _, cmd := range root.Commands() { - cmd := cmd - commands[cmd.Name()] = cmd - if len(cmd.Aliases) > 0 { - for _, alias := range cmd.Aliases { - commands[alias] = cmd - } - } - } - - listCommands := func(names []string) { - for _, name := range names { - fmt.Printf(" %s %s\n", tablewriter.PadRight(name, " ", 15), commands[name].Short) - } - } - - fmt.Printf(` -Deploying apps and machines: -`) - listCommands([]string{"apps", "machine", "launch", "deploy", "destroy", "open"}) - - fmt.Printf(` -Scaling and configuring: -`) - listCommands([]string{"scale", "regions", "secrets"}) - - fmt.Printf(` -Provisioning storage: -`) - listCommands([]string{"volumes", "mysql", "postgres", "redis", "consul"}) - - fmt.Printf(` -Networking configuration: -`) - listCommands([]string{"ips", "wireguard", "proxy", "certs"}) - - fmt.Printf(` -Monitoring and managing things: -`) - listCommands([]string{"logs", "status", "dashboard", "dig", "ping", "ssh", "sftp"}) - - fmt.Printf(` -Platform overview: -`) - listCommands([]string{"platform"}) - - fmt.Printf(` -Access control: -`) - listCommands([]string{"orgs", "auth", "move"}) - - fmt.Printf(` -More help: -`) - listCommands([]string{"docs", "doctor"}) - fmt.Printf(" help commands A complete list of commands (there are a bunch more)\n") - - return nil - } -} - -// the output of `flyctl help commands`; the master list of commands -func HelpCommands(root *cobra.Command) func(ctx context.Context) error { - return func(ctx context.Context) error { - all := flag.GetBool(ctx, "all") - - fmt.Printf("flyctl commands:\n") - for _, cmd := range root.Commands() { - if cmd.Hidden { - continue - } - - name := cmd.Name() - if deprecatedCommands[name] && !all { - continue - } - - fmt.Printf(" %s %s\n", tablewriter.PadRight(name, " ", 15), cmd.Short) - } - - fmt.Printf(` -Flags: - -a, --all List all flyctl commands, even the ones we secretly hate. -`) - - return nil - } -} diff --git a/internal/command/root/root.go b/internal/command/root/root.go index 830b1e9ba1..9a8381d0f6 100644 --- a/internal/command/root/root.go +++ b/internal/command/root/root.go @@ -2,8 +2,12 @@ package root import ( + "context" + + "github.com/olekukonko/tablewriter" "github.com/spf13/cobra" + "github.com/superfly/flyctl/client" "github.com/superfly/flyctl/flyctl" "github.com/superfly/flyctl/internal/command" "github.com/superfly/flyctl/internal/command/agent" @@ -26,7 +30,6 @@ import ( "github.com/superfly/flyctl/internal/command/doctor" "github.com/superfly/flyctl/internal/command/domains" "github.com/superfly/flyctl/internal/command/extensions" - "github.com/superfly/flyctl/internal/command/help" "github.com/superfly/flyctl/internal/command/history" "github.com/superfly/flyctl/internal/command/image" "github.com/superfly/flyctl/internal/command/info" @@ -48,7 +51,6 @@ import ( "github.com/superfly/flyctl/internal/command/redis" "github.com/superfly/flyctl/internal/command/regions" "github.com/superfly/flyctl/internal/command/releases" - "github.com/superfly/flyctl/internal/command/restart" "github.com/superfly/flyctl/internal/command/resume" "github.com/superfly/flyctl/internal/command/scale" "github.com/superfly/flyctl/internal/command/secrets" @@ -69,23 +71,11 @@ import ( // New initializes and returns a reference to a new root command. func New() *cobra.Command { const ( - long = `flyctl is a command line interface to the Fly.io platform. - -It allows users to manage authentication, application launch, -deployment, network configuration, logging and more with just the -one command. - -* Launch an app with the launch command -* Deploy an app with the deploy command -* View a deployed web application with the open command -* Check the status of an application with the status command - -To read more, use the docs command to view Fly's help on the web. - ` - short = "The Fly CLI" + long = `This is flyctl, the Fly.io command line interface.` + short = "The Fly.io command line interface" ) - root := command.New("flyctl", short, long, nil) + root := command.New("flyctl", short, long, run) root.PersistentPreRun = func(cmd *cobra.Command, args []string) { cmd.SilenceUsage = true cmd.SilenceErrors = true @@ -98,76 +88,151 @@ To read more, use the docs command to view Fly's help on the web. flyctl.InitConfig() - // what follows is a hack in order to achieve compatibility with what exists - // already. the commented out code above, is what should remain after the - // migration is complete. - - // newCommands is the set of commands which work with the new way root.AddCommand( + group(apps.New(), "deploy"), + group(machine.New(), "deploy"), version.New(), - apps.New(), - create.New(), // TODO: deprecate - destroy.New(), // TODO: deprecate - move.New(), // TODO: deprecate - suspend.New(), // TODO: deprecate - resume.New(), // TODO: deprecate - restart.New(), // TODO: deprecate - orgs.New(), - auth.New(), - open.New(), // TODO: deprecate - curl.New(), - platform.New(), - docs.New(), - releases.New(), - deploy.New(), - history.New(), - status.New(), - logs.New(), - doctor.New(), - dig.New(), - volumes.New(), + group(orgs.New(), "acl"), + group(auth.New(), "acl"), + group(platform.New(), "more_help"), + group(docs.New(), "more_help"), + group(releases.New(), "upkeep"), + group(deploy.New(), "deploy"), + group(history.New(), "upkeep"), + group(status.New(), "deploy"), + group(logs.New(), "upkeep"), + group(doctor.New(), "more_help"), + group(dig.New(), "upkeep"), + group(volumes.New(), "configuring"), agent.New(), - image.New(), - ping.New(), - proxy.New(), - machine.New(), - monitor.New(), - postgres.New(), - ips.New(), - secrets.New(), - ssh.New(), - ssh.NewSFTP(), - redis.New(), - vm.New(), - checks.New(), - launch.New(), - info.New(), + group(image.New(), "configuring"), + group(ping.New(), "upkeep"), + group(proxy.New(), "upkeep"), + group(monitor.New(), "apps_v1"), + group(postgres.New(), "dbs_and_extensions"), + group(ips.New(), "configuring"), + group(secrets.New(), "configuring"), + group(ssh.New(), "upkeep"), + group(ssh.NewSFTP(), "upkeep"), + group(redis.New(), "dbs_and_extensions"), + group(vm.New(), "apps_v1"), + group(checks.New(), "upkeep"), + group(launch.New(), "deploy"), + group(info.New(), "upkeep"), jobs.New(), turboku.New(), - services.New(), - config.New(), - scale.New(), - migrate_to_v2.New(), - tokens.New(), - extensions.New(), - consul.New(), - regions.New(), - dnsrecords.New(), - certificates.New(), - dashboard.New(), - wireguard.New(), - autoscale.New(), - domains.New(), - console.New(), + group(services.New(), "upkeep"), + group(config.New(), "configuring"), + group(scale.New(), "configuring"), + group(migrate_to_v2.New(), "apps_v1"), + group(tokens.New(), "acl"), + group(extensions.New(), "dbs_and_extensions"), + group(consul.New(), "dbs_and_extensions"), + group(regions.New(), "apps_v1"), + group(certificates.New(), "configuring"), + group(dashboard.New(), "upkeep"), + group(wireguard.New(), "upkeep"), + group(autoscale.New(), "apps_v1"), + group(console.New(), "upkeep"), settings.New(), - mysql.New(), + group(mysql.New(), "dbs_and_extensions"), + curl.New(), // TODO: deprecate + domains.New(), // TODO: deprecate + open.New(), // TODO: deprecate + create.New(), // TODO: deprecate + destroy.New(), // TODO: deprecate + move.New(), // TODO: deprecate + suspend.New(), // TODO: deprecate + resume.New(), // TODO: deprecate + dnsrecords.New(), // TODO: deprecate ) // if os.Getenv("DEV") != "" { // newCommands = append(newCommands, services.New()) // } - root.SetHelpCommand(help.New(root)) - root.RunE = help.NewRootHelp().RunE + // root.SetHelpCommand(help.New(root)) + // root.RunE = help.NewRootHelp().RunE + + root.AddGroup(&cobra.Group{ + ID: "deploy", + Title: "Deploying apps & machines", + }) + root.AddGroup(&cobra.Group{ + ID: "configuring", + Title: "Configuration & scaling", + }) + root.AddGroup(&cobra.Group{ + ID: "upkeep", + Title: "Monitoring & managing things", + }) + root.AddGroup(&cobra.Group{ + ID: "dbs_and_extensions", + Title: "Databases & extensions", + }) + root.AddGroup(&cobra.Group{ + ID: "acl", + Title: "Access control", + }) + root.AddGroup(&cobra.Group{ + ID: "more_help", + Title: "Help & troubleshooting", + }) + root.AddGroup(&cobra.Group{ + ID: "apps_v1", + Title: "Apps v1 (deprecated)", + }) + return root } + +func run(ctx context.Context) error { + cmd := command.FromContext(ctx) + + cmd.Println(cmd.Long) + cmd.Println() + cmd.Println("Usage:") + cmd.Printf(" %s\n", cmd.UseLine()) + cmd.Println() + + if !client.FromContext(ctx).Authenticated() { + cmd.Println(`It doesn't look like you're logged in. Try "flyctl auth signup" to create an account, +or "flyctl auth login" to log in to an existing account.`) + } + + cmd.Println("Here's a few commands to get you started:") + + importantCommands := [][]string{ + {"launch"}, + {"status"}, + {"deploy"}, + {"logs"}, + {"apps"}, + {"machines"}, + } + + for _, path := range importantCommands { + c, _, err := cmd.Traverse(path) + if err != nil { + panic(err) + } + cmd.Printf(" %s %s\n", tablewriter.PadRight(c.CommandPath(), " ", 16), c.Short) + } + + cmd.Println() + + cmd.Println("If you need help along the way:") + cmd.Println(" Use `fly docs` to open the Fly.io documentation, or visit https://fly.io/docs.") + cmd.Println(" Use `fly --help` for more information about a command.") + cmd.Println(" Visit https://community.fly.io for help from the Fly.io community.") + + cmd.Println() + cmd.Println("For a full list of commands, run `fly help`.") + + return nil +} + +func group(cmd *cobra.Command, id string) *cobra.Command { + cmd.GroupID = id + return cmd +}