From ea92b272f623f90a62189d76ac9da9bd15f5779d Mon Sep 17 00:00:00 2001 From: "penify-dev[bot]" <146478655+penify-dev[bot]@users.noreply.github.com> Date: Sat, 26 Apr 2025 20:40:10 +0000 Subject: [PATCH] Generated Documentation --- doc/man_docs.go | 74 ++++++++++++++++-- fish_completions_test.go | 165 --------------------------------------- 2 files changed, 66 insertions(+), 173 deletions(-) diff --git a/doc/man_docs.go b/doc/man_docs.go index 2138f248..c5dc2523 100644 --- a/doc/man_docs.go +++ b/doc/man_docs.go @@ -30,11 +30,15 @@ import ( "github.com/spf13/pflag" ) -// GenManTree will generate a man 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`. +// GenManTree generates a man page for the provided command and all its descendants in the specified directory. +// +// It takes a cobra.Command pointer representing the root command, an optional GenManHeader pointer to customize the header information, and a string specifying the output directory. +// +// The function assumes that command names do not contain hyphens (`-`). If they do, unexpected behavior may occur. +// +// Note: If a command named `cmd` has subcommands `sub` and `sub-third`, and `sub` itself has a subcommand called `third`, it is undefined which help output will be written to the file `cmd-sub-third.1`. +// +// Returns an error if the generation process encounters any issues, such as invalid input or permission errors when writing files to the specified directory. func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { return GenManTreeFromOpts(cmd, GenManTreeOptions{ Header: header, @@ -44,7 +48,15 @@ func GenManTree(cmd *cobra.Command, header *GenManHeader, dir string) error { } // GenManTreeFromOpts generates a man page for the command and all descendants. -// The pages are written to the opts.Path directory. +// The pages are written to the opts.Path directory. It recursively processes each command in the tree, +// skipping non-available or additional help topic commands. Each man page is saved with a filename based on the command path and section. + +// Parameters: +// - cmd: A pointer to the root cobra.Command for which man pages need to be generated. +// - opts: A GenManTreeOptions struct containing options for generating the man pages, such as header details, output directory, and separators. + +// Returns: +// - error: If any error occurs during the generation of the man pages, it is returned. func GenManTreeFromOpts(cmd *cobra.Command, opts GenManTreeOptions) error { header := opts.Header if header == nil { @@ -100,8 +112,15 @@ type GenManHeader struct { Manual string } -// GenMan 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. +// GenMan generates a man page for the given command and writes it to the specified writer. +// +// Parameters: +// cmd - The cobra.Command for which to generate the man page. +// header - A pointer to a GenManHeader that contains additional information for the man page. If nil, a default header will be used. +// w - The io.Writer to which the generated man page will be written. +// +// Returns: +// error - If an error occurs during the generation of the man page, it will be returned here. func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error { if header == nil { header = &GenManHeader{} @@ -115,6 +134,15 @@ func GenMan(cmd *cobra.Command, header *GenManHeader, w io.Writer) error { return err } +// fillHeader populates the GenManHeader with default values if they are not already set. +// +// It sets the title to the uppercase version of `name`, replacing spaces with hyphens. +// If the section is empty, it defaults to "1". +// If the date is nil, it sets the date to the current time or a time specified by the SOURCE_DATE_EPOCH environment variable. +// The formatted date is stored in header.date. +// If source is empty and auto-generation is not disabled, it sets the source to "Auto generated by spf13/cobra". +// +// It returns an error if there is an issue parsing the SOURCE_DATE_EPOCH environment variable. func fillHeader(header *GenManHeader, name string, disableAutoGen bool) error { if header.Title == "" { header.Title = strings.ToUpper(strings.ReplaceAll(name, " ", "\\-")) @@ -140,6 +168,17 @@ func fillHeader(header *GenManHeader, name string, disableAutoGen bool) error { return nil } +// manPreamble writes the preamble for a manual page to the given buffer. +// +// Parameters: +// buf - the io.StringWriter to write the preamble to. +// header - a pointer to a GenManHeader containing metadata for the manual page. +// cmd - a pointer to a cobra.Command representing the command being documented. +// dashedName - the dash-separated name of the command. +// +// This function constructs the preamble section of a man page, including +// the title, section, date, source, and manual. It also includes the command's +// short description and synopsis. func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command, dashedName string) { description := cmd.Long if len(description) == 0 { @@ -156,6 +195,12 @@ func manPreamble(buf io.StringWriter, header *GenManHeader, cmd *cobra.Command, cobra.WriteStringAndCheck(buf, description+"\n\n") } +// manPrintFlags prints the flags in a format suitable for a man page. +// +// It takes an io.StringWriter to write to and a pflag.FlagSet containing the flags to print. +// For each flag, it checks if it is deprecated or hidden. If not, it formats the flag name, +// shorthand, and usage information according to its type (string or other) and whether it has +// a default value. The formatted string is then written to the provided writer. func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) { flags.VisitAll(func(flag *pflag.Flag) { if len(flag.Deprecated) > 0 || flag.Hidden { @@ -184,6 +229,8 @@ func manPrintFlags(buf io.StringWriter, flags *pflag.FlagSet) { }) } +// manPrintOptions writes the options for a command to a StringWriter. +// It includes both non-inherited and inherited flags, if available. func manPrintOptions(buf io.StringWriter, command *cobra.Command) { flags := command.NonInheritedFlags() if flags.HasAvailableFlags() { @@ -199,6 +246,17 @@ func manPrintOptions(buf io.StringWriter, command *cobra.Command) { } } +// genMan generates a man page for the given Cobra command and header. +// It initializes default help commands and flags, processes the command path, +// and constructs the man page content including preamble, options, examples, +// see also sections, and history. +// +// Parameters: +// - cmd: The Cobra command for which to generate the man page. +// - header: Header information for the man page, such as section and date. +// +// Returns: +// - A byte slice containing the generated man page content. func genMan(cmd *cobra.Command, header *GenManHeader) []byte { cmd.InitDefaultHelpCmd() cmd.InitDefaultHelpFlag() diff --git a/fish_completions_test.go b/fish_completions_test.go index 2a1da426..e69de29b 100644 --- a/fish_completions_test.go +++ b/fish_completions_test.go @@ -1,165 +0,0 @@ -// Copyright 2013-2023 The Cobra Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cobra - -import ( - "bytes" - "errors" - "fmt" - "os" - "path/filepath" - "testing" -) - -// TestCompleteNoDesCmdInFishScript tests the completion functionality for a command without descriptions in a Fish shell script. -// -// It sets up a root command and a child command, adds the child to the root, generates Fish completion script, -// and checks if the output contains the expected completion information without descriptions. -func TestCompleteNoDesCmdInFishScript(t *testing.T) { - rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} - child := &Command{ - Use: "child", - ValidArgsFunction: validArgsFunc, - Run: emptyRun, - } - rootCmd.AddCommand(child) - - buf := new(bytes.Buffer) - assertNoErr(t, rootCmd.GenFishCompletion(buf, false)) - output := buf.String() - - check(t, output, ShellCompNoDescRequestCmd) -} - -// TestCompleteCmdInFishScript tests the generation of fish completion script for a command. -func TestCompleteCmdInFishScript(t *testing.T) { - rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} - child := &Command{ - Use: "child", - ValidArgsFunction: validArgsFunc, - Run: emptyRun, - } - rootCmd.AddCommand(child) - - buf := new(bytes.Buffer) - assertNoErr(t, rootCmd.GenFishCompletion(buf, true)) - output := buf.String() - - check(t, output, ShellCompRequestCmd) - checkOmit(t, output, ShellCompNoDescRequestCmd) -} - -// TestProgWithDash tests the generation of fish completion for a command with a hyphen in its name. -// It verifies that the hyphen is replaced in function names but remains intact in the command name. -func TestProgWithDash(t *testing.T) { - rootCmd := &Command{Use: "root-dash", Args: NoArgs, Run: emptyRun} - buf := new(bytes.Buffer) - assertNoErr(t, rootCmd.GenFishCompletion(buf, false)) - output := buf.String() - - // Functions name should have replace the '-' - check(t, output, "__root_dash_perform_completion") - checkOmit(t, output, "__root-dash_perform_completion") - - // The command name should not have replaced the '-' - check(t, output, "-c root-dash") - checkOmit(t, output, "-c root_dash") -} - -// TestProgWithColon tests the generation of Fish completion for a command with a colon in its name. -func TestProgWithColon(t *testing.T) { - rootCmd := &Command{Use: "root:colon", Args: NoArgs, Run: emptyRun} - buf := new(bytes.Buffer) - assertNoErr(t, rootCmd.GenFishCompletion(buf, false)) - output := buf.String() - - // Functions name should have replace the ':' - check(t, output, "__root_colon_perform_completion") - checkOmit(t, output, "__root:colon_perform_completion") - - // The command name should not have replaced the ':' - check(t, output, "-c root:colon") - checkOmit(t, output, "-c root_colon") -} - -// TestFishCompletionNoActiveHelp tests the generation of Fish completion script without active help enabled. -// -// Parameters: -// - t: A testing.T instance for assertions and logging. -// -// The function creates a new Command, generates its Fish completion script with active help disabled, -// and asserts that the output does not include an active help variable set to 1. -func TestFishCompletionNoActiveHelp(t *testing.T) { - c := &Command{Use: "c", Run: emptyRun} - - buf := new(bytes.Buffer) - assertNoErr(t, c.GenFishCompletion(buf, true)) - output := buf.String() - - // check that active help is being disabled - activeHelpVar := activeHelpEnvVar(c.Name()) - check(t, output, fmt.Sprintf("%s=0", activeHelpVar)) -} - -// TestGenFishCompletionFile tests the generation of a Fish completion file for a Cobra command. -// It creates a temporary file, sets up a Cobra command hierarchy, and asserts that no errors occur during the completion file generation process. -func TestGenFishCompletionFile(t *testing.T) { - tmpFile, err := os.CreateTemp("", "cobra-test") - if err != nil { - t.Fatal(err.Error()) - } - - defer os.Remove(tmpFile.Name()) - - rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} - child := &Command{ - Use: "child", - ValidArgsFunction: validArgsFunc, - Run: emptyRun, - } - rootCmd.AddCommand(child) - - assertNoErr(t, rootCmd.GenFishCompletionFile(tmpFile.Name(), false)) -} - -// TestFailGenFishCompletionFile tests the GenFishCompletionFile method for permission errors. -// -// It creates a temporary directory and file, sets up a command structure, -// and attempts to generate Fish completion file. It checks if the error returned -// matches os.ErrPermission as expected. If not, it fails the test with an error message. -func TestFailGenFishCompletionFile(t *testing.T) { - tmpDir, err := os.MkdirTemp("", "cobra-test") - if err != nil { - t.Fatal(err.Error()) - } - - defer os.RemoveAll(tmpDir) - - f, _ := os.OpenFile(filepath.Join(tmpDir, "test"), os.O_CREATE, 0400) - defer f.Close() - - rootCmd := &Command{Use: "root", Args: NoArgs, Run: emptyRun} - child := &Command{ - Use: "child", - ValidArgsFunction: validArgsFunc, - Run: emptyRun, - } - rootCmd.AddCommand(child) - - got := rootCmd.GenFishCompletionFile(f.Name(), false) - if !errors.Is(got, os.ErrPermission) { - t.Errorf("got: %s, want: %s", got.Error(), os.ErrPermission.Error()) - } -}