Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add default values to web manual and man pages #8395

Merged
merged 12 commits into from Feb 6, 2024
9 changes: 7 additions & 2 deletions internal/docs/man.go
Expand Up @@ -149,10 +149,15 @@ func manPrintFlags(buf *bytes.Buffer, flags *pflag.FlagSet) {
} else {
buf.WriteString(fmt.Sprintf("`--%s`", flag.Name))
}
if varname == "" {

defval := getDefaultValueDisplayString(flag)

if varname == "" && defval != "" {
buf.WriteString(fmt.Sprintf(" `%s`\n", strings.TrimSpace(defval)))
} else if varname == "" {
buf.WriteString("\n")
} else {
buf.WriteString(fmt.Sprintf(" `<%s>`\n", varname))
buf.WriteString(fmt.Sprintf(" `<%s>%s`\n", varname, defval))
}
buf.WriteString(fmt.Sprintf(": %s\n\n", usage))
})
Expand Down
103 changes: 102 additions & 1 deletion internal/docs/man_test.go
Expand Up @@ -107,7 +107,7 @@ func TestManPrintFlagsHidesShortDeprecated(t *testing.T) {
manPrintFlags(buf, c.Flags())

got := buf.String()
expected := "`--foo` `<string>`\n: Foo flag\n\n"
expected := "`--foo` `<string> (default \"default\")`\n: Foo flag\n\n"
if got != expected {
t.Errorf("Expected %q, got %q", expected, got)
}
Expand All @@ -130,6 +130,107 @@ func TestGenManTree(t *testing.T) {
}
}

func TestManPrintFlagsShowsDefaultValues(t *testing.T) {
type TestOptions struct {
Limit int
Template string
Fork bool
NoArchive bool
Topic []string
}
opts := TestOptions{}
// Int flag should show it
c := &cobra.Command{}
c.Flags().IntVar(&opts.Limit, "limit", 30, "Some limit")

buf := new(bytes.Buffer)
manPrintFlags(buf, c.Flags())

got := buf.String()
expected := "`--limit` `<int> (default 30)`\n: Some limit\n\n"
if got != expected {
t.Errorf("Expected %q, got %q", expected, got)
}

// Bool flag should hide it if default is false
c = &cobra.Command{}
c.Flags().BoolVar(&opts.Fork, "fork", false, "Show only forks")

buf = new(bytes.Buffer)
manPrintFlags(buf, c.Flags())

got = buf.String()
expected = "`--fork`\n: Show only forks\n\n"
if got != expected {
t.Errorf("Expected %q, got %q", expected, got)
}

// Bool flag should show it if default is true
c = &cobra.Command{}
c.Flags().BoolVar(&opts.NoArchive, "no-archived", true, "Hide archived")

buf = new(bytes.Buffer)
manPrintFlags(buf, c.Flags())

got = buf.String()
expected = "`--no-archived` `(default true)`\n: Hide archived\n\n"
if got != expected {
t.Errorf("Expected %q, got %q", expected, got)
}

// String flag should show it if default is not an empty string
c = &cobra.Command{}
c.Flags().StringVar(&opts.Template, "template", "T1", "Some template")

buf = new(bytes.Buffer)
manPrintFlags(buf, c.Flags())

got = buf.String()
expected = "`--template` `<string> (default \"T1\")`\n: Some template\n\n"
if got != expected {
t.Errorf("Expected %q, got %q", expected, got)
}

// String flag should hide it if default is an empty string
c = &cobra.Command{}
c.Flags().StringVar(&opts.Template, "template", "", "Some template")

buf = new(bytes.Buffer)
manPrintFlags(buf, c.Flags())

got = buf.String()
expected = "`--template` `<string>`\n: Some template\n\n"
if got != expected {
t.Errorf("Expected %q, got %q", expected, got)
}

// String slice flag should hide it if default is an empty slice
c = &cobra.Command{}
c.Flags().StringSliceVar(&opts.Topic, "topic", nil, "Some topics")

buf = new(bytes.Buffer)
manPrintFlags(buf, c.Flags())

got = buf.String()
expected = "`--topic` `<strings>`\n: Some topics\n\n"
if got != expected {
t.Errorf("Expected %q, got %q", expected, got)
}

// String slice flag should show it if default is not an empty slice
c = &cobra.Command{}
c.Flags().StringSliceVar(&opts.Topic, "topic", []string{"apples", "oranges"}, "Some topics")

buf = new(bytes.Buffer)
manPrintFlags(buf, c.Flags())

got = buf.String()
expected = "`--topic` `<strings> (default [apples,oranges])`\n: Some topics\n\n"
if got != expected {
t.Errorf("Expected %q, got %q", expected, got)
}
}

func assertLineFound(scanner *bufio.Scanner, expectedLine string) error {
for scanner.Scan() {
line := scanner.Text()
Expand Down
32 changes: 30 additions & 2 deletions internal/docs/markdown.go
Expand Up @@ -46,17 +46,43 @@ func hasNonHelpFlags(fs *pflag.FlagSet) (found bool) {
return
}

var hiddenFlagDefaults = map[string]bool{
"false": true,
"": true,
"[]": true,
"0s": true,
}

var defaultValFormats = map[string]string{
"string": " (default \"%s\")",
"duration": " (default \"%s\")",
}

andyfeller marked this conversation as resolved.
Show resolved Hide resolved
func getDefaultValueDisplayString(f *pflag.Flag) string {

if hiddenFlagDefaults[f.DefValue] || hiddenFlagDefaults[f.Value.Type()] {
return ""
}

if dvf, found := defaultValFormats[f.Value.Type()]; found {
return fmt.Sprintf(dvf, f.Value)
}
return fmt.Sprintf(" (default %s)", f.Value)
andyfeller marked this conversation as resolved.
Show resolved Hide resolved

}

type flagView struct {
Name string
Varname string
Shorthand string
DefValue string
Usage string
}

var flagsTemplate = `
<dl class="flags">{{ range . }}
<dt>{{ if .Shorthand }}<code>-{{.Shorthand}}</code>, {{ end -}}
<code>--{{.Name}}{{ if .Varname }} &lt;{{.Varname}}&gt;{{ end }}</code></dt>
<dt>{{ if .Shorthand }}<code>-{{.Shorthand}}</code>, {{ end }}
<code>--{{.Name}}{{ if .Varname }} &lt;{{.Varname}}&gt;{{ end }}{{.DefValue}} </code></dt>
<dd>{{.Usage}}</dd>
{{ end }}</dl>
`
Expand All @@ -70,10 +96,12 @@ func printFlagsHTML(w io.Writer, fs *pflag.FlagSet) error {
return
}
varname, usage := pflag.UnquoteUsage(f)

flags = append(flags, flagView{
Name: f.Name,
Varname: varname,
Shorthand: f.Shorthand,
DefValue: getDefaultValueDisplayString(f),
Usage: usage,
})
})
Expand Down
112 changes: 112 additions & 0 deletions internal/docs/markdown_test.go
Expand Up @@ -103,3 +103,115 @@ func BenchmarkGenMarkdownToFile(b *testing.B) {
}
}
}

func TestPrintFlagsHTMLShowsDefaultValues(t *testing.T) {

type TestOptions struct {
Limit int
Template string
Fork bool
NoArchive bool
Topic []string
}
opts := TestOptions{}

// Int flag should show it
c := &cobra.Command{}
c.Flags().IntVar(&opts.Limit, "limit", 30, "Some limit")
flags := c.NonInheritedFlags()
buf := new(bytes.Buffer)
flags.SetOutput(buf)

if err := printFlagsHTML(buf, flags); err != nil {
t.Fatalf("printFlagsHTML failed: %s", err.Error())
}
output := buf.String()

checkStringContains(t, output, "(default 30)")

// Bool flag should hide it if default is false
c = &cobra.Command{}
c.Flags().BoolVar(&opts.Fork, "fork", false, "Show only forks")

flags = c.NonInheritedFlags()
buf = new(bytes.Buffer)
flags.SetOutput(buf)

if err := printFlagsHTML(buf, flags); err != nil {
t.Fatalf("printFlagsHTML failed: %s", err.Error())
}
output = buf.String()

checkStringOmits(t, output, "(default ")

// Bool flag should show it if default is true
c = &cobra.Command{}
c.Flags().BoolVar(&opts.NoArchive, "no-archived", true, "Hide archived")
flags = c.NonInheritedFlags()
buf = new(bytes.Buffer)
flags.SetOutput(buf)

if err := printFlagsHTML(buf, flags); err != nil {
t.Fatalf("printFlagsHTML failed: %s", err.Error())
}
output = buf.String()

checkStringContains(t, output, "(default true)")

// String flag should show it if default is not an empty string
c = &cobra.Command{}
c.Flags().StringVar(&opts.Template, "template", "T1", "Some template")
flags = c.NonInheritedFlags()
buf = new(bytes.Buffer)
flags.SetOutput(buf)

if err := printFlagsHTML(buf, flags); err != nil {
t.Fatalf("printFlagsHTML failed: %s", err.Error())
}
output = buf.String()

checkStringContains(t, output, "(default &#34;T1&#34;)")

// String flag should hide it if default is an empty string
c = &cobra.Command{}
c.Flags().StringVar(&opts.Template, "template", "", "Some template")

flags = c.NonInheritedFlags()
buf = new(bytes.Buffer)
flags.SetOutput(buf)

if err := printFlagsHTML(buf, flags); err != nil {
t.Fatalf("printFlagsHTML failed: %s", err.Error())
}
output = buf.String()

checkStringOmits(t, output, "(default ")

// String slice flag should hide it if default is an empty slice
c = &cobra.Command{}
c.Flags().StringSliceVar(&opts.Topic, "topic", nil, "Some topics")
flags = c.NonInheritedFlags()
buf = new(bytes.Buffer)
flags.SetOutput(buf)

if err := printFlagsHTML(buf, flags); err != nil {
t.Fatalf("printFlagsHTML failed: %s", err.Error())
}
output = buf.String()

checkStringOmits(t, output, "(default ")

// String slice flag should show it if default is not an empty slice
c = &cobra.Command{}
c.Flags().StringSliceVar(&opts.Topic, "topic", []string{"apples", "oranges"}, "Some topics")
flags = c.NonInheritedFlags()
buf = new(bytes.Buffer)
flags.SetOutput(buf)

if err := printFlagsHTML(buf, flags); err != nil {
t.Fatalf("printFlagsHTML failed: %s", err.Error())
}
output = buf.String()

checkStringContains(t, output, "(default [apples,oranges])")
}
5 changes: 4 additions & 1 deletion pkg/cmd/config/config.go
Expand Up @@ -19,8 +19,11 @@ func NewCmdConfig(f *cmdutil.Factory) *cobra.Command {
longDoc.WriteString("Current respected settings:\n")
for _, co := range config.ConfigOptions() {
longDoc.WriteString(fmt.Sprintf("- `%s`: %s", co.Key, co.Description))
if len(co.AllowedValues) > 0 {
longDoc.WriteString(fmt.Sprintf(" {%s}", strings.Join(co.AllowedValues, "|")))
}
if co.DefaultValue != "" {
longDoc.WriteString(fmt.Sprintf(" (default: %q)", co.DefaultValue))
longDoc.WriteString(fmt.Sprintf(" (default %s)", co.DefaultValue))
}
longDoc.WriteRune('\n')
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/gist/create/create.go
Expand Up @@ -96,7 +96,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co

cmd.Flags().StringVarP(&opts.Description, "desc", "d", "", "A description for this gist")
cmd.Flags().BoolVarP(&opts.WebMode, "web", "w", false, "Open the web browser with created gist")
cmd.Flags().BoolVarP(&opts.Public, "public", "p", false, "List the gist publicly (default: secret)")
cmd.Flags().BoolVarP(&opts.Public, "public", "p", false, "List the gist publicly (default \"secret\")")
cmd.Flags().StringVarP(&opts.FilenameOverride, "filename", "f", "", "Provide a filename to be used when reading from standard input")
return cmd
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/pr/checkout/checkout.go
Expand Up @@ -65,7 +65,7 @@ func NewCmdCheckout(f *cmdutil.Factory, runF func(*CheckoutOptions) error) *cobr
cmd.Flags().BoolVarP(&opts.RecurseSubmodules, "recurse-submodules", "", false, "Update all submodules after checkout")
cmd.Flags().BoolVarP(&opts.Force, "force", "f", false, "Reset the existing local branch to the latest state of the pull request")
cmd.Flags().BoolVarP(&opts.Detach, "detach", "", false, "Checkout PR with a detached HEAD")
cmd.Flags().StringVarP(&opts.BranchName, "branch", "b", "", "Local branch name to use (default: the name of the head branch)")
cmd.Flags().StringVarP(&opts.BranchName, "branch", "b", "", "Local branch name to use (default [the name of the head branch])")

return cmd
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/pr/create/create.go
Expand Up @@ -203,7 +203,7 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co
fl.StringVarP(&opts.Body, "body", "b", "", "Body for the pull request")
fl.StringVarP(&bodyFile, "body-file", "F", "", "Read body text from `file` (use \"-\" to read from standard input)")
fl.StringVarP(&opts.BaseBranch, "base", "B", "", "The `branch` into which you want your code merged")
fl.StringVarP(&opts.HeadBranch, "head", "H", "", "The `branch` that contains commits for your pull request (default: current branch)")
fl.StringVarP(&opts.HeadBranch, "head", "H", "", "The `branch` that contains commits for your pull request (default [current branch])")
fl.BoolVarP(&opts.WebMode, "web", "w", false, "Open the web browser to create a pull request")
fl.BoolVarP(&opts.FillVerbose, "fill-verbose", "", false, "Use commits msg+body for description")
fl.BoolVarP(&opts.Autofill, "fill", "f", false, "Use commit info for title and body")
Expand Down
4 changes: 2 additions & 2 deletions pkg/cmd/release/create/create.go
Expand Up @@ -178,14 +178,14 @@ func NewCmdCreate(f *cmdutil.Factory, runF func(*CreateOptions) error) *cobra.Co

cmd.Flags().BoolVarP(&opts.Draft, "draft", "d", false, "Save the release as a draft instead of publishing it")
cmd.Flags().BoolVarP(&opts.Prerelease, "prerelease", "p", false, "Mark the release as a prerelease")
cmd.Flags().StringVar(&opts.Target, "target", "", "Target `branch` or full commit SHA (default: main branch)")
cmd.Flags().StringVar(&opts.Target, "target", "", "Target `branch` or full commit SHA (default [main branch])")
cmd.Flags().StringVarP(&opts.Name, "title", "t", "", "Release title")
cmd.Flags().StringVarP(&opts.Body, "notes", "n", "", "Release notes")
cmd.Flags().StringVarP(&notesFile, "notes-file", "F", "", "Read release notes from `file` (use \"-\" to read from standard input)")
cmd.Flags().StringVarP(&opts.DiscussionCategory, "discussion-category", "", "", "Start a discussion in the specified category")
cmd.Flags().BoolVarP(&opts.GenerateNotes, "generate-notes", "", false, "Automatically generate title and notes for the release")
cmd.Flags().StringVar(&opts.NotesStartTag, "notes-start-tag", "", "Tag to use as the starting point for generating release notes")
cmdutil.NilBoolFlag(cmd, &opts.IsLatest, "latest", "", "Mark this release as \"Latest\" (default: automatic based on date and version)")
cmdutil.NilBoolFlag(cmd, &opts.IsLatest, "latest", "", "Mark this release as \"Latest\" (default [automatic based on date and version])")
cmd.Flags().BoolVarP(&opts.VerifyTag, "verify-tag", "", false, "Abort in case the git tag doesn't already exist in the remote repository")
cmd.Flags().BoolVarP(&opts.NotesFromTag, "notes-from-tag", "", false, "Automatically generate notes from annotated tag")

Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/release/edit/edit.go
Expand Up @@ -79,7 +79,7 @@ func NewCmdEdit(f *cmdutil.Factory, runF func(*EditOptions) error) *cobra.Comman
cmdutil.NilStringFlag(cmd, &opts.Body, "notes", "n", "Release notes")
cmdutil.NilStringFlag(cmd, &opts.Name, "title", "t", "Release title")
cmdutil.NilStringFlag(cmd, &opts.DiscussionCategory, "discussion-category", "", "Start a discussion in the specified category when publishing a draft")
cmd.Flags().StringVar(&opts.Target, "target", "", "Target `branch` or full commit SHA (default: main branch)")
cmd.Flags().StringVar(&opts.Target, "target", "", "Target `branch` or full commit SHA (default [main branch])")
cmd.Flags().StringVar(&opts.TagName, "tag", "", "The name of the tag")
cmd.Flags().StringVarP(&notesFile, "notes-file", "F", "", "Read release notes from `file` (use \"-\" to read from standard input)")
cmd.Flags().BoolVar(&opts.VerifyTag, "verify-tag", false, "Abort in case the git tag doesn't already exist in the remote repository")
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/repo/sync/sync.go
Expand Up @@ -83,7 +83,7 @@ func NewCmdSync(f *cmdutil.Factory, runF func(*SyncOptions) error) *cobra.Comman
}

cmd.Flags().StringVarP(&opts.SrcArg, "source", "s", "", "Source repository")
cmd.Flags().StringVarP(&opts.Branch, "branch", "b", "", "Branch to sync (default: default branch)")
cmd.Flags().StringVarP(&opts.Branch, "branch", "b", "", "Branch to sync (default [default branch])")
cmd.Flags().BoolVarP(&opts.Force, "force", "", false, "Hard reset the branch of the destination repository to match the source repository")
return cmd
}
Expand Down