feat(docs): add UsageText to docs output for markdown and man page generation (#1171)

* feat(docs): add UsageText to docs output for markdown and man page generation

* feat(docs): updated tests, DRYd up code, cleaned up string logic

* fix(lint): fixed go1.15 lint errors
This commit is contained in:
Derek Smith 2021-05-20 20:04:51 -05:00 committed by GitHub
parent e79ceb69ff
commit 581b769cf3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 320 additions and 7 deletions

48
docs.go
View File

@ -68,15 +68,16 @@ func prepareCommands(commands []*Command, level int) []string {
if command.Hidden {
continue
}
usage := ""
if command.Usage != "" {
usage = command.Usage
}
prepared := fmt.Sprintf("%s %s\n\n%s\n",
usageText := prepareUsageText(command)
usage := prepareUsage(command, usageText)
prepared := fmt.Sprintf("%s %s\n\n%s%s",
strings.Repeat("#", level+2),
strings.Join(command.Names(), ", "),
usage,
usageText,
)
flags := prepareArgsWithValues(command.Flags)
@ -155,3 +156,40 @@ func flagDetails(flag DocGenerationFlag) string {
}
return ": " + description
}
func prepareUsageText(command *Command) string {
if command.UsageText == "" {
return ""
}
// Remove leading and trailing newlines
preparedUsageText := strings.Trim(command.UsageText, "\n")
var usageText string
if strings.Contains(preparedUsageText, "\n") {
// Format multi-line string as a code block using the 4 space schema to allow for embedded markdown such
// that it will not break the continuous code block.
for _, ln := range strings.Split(preparedUsageText, "\n") {
usageText += fmt.Sprintf(" %s\n", ln)
}
} else {
// Style a single line as a note
usageText = fmt.Sprintf(">%s\n", preparedUsageText)
}
return usageText
}
func prepareUsage(command *Command, usageText string) string {
if command.Usage == "" {
return ""
}
usage := command.Usage + "\n"
// Add a newline to the Usage IFF there is a UsageText
if usageText != "" {
usage += "\n"
}
return usage
}

View File

@ -67,6 +67,47 @@ func testApp() *App {
}, {
Name: "hidden-command",
Hidden: true,
}, {
Aliases: []string{"u"},
Flags: []Flag{
&StringFlag{
Name: "flag",
Aliases: []string{"fl", "f"},
TakesFile: true,
},
&BoolFlag{
Name: "another-flag",
Aliases: []string{"b"},
Usage: "another usage text",
},
},
Name: "usage",
Usage: "standard usage text",
UsageText: `
Usage for the usage text
- formatted: Based on the specified ConfigMap and summon secrets.yml
- list: Inspect the environment for a specific process running on a Pod
- for_effect: Compare 'namespace' environment with 'local'
` + "```" + `
func() { ... }
` + "```" + `
Should be a part of the same code block
`,
Subcommands: []*Command{{
Aliases: []string{"su"},
Flags: []Flag{
&BoolFlag{
Name: "sub-command-flag",
Aliases: []string{"s"},
Usage: "some usage text",
},
},
Name: "sub-usage",
Usage: "standard usage text",
UsageText: "Single line of UsageText",
}},
}}
app.UsageText = "app [first_arg] [second_arg]"
app.Usage = "Some app"
@ -175,3 +216,110 @@ func TestToManWithSection(t *testing.T) {
expect(t, err, nil)
expectFileContent(t, "testdata/expected-doc-full.man", res)
}
func Test_prepareUsageText(t *testing.T) {
t.Run("no UsageText provided", func(t *testing.T) {
// Given
cmd := Command{}
// When
res := prepareUsageText(&cmd)
// Then
expect(t, res, "")
})
t.Run("single line UsageText", func(t *testing.T) {
// Given
cmd := Command{UsageText: "Single line usage text"}
// When
res := prepareUsageText(&cmd)
// Then
expect(t, res, ">Single line usage text\n")
})
t.Run("multiline UsageText", func(t *testing.T) {
// Given
cmd := Command{
UsageText: `
Usage for the usage text
- Should be a part of the same code block
`,
}
// When
res := prepareUsageText(&cmd)
// Then
test := ` Usage for the usage text
- Should be a part of the same code block
`
expect(t, res, test)
})
t.Run("multiline UsageText has formatted embedded markdown", func(t *testing.T) {
// Given
cmd := Command{
UsageText: `
Usage for the usage text
` + "```" + `
func() { ... }
` + "```" + `
Should be a part of the same code block
`,
}
// When
res := prepareUsageText(&cmd)
// Then
test := ` Usage for the usage text
` + "```" + `
func() { ... }
` + "```" + `
Should be a part of the same code block
`
expect(t, res, test)
})
}
func Test_prepareUsage(t *testing.T) {
t.Run("no Usage provided", func(t *testing.T) {
// Given
cmd := Command{}
// When
res := prepareUsage(&cmd, "")
// Then
expect(t, res, "")
})
t.Run("simple Usage", func(t *testing.T) {
// Given
cmd := Command{Usage: "simple usage text"}
// When
res := prepareUsage(&cmd, "")
// Then
expect(t, res, cmd.Usage+"\n")
})
t.Run("simple Usage with UsageText", func(t *testing.T) {
// Given
cmd := Command{Usage: "simple usage text"}
// When
res := prepareUsage(&cmd, "a non-empty string")
// Then
expect(t, res, cmd.Usage+"\n\n")
})
}

View File

@ -75,4 +75,46 @@ another usage test
.PP
retrieve generic information
.SH some\-command
.SH some\-command
.SH usage, u
.PP
standard usage text
.PP
.RS
.nf
Usage for the usage text
\- formatted: Based on the specified ConfigMap and summon secrets.yml
\- list: Inspect the environment for a specific process running on a Pod
\- for\_effect: Compare 'namespace' environment with 'local'
```
func() { ... }
```
Should be a part of the same code block
.fi
.RE
.PP
\fB\-\-another\-flag, \-b\fP: another usage text
.PP
\fB\-\-flag, \-\-fl, \-f\fP="":
.SS sub\-usage, su
.PP
standard usage text
.PP
.RS
.PP
Single line of UsageText
.RE
.PP
\fB\-\-sub\-command\-flag, \-s\fP: some usage text

View File

@ -58,3 +58,29 @@ retrieve generic information
## some-command
## usage, u
standard usage text
Usage for the usage text
- formatted: Based on the specified ConfigMap and summon secrets.yml
- list: Inspect the environment for a specific process running on a Pod
- for_effect: Compare 'namespace' environment with 'local'
```
func() { ... }
```
Should be a part of the same code block
**--another-flag, -b**: another usage text
**--flag, --fl, -f**="":
### sub-usage, su
standard usage text
>Single line of UsageText
**--sub-command-flag, -s**: some usage text

View File

@ -58,3 +58,29 @@ retrieve generic information
## some-command
## usage, u
standard usage text
Usage for the usage text
- formatted: Based on the specified ConfigMap and summon secrets.yml
- list: Inspect the environment for a specific process running on a Pod
- for_effect: Compare 'namespace' environment with 'local'
```
func() { ... }
```
Should be a part of the same code block
**--another-flag, -b**: another usage text
**--flag, --fl, -f**="":
### sub-usage, su
standard usage text
>Single line of UsageText
**--sub-command-flag, -s**: some usage text

View File

@ -43,3 +43,29 @@ retrieve generic information
## some-command
## usage, u
standard usage text
Usage for the usage text
- formatted: Based on the specified ConfigMap and summon secrets.yml
- list: Inspect the environment for a specific process running on a Pod
- for_effect: Compare 'namespace' environment with 'local'
```
func() { ... }
```
Should be a part of the same code block
**--another-flag, -b**: another usage text
**--flag, --fl, -f**="":
### sub-usage, su
standard usage text
>Single line of UsageText
**--sub-command-flag, -s**: some usage text

View File

@ -2,7 +2,7 @@
function __fish_greet_no_subcommand --description 'Test if there has been any subcommand yet'
for i in (commandline -opc)
if contains -- $i config c sub-config s ss info i in some-command
if contains -- $i config c sub-config s ss info i in some-command usage u sub-usage su
return 1
end
end
@ -27,3 +27,10 @@ complete -c greet -n '__fish_seen_subcommand_from info i in' -f -l help -s h -d
complete -r -c greet -n '__fish_greet_no_subcommand' -a 'info i in' -d 'retrieve generic information'
complete -c greet -n '__fish_seen_subcommand_from some-command' -f -l help -s h -d 'show help'
complete -r -c greet -n '__fish_greet_no_subcommand' -a 'some-command'
complete -c greet -n '__fish_seen_subcommand_from usage u' -f -l help -s h -d 'show help'
complete -r -c greet -n '__fish_greet_no_subcommand' -a 'usage u' -d 'standard usage text'
complete -c greet -n '__fish_seen_subcommand_from usage u' -l flag -s fl -s f -r
complete -c greet -n '__fish_seen_subcommand_from usage u' -f -l another-flag -s b -d 'another usage text'
complete -c greet -n '__fish_seen_subcommand_from sub-usage su' -f -l help -s h -d 'show help'
complete -r -c greet -n '__fish_seen_subcommand_from usage u' -a 'sub-usage su' -d 'standard usage text'
complete -c greet -n '__fish_seen_subcommand_from sub-usage su' -f -l sub-command-flag -s s -d 'some usage text'