From 278ff59fce6abbf6088a4393bf2c2658951f6439 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mislav=20Marohni=C4=87?= Date: Wed, 9 Nov 2022 17:30:32 +0100 Subject: [PATCH] Allow accessing Cobra built-in doc generation features Setting GH_COBRA allows access to Cobra's built-in implementation of generating man pages and markdown trees. This is useful for testing and comparing our overrides against Cobra's own logic. --- internal/docs/man.go | 21 ++++++++++++++------- internal/docs/man_test.go | 8 ++++---- internal/docs/markdown.go | 28 ++++++++-------------------- internal/docs/markdown_test.go | 18 +++++++++++++----- 4 files changed, 39 insertions(+), 36 deletions(-) diff --git a/internal/docs/man.go b/internal/docs/man.go index 633e149a1..4864140f1 100644 --- a/internal/docs/man.go +++ b/internal/docs/man.go @@ -13,6 +13,7 @@ import ( "github.com/cli/cli/v2/pkg/cmd/root" "github.com/cpuguy83/go-md2man/v2/md2man" "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" "github.com/spf13/pflag" ) @@ -22,20 +23,26 @@ import ( // subcmds, `sub` and `sub-third`, and `sub` has a subcommand called `third` // it is undefined which help output will be in the file `cmd-sub-third.1`. func GenManTree(cmd *cobra.Command, dir string) error { - return GenManTreeFromOpts(cmd, GenManTreeOptions{ + if os.Getenv("GH_COBRA") != "" { + return doc.GenManTreeFromOpts(cmd, doc.GenManTreeOptions{ + Path: dir, + CommandSeparator: "-", + }) + } + return genManTreeFromOpts(cmd, GenManTreeOptions{ Path: dir, CommandSeparator: "-", }) } -// GenManTreeFromOpts generates a man page for the command and all descendants. +// genManTreeFromOpts generates a man page for the command and all descendants. // The pages are written to the opts.Path directory. -func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { +func genManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { for _, c := range cmd.Commands() { if !c.IsAvailableCommand() || c.IsAdditionalHelpTopicCommand() { continue } - if err := GenManTreeFromOpts(c, opts); err != nil { + if err := genManTreeFromOpts(c, opts); err != nil { return err } } @@ -58,7 +65,7 @@ func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { versionString = "GitHub CLI " + v } - return GenMan(cmd, &GenManHeader{ + return renderMan(cmd, &GenManHeader{ Section: section, Source: versionString, Manual: "GitHub CLI manual", @@ -83,9 +90,9 @@ type GenManHeader struct { Manual string } -// GenMan will generate a man page for the given command and write it to +// renderMan will generate a man page for the given command and write it to // w. The header argument may be nil, however obviously w may not. -func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error { +func renderMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error { if err := fillHeader(header, cmd.CommandPath()); err != nil { return err } diff --git a/internal/docs/man_test.go b/internal/docs/man_test.go index 0be6984ad..84fc8cc57 100644 --- a/internal/docs/man_test.go +++ b/internal/docs/man_test.go @@ -24,7 +24,7 @@ func TestGenManDoc(t *testing.T) { // We generate on a subcommand so we have both subcommands and parents buf := new(bytes.Buffer) - if err := GenMan(echoCmd, header, buf); err != nil { + if err := renderMan(echoCmd, header, buf); err != nil { t.Fatal(err) } output := buf.String() @@ -58,7 +58,7 @@ func TestGenManNoHiddenParents(t *testing.T) { defer func() { f.Hidden = false }() } buf := new(bytes.Buffer) - if err := GenMan(echoCmd, header, buf); err != nil { + if err := renderMan(echoCmd, header, buf); err != nil { t.Fatal(err) } output := buf.String() @@ -89,7 +89,7 @@ func TestGenManSeeAlso(t *testing.T) { buf := new(bytes.Buffer) header := &GenManHeader{} - if err := GenMan(rootCmd, header, buf); err != nil { + if err := renderMan(rootCmd, header, buf); err != nil { t.Fatal(err) } scanner := bufio.NewScanner(buf) @@ -154,7 +154,7 @@ func BenchmarkGenManToFile(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - if err := GenMan(rootCmd, nil, file); err != nil { + if err := renderMan(rootCmd, nil, file); err != nil { b.Fatal(err) } } diff --git a/internal/docs/markdown.go b/internal/docs/markdown.go index 4312459c5..41fe3a1fd 100644 --- a/internal/docs/markdown.go +++ b/internal/docs/markdown.go @@ -10,6 +10,7 @@ import ( "github.com/cli/cli/v2/pkg/cmd/root" "github.com/spf13/cobra" + "github.com/spf13/cobra/doc" "github.com/spf13/pflag" ) @@ -79,13 +80,8 @@ func printFlagsHTML(w io.Writer, fs *pflag.FlagSet) error { return tpl.Execute(w, flags) } -// GenMarkdown creates markdown output. -func GenMarkdown(cmd *cobra.Command, w io.Writer) error { - return GenMarkdownCustom(cmd, w, func(s string) string { return s }) -} - -// GenMarkdownCustom creates custom markdown output. -func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error { +// genMarkdownCustom creates custom markdown output. +func genMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) string) error { fmt.Fprint(w, "{% raw %}") fmt.Fprintf(w, "## %s\n\n", cmd.CommandPath()) @@ -128,21 +124,13 @@ func GenMarkdownCustom(cmd *cobra.Command, w io.Writer, linkHandler func(string) return nil } -// 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. -// If you have `cmd` with two subcmds, `sub` and `sub-third`, -// and `sub` has a subcommand called `third`, it is undefined which -// help output will be in the file `cmd-sub-third.1`. -func GenMarkdownTree(cmd *cobra.Command, dir string) error { - identity := func(s string) string { return s } - emptyStr := func(s string) string { return "" } - return GenMarkdownTreeCustom(cmd, dir, emptyStr, identity) -} - // GenMarkdownTreeCustom is the same as GenMarkdownTree, but // with custom filePrepender and linkHandler. func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHandler func(string) string) error { + if os.Getenv("GH_COBRA") != "" { + return doc.GenMarkdownTreeCustom(cmd, dir, filePrepender, linkHandler) + } + for _, c := range cmd.Commands() { _, forceGeneration := c.Annotations["markdown:generate"] if c.Hidden && !forceGeneration { @@ -164,7 +152,7 @@ func GenMarkdownTreeCustom(cmd *cobra.Command, dir string, filePrepender, linkHa if _, err := io.WriteString(f, filePrepender(filename)); err != nil { return err } - if err := GenMarkdownCustom(cmd, f, linkHandler); err != nil { + if err := genMarkdownCustom(cmd, f, linkHandler); err != nil { return err } return nil diff --git a/internal/docs/markdown_test.go b/internal/docs/markdown_test.go index 43bdbd7df..997029205 100644 --- a/internal/docs/markdown_test.go +++ b/internal/docs/markdown_test.go @@ -10,9 +10,11 @@ import ( ) func TestGenMdDoc(t *testing.T) { + linkHandler := func(s string) string { return s } + // We generate on subcommand so we have both subcommands and parents. buf := new(bytes.Buffer) - if err := GenMarkdown(echoCmd, buf); err != nil { + if err := genMarkdownCustom(echoCmd, buf, linkHandler); err != nil { t.Fatal(err) } output := buf.String() @@ -28,9 +30,11 @@ func TestGenMdDoc(t *testing.T) { } func TestGenMdDocWithNoLongOrSynopsis(t *testing.T) { + linkHandler := func(s string) string { return s } + // We generate on subcommand so we have both subcommands and parents. buf := new(bytes.Buffer) - if err := GenMarkdown(dummyCmd, buf); err != nil { + if err := genMarkdownCustom(dummyCmd, buf, linkHandler); err != nil { t.Fatal(err) } output := buf.String() @@ -42,6 +46,8 @@ func TestGenMdDocWithNoLongOrSynopsis(t *testing.T) { } func TestGenMdNoHiddenParents(t *testing.T) { + linkHandler := func(s string) string { return s } + // We generate on subcommand so we have both subcommands and parents. for _, name := range []string{"rootflag", "strtwo"} { f := rootCmd.PersistentFlags().Lookup(name) @@ -49,7 +55,7 @@ func TestGenMdNoHiddenParents(t *testing.T) { defer func() { f.Hidden = false }() } buf := new(bytes.Buffer) - if err := GenMarkdown(echoCmd, buf); err != nil { + if err := genMarkdownCustom(echoCmd, buf, linkHandler); err != nil { t.Fatal(err) } output := buf.String() @@ -72,7 +78,7 @@ func TestGenMdTree(t *testing.T) { } defer os.RemoveAll(tmpdir) - if err := GenMarkdownTree(c, tmpdir); err != nil { + if err := GenMarkdownTreeCustom(c, tmpdir, func(s string) string { return s }, func(s string) string { return s }); err != nil { t.Fatalf("GenMarkdownTree failed: %v", err) } @@ -88,9 +94,11 @@ func BenchmarkGenMarkdownToFile(b *testing.B) { } defer file.Close() + linkHandler := func(s string) string { return s } + b.ResetTimer() for i := 0; i < b.N; i++ { - if err := GenMarkdown(rootCmd, file); err != nil { + if err := genMarkdownCustom(rootCmd, file, linkHandler); err != nil { b.Fatal(err) } }