Migrate to the new Cobra command grouping feature
This commit is contained in:
parent
8c0feacb71
commit
b12ea845ef
13 changed files with 103 additions and 130 deletions
|
|
@ -10,6 +10,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/cli/cli/v2/pkg/cmd/root"
|
||||
"github.com/cpuguy83/go-md2man/v2/md2man"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
|
|
@ -175,11 +176,8 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte {
|
|||
buf := new(bytes.Buffer)
|
||||
|
||||
manPreamble(buf, header, cmd, dashCommandName)
|
||||
for _, g := range subcommandGroups(cmd) {
|
||||
if len(g.Commands) == 0 {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(buf, "# %s\n", strings.ToUpper(g.Name))
|
||||
for _, g := range root.GroupedCommands(cmd) {
|
||||
fmt.Fprintf(buf, "# %s\n", strings.ToUpper(g.Title))
|
||||
for _, subcmd := range g.Commands {
|
||||
fmt.Fprintf(buf, "`%s`\n: %s\n\n", manLink(subcmd), subcmd.Short)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/cli/cli/v2/pkg/cmd/root"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
|
@ -99,11 +100,8 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string)
|
|||
fmt.Fprintf(w, "%s\n\n", cmd.Long)
|
||||
}
|
||||
|
||||
for _, g := range subcommandGroups(cmd) {
|
||||
if len(g.Commands) == 0 {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(w, "### %s\n\n", g.Name)
|
||||
for _, g := range root.GroupedCommands(cmd) {
|
||||
fmt.Fprintf(w, "### %s\n\n", g.Title)
|
||||
for _, subcmd := range g.Commands {
|
||||
fmt.Fprintf(w, "* [%s](%s)\n", subcmd.CommandPath(), linkHandler(cmdManualPath(subcmd)))
|
||||
}
|
||||
|
|
@ -130,56 +128,6 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string)
|
|||
return nil
|
||||
}
|
||||
|
||||
type commandGroup struct {
|
||||
Name string
|
||||
Commands []*cobra.Command
|
||||
}
|
||||
|
||||
// subcommandGroups lists child commands of a Cobra command split into groups.
|
||||
// TODO: have rootHelpFunc use this instead of repeating the same logic.
|
||||
func subcommandGroups(c *cobra.Command) []commandGroup {
|
||||
var rest []*cobra.Command
|
||||
var core []*cobra.Command
|
||||
var actions []*cobra.Command
|
||||
|
||||
for _, subcmd := range c.Commands() {
|
||||
if !subcmd.IsAvailableCommand() {
|
||||
continue
|
||||
}
|
||||
if _, ok := subcmd.Annotations["IsCore"]; ok {
|
||||
core = append(core, subcmd)
|
||||
} else if _, ok := subcmd.Annotations["IsActions"]; ok {
|
||||
actions = append(actions, subcmd)
|
||||
} else {
|
||||
rest = append(rest, subcmd)
|
||||
}
|
||||
}
|
||||
|
||||
if len(core) > 0 {
|
||||
return []commandGroup{
|
||||
{
|
||||
Name: "Core commands",
|
||||
Commands: core,
|
||||
},
|
||||
{
|
||||
Name: "Actions commands",
|
||||
Commands: actions,
|
||||
},
|
||||
{
|
||||
Name: "Additional commands",
|
||||
Commands: rest,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return []commandGroup{
|
||||
{
|
||||
Name: "Commands",
|
||||
Commands: rest,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GenMarkdownTree will generate a markdown page for this command and all
|
||||
// descendants in the directory given. The header may be nil.
|
||||
// This function may not work correctly if your command names have `-` in them.
|
||||
|
|
|
|||
|
|
@ -14,11 +14,9 @@ import (
|
|||
|
||||
func NewCmdAuth(f *cmdutil.Factory) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "auth <command>",
|
||||
Short: "Authenticate gh and git with GitHub",
|
||||
Annotations: map[string]string{
|
||||
"IsCore": "true",
|
||||
},
|
||||
Use: "auth <command>",
|
||||
Short: "Authenticate gh and git with GitHub",
|
||||
GroupID: "core",
|
||||
}
|
||||
|
||||
cmdutil.DisableAuthCheck(cmd)
|
||||
|
|
|
|||
|
|
@ -76,7 +76,6 @@ func NewCmdBrowse(f *cmdutil.Factory, runF func(*BrowseOptions) error) *cobra.Co
|
|||
#=> Open main.go in the main branch
|
||||
`),
|
||||
Annotations: map[string]string{
|
||||
"IsCore": "true",
|
||||
"help:arguments": heredoc.Doc(`
|
||||
A browser location can be specified using arguments in the following format:
|
||||
- by number for issue or pull request, e.g. "123"; or
|
||||
|
|
@ -86,6 +85,7 @@ func NewCmdBrowse(f *cmdutil.Factory, runF func(*BrowseOptions) error) *cobra.Co
|
|||
To configure a web browser other than the default, use the BROWSER environment variable.
|
||||
`),
|
||||
},
|
||||
GroupID: "core",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
opts.BaseRepo = f.BaseRepo
|
||||
|
||||
|
|
|
|||
|
|
@ -18,13 +18,13 @@ func NewCmdGist(f *cmdutil.Factory) *cobra.Command {
|
|||
Short: "Manage gists",
|
||||
Long: `Work with GitHub gists.`,
|
||||
Annotations: map[string]string{
|
||||
"IsCore": "true",
|
||||
"help:arguments": heredoc.Doc(`
|
||||
A gist can be supplied as argument in either of the following formats:
|
||||
- by ID, e.g. 5b0e0062eb8e9654adad7bb1d81cc75f
|
||||
- by URL, e.g. "https://gist.github.com/OWNER/5b0e0062eb8e9654adad7bb1d81cc75f"
|
||||
`),
|
||||
},
|
||||
GroupID: "core",
|
||||
}
|
||||
|
||||
cmd.AddCommand(gistCloneCmd.NewCmdClone(f, nil))
|
||||
|
|
|
|||
|
|
@ -30,13 +30,13 @@ func NewCmdIssue(f *cmdutil.Factory) *cobra.Command {
|
|||
$ gh issue view 123 --web
|
||||
`),
|
||||
Annotations: map[string]string{
|
||||
"IsCore": "true",
|
||||
"help:arguments": heredoc.Doc(`
|
||||
An issue can be supplied as argument in any of the following formats:
|
||||
- by number, e.g. "123"; or
|
||||
- by URL, e.g. "https://github.com/OWNER/REPO/issues/123".
|
||||
`),
|
||||
},
|
||||
GroupID: "core",
|
||||
}
|
||||
|
||||
cmdutil.EnableRepoOverride(cmd, f)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ func NewCmdPR(f *cmdutil.Factory) *cobra.Command {
|
|||
$ gh pr view --web
|
||||
`),
|
||||
Annotations: map[string]string{
|
||||
"IsCore": "true",
|
||||
"help:arguments": heredoc.Doc(`
|
||||
A pull request can be supplied as argument in any of the following formats:
|
||||
- by number, e.g. "123";
|
||||
|
|
@ -39,6 +38,7 @@ func NewCmdPR(f *cmdutil.Factory) *cobra.Command {
|
|||
- by the name of its head branch, e.g. "patch-1" or "OWNER:patch-1".
|
||||
`),
|
||||
},
|
||||
GroupID: "core",
|
||||
}
|
||||
|
||||
cmdutil.EnableRepoOverride(cmd, f)
|
||||
|
|
|
|||
|
|
@ -15,11 +15,9 @@ import (
|
|||
|
||||
func NewCmdRelease(f *cmdutil.Factory) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "release <command>",
|
||||
Short: "Manage releases",
|
||||
Annotations: map[string]string{
|
||||
"IsCore": "true",
|
||||
},
|
||||
Use: "release <command>",
|
||||
Short: "Manage releases",
|
||||
GroupID: "core",
|
||||
}
|
||||
|
||||
cmdutil.EnableRepoOverride(cmd, f)
|
||||
|
|
|
|||
|
|
@ -30,13 +30,13 @@ func NewCmdRepo(f *cmdutil.Factory) *cobra.Command {
|
|||
$ gh repo view --web
|
||||
`),
|
||||
Annotations: map[string]string{
|
||||
"IsCore": "true",
|
||||
"help:arguments": heredoc.Doc(`
|
||||
A repository can be supplied as an argument in any of the following formats:
|
||||
- "OWNER/REPO"
|
||||
- by URL, e.g. "https://github.com/OWNER/REPO"
|
||||
`),
|
||||
},
|
||||
GroupID: "core",
|
||||
}
|
||||
|
||||
cmd.AddCommand(repoViewCmd.NewCmdView(f, nil))
|
||||
|
|
|
|||
|
|
@ -102,32 +102,6 @@ func rootHelpFunc(f *cmdutil.Factory, command *cobra.Command, args []string) {
|
|||
}
|
||||
|
||||
namePadding := 12
|
||||
coreCommands := []string{}
|
||||
actionsCommands := []string{}
|
||||
additionalCommands := []string{}
|
||||
for _, c := range command.Commands() {
|
||||
if c.Short == "" {
|
||||
continue
|
||||
}
|
||||
if c.Hidden {
|
||||
continue
|
||||
}
|
||||
|
||||
s := rpad(c.Name()+":", namePadding) + c.Short
|
||||
if _, ok := c.Annotations["IsCore"]; ok {
|
||||
coreCommands = append(coreCommands, s)
|
||||
} else if _, ok := c.Annotations["IsActions"]; ok {
|
||||
actionsCommands = append(actionsCommands, s)
|
||||
} else {
|
||||
additionalCommands = append(additionalCommands, s)
|
||||
}
|
||||
}
|
||||
|
||||
// If there are no core commands, assume everything is a core command
|
||||
if len(coreCommands) == 0 {
|
||||
coreCommands = additionalCommands
|
||||
additionalCommands = []string{}
|
||||
}
|
||||
|
||||
type helpEntry struct {
|
||||
Title string
|
||||
|
|
@ -148,14 +122,16 @@ func rootHelpFunc(f *cmdutil.Factory, command *cobra.Command, args []string) {
|
|||
helpEntries = append(helpEntries, helpEntry{"", longText})
|
||||
}
|
||||
helpEntries = append(helpEntries, helpEntry{"USAGE", command.UseLine()})
|
||||
if len(coreCommands) > 0 {
|
||||
helpEntries = append(helpEntries, helpEntry{"CORE COMMANDS", strings.Join(coreCommands, "\n")})
|
||||
}
|
||||
if len(actionsCommands) > 0 {
|
||||
helpEntries = append(helpEntries, helpEntry{"ACTIONS COMMANDS", strings.Join(actionsCommands, "\n")})
|
||||
}
|
||||
if len(additionalCommands) > 0 {
|
||||
helpEntries = append(helpEntries, helpEntry{"ADDITIONAL COMMANDS", strings.Join(additionalCommands, "\n")})
|
||||
|
||||
for _, g := range GroupedCommands(command) {
|
||||
var names []string
|
||||
for _, c := range g.Commands {
|
||||
names = append(names, rpad(c.Name()+":", namePadding)+c.Short)
|
||||
}
|
||||
helpEntries = append(helpEntries, helpEntry{
|
||||
Title: strings.ToUpper(g.Title),
|
||||
Body: strings.Join(names, "\n"),
|
||||
})
|
||||
}
|
||||
|
||||
if isRootCmd(command) {
|
||||
|
|
@ -225,6 +201,49 @@ func findCommand(cmd *cobra.Command, name string) *cobra.Command {
|
|||
return nil
|
||||
}
|
||||
|
||||
type CommandGroup struct {
|
||||
Title string
|
||||
Commands []*cobra.Command
|
||||
}
|
||||
|
||||
func GroupedCommands(cmd *cobra.Command) []CommandGroup {
|
||||
var res []CommandGroup
|
||||
|
||||
for _, g := range cmd.Groups() {
|
||||
var cmds []*cobra.Command
|
||||
for _, c := range cmd.Commands() {
|
||||
if c.GroupID == g.ID && c.IsAvailableCommand() {
|
||||
cmds = append(cmds, c)
|
||||
}
|
||||
}
|
||||
if len(cmds) > 0 {
|
||||
res = append(res, CommandGroup{
|
||||
Title: g.Title,
|
||||
Commands: cmds,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var cmds []*cobra.Command
|
||||
for _, c := range cmd.Commands() {
|
||||
if c.GroupID == "" && c.IsAvailableCommand() {
|
||||
cmds = append(cmds, c)
|
||||
}
|
||||
}
|
||||
if len(cmds) > 0 {
|
||||
defaultGroupTitle := "Additional commands"
|
||||
if len(cmd.Groups()) == 0 {
|
||||
defaultGroupTitle = "Available commands"
|
||||
}
|
||||
res = append(res, CommandGroup{
|
||||
Title: defaultGroupTitle,
|
||||
Commands: cmds,
|
||||
})
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
// rpad adds padding to the right of a string.
|
||||
func rpad(s string, padding int) string {
|
||||
template := fmt.Sprintf("%%-%ds ", padding)
|
||||
|
|
|
|||
|
|
@ -43,8 +43,6 @@ func NewCmdRoot(f *cmdutil.Factory, version, buildDate string) *cobra.Command {
|
|||
Short: "GitHub CLI",
|
||||
Long: `Work seamlessly with GitHub from the command line.`,
|
||||
|
||||
SilenceErrors: true,
|
||||
SilenceUsage: true,
|
||||
Example: heredoc.Doc(`
|
||||
$ gh issue create
|
||||
$ gh repo clone cli/cli
|
||||
|
|
@ -61,15 +59,33 @@ func NewCmdRoot(f *cmdutil.Factory, version, buildDate string) *cobra.Command {
|
|||
// cmd.SetOut(f.IOStreams.Out) // can't use due to https://github.com/spf13/cobra/issues/1708
|
||||
// cmd.SetErr(f.IOStreams.ErrOut) // just let it default to os.Stderr instead
|
||||
|
||||
cmd.Flags().Bool("version", false, "Show gh version")
|
||||
cmd.PersistentFlags().Bool("help", false, "Show help for command")
|
||||
cmd.SetHelpFunc(func(c *cobra.Command, args []string) {
|
||||
rootHelpFunc(f, c, args)
|
||||
|
||||
// override Cobra's default behaviors unless an opt-out has been set
|
||||
if os.Getenv("GH_COBRA") == "" {
|
||||
cmd.SilenceErrors = true
|
||||
cmd.SilenceUsage = true
|
||||
|
||||
// this --version flag is checked in rootHelpFunc
|
||||
cmd.Flags().Bool("version", false, "Show gh version")
|
||||
|
||||
cmd.SetHelpFunc(func(c *cobra.Command, args []string) {
|
||||
rootHelpFunc(f, c, args)
|
||||
})
|
||||
cmd.SetUsageFunc(func(c *cobra.Command) error {
|
||||
return rootUsageFunc(f.IOStreams.ErrOut, c)
|
||||
})
|
||||
cmd.SetFlagErrorFunc(rootFlagErrorFunc)
|
||||
}
|
||||
|
||||
cmd.AddGroup(&cobra.Group{
|
||||
ID: "core",
|
||||
Title: "Core commands",
|
||||
})
|
||||
cmd.SetUsageFunc(func(c *cobra.Command) error {
|
||||
return rootUsageFunc(f.IOStreams.ErrOut, c)
|
||||
cmd.AddGroup(&cobra.Group{
|
||||
ID: "actions",
|
||||
Title: "GitHub Actions commands",
|
||||
})
|
||||
cmd.SetFlagErrorFunc(rootFlagErrorFunc)
|
||||
|
||||
// Child commands
|
||||
cmd.AddCommand(versionCmd.NewCmdVersion(f, version, buildDate))
|
||||
|
|
@ -158,7 +174,7 @@ func newCodespaceCmd(f *cmdutil.Factory) *cobra.Command {
|
|||
cmd := codespaceCmd.NewRootCmd(app)
|
||||
cmd.Use = "codespace"
|
||||
cmd.Aliases = []string{"cs"}
|
||||
cmd.Annotations = map[string]string{"IsCore": "true"}
|
||||
cmd.GroupID = "core"
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,12 +13,10 @@ import (
|
|||
|
||||
func NewCmdRun(f *cmdutil.Factory) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "run <command>",
|
||||
Short: "View details about workflow runs",
|
||||
Long: "List, view, and watch recent workflow runs from GitHub Actions.",
|
||||
Annotations: map[string]string{
|
||||
"IsActions": "true",
|
||||
},
|
||||
Use: "run <command>",
|
||||
Short: "View details about workflow runs",
|
||||
Long: "List, view, and watch recent workflow runs from GitHub Actions.",
|
||||
GroupID: "actions",
|
||||
}
|
||||
cmdutil.EnableRepoOverride(cmd, f)
|
||||
|
||||
|
|
|
|||
|
|
@ -12,12 +12,10 @@ import (
|
|||
|
||||
func NewCmdWorkflow(f *cmdutil.Factory) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "workflow <command>",
|
||||
Short: "View details about GitHub Actions workflows",
|
||||
Long: "List, view, and run workflows in GitHub Actions.",
|
||||
Annotations: map[string]string{
|
||||
"IsActions": "true",
|
||||
},
|
||||
Use: "workflow <command>",
|
||||
Short: "View details about GitHub Actions workflows",
|
||||
Long: "List, view, and run workflows in GitHub Actions.",
|
||||
GroupID: "actions",
|
||||
}
|
||||
cmdutil.EnableRepoOverride(cmd, f)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue