diff --git a/doc/cmd_test.go b/doc/cmd_test.go index 0917d602..912218af 100644 --- a/doc/cmd_test.go +++ b/doc/cmd_test.go @@ -1,6 +1,7 @@ package doc import ( + "regexp" "strings" "testing" @@ -89,3 +90,9 @@ func checkStringOmits(t *testing.T, got, expected string) { t.Errorf("Expected to not contain: \n %v\nGot: %v", expected, got) } } + +func checkStringMatch(t *testing.T, got, pattern string) { + if ok, _ := regexp.MatchString(pattern, got); !ok { + t.Errorf("Expected to match: \n%v\nGot:\n %v\n", pattern, got) + } +} diff --git a/doc/man_docs.go b/doc/man_docs.go index 916e3614..60a43efe 100644 --- a/doc/man_docs.go +++ b/doc/man_docs.go @@ -155,6 +155,31 @@ func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command, cobra.WriteStringAndCheck(buf, description+"\n\n") } +func manPrintCommands(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command) { + // Find sub-commands that need to be documented + subCommands := []*cobra.Command{} + for _, c := range cmd.Commands() { + if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { + continue + } + subCommands = append(subCommands, c) + } + + // No need to go further if there is no sub-commands to document + if len(subCommands) <= 0 { + return + } + + // Add a 'COMMANDS' section in the generated documentation + cobra.WriteStringAndCheck(buf, "# COMMANDS\n") + // For each sub-commands, and an entry with the command name and it's Short description and reference to dedicated + // man page + for _, c := range subCommands { + dashedPath := strings.Replace(c.CommandPath(), " ", "-", -1) + cobra.WriteStringAndCheck(buf, fmt.Sprintf("**%s**\n %s \n See **%s(%s)**.\n\n", c.Name(), c.Short, dashedPath, header.Section)) + } +} + func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) { flags.VisitAll(func(flag *pflag.Flag) { if len(flag.Deprecated) > 0 || flag.Hidden { @@ -208,6 +233,7 @@ func genMan(cmd *cobra.Command, header *GenManHeader) []byte { buf := new(bytes.Buffer) manPreamble(buf, header, cmd, dashCommandName) + manPrintCommands(buf, header, cmd) manPrintOptions(buf, cmd) if len(cmd.Example) > 0 { buf.WriteString("# EXAMPLE\n") diff --git a/doc/man_docs_test.go b/doc/man_docs_test.go index f3fe3d61..60af060d 100644 --- a/doc/man_docs_test.go +++ b/doc/man_docs_test.go @@ -151,6 +151,45 @@ func TestManPrintFlagsHidesShortDeperecated(t *testing.T) { } } +func TestGenManCommands(t *testing.T) { + header := &GenManHeader{ + Title: "Project", + Section: "2", + } + + // Root command + buf := new(bytes.Buffer) + if err := GenMan(rootCmd, header, buf); err != nil { + t.Fatal(err) + } + output := buf.String() + + checkStringContains(t, output, ".SH COMMANDS") + checkStringMatch(t, output, "\\\\fBecho\\\\fP\n[ \t]+Echo anything to the screen\n[ \t]+See \\\\fBroot-echo\\(2\\)\\\\fP\\\\&\\.") + checkStringOmits(t, output, ".PP\n\\fBprint\\fP\n") + + // Echo command + buf = new(bytes.Buffer) + if err := GenMan(echoCmd, header, buf); err != nil { + t.Fatal(err) + } + output = buf.String() + + checkStringContains(t, output, ".SH COMMANDS") + checkStringMatch(t, output, "\\\\fBtimes\\\\fP\n[ \t]+Echo anything to the screen more times\n[ \t]+See \\\\fBroot-echo-times\\(2\\)\\\\fP\\\\&\\.") + checkStringMatch(t, output, "\\\\fBechosub\\\\fP\n[ \t]+second sub command for echo\n[ \t]+See \\\\fBroot-echo-echosub\\(2\\)\\\\fP\\\\&\\.") + checkStringOmits(t, output, ".PP\n\\fBdeprecated\\fP\n") + + // Time command as echo's subcommand + buf = new(bytes.Buffer) + if err := GenMan(timesCmd, header, buf); err != nil { + t.Fatal(err) + } + output = buf.String() + + checkStringOmits(t, output, ".SH COMMANDS") +} + func TestGenManTree(t *testing.T) { c := &cobra.Command{Use: "do [OPTIONS] arg1 arg2"} header := &GenManHeader{Section: "2"}