feat: add command groups to help output for better organization#10
Conversation
There was a problem hiding this comment.
Pull request overview
Adds optional command grouping support to the CLI help output so large CLIs can present commands under labeled headings, while preserving the existing flat help layout when no groups are provided.
Changes:
- Introduces
CommandGroupand extendsBasicHelpFunc(app string, groups ...CommandGroup)to render grouped help output. - Keeps the original flat help output when
groupsis omitted (backward-compatible call sites). - Adds a new
help_test.gotest suite covering flat vs grouped output andFilteredHelpFuncinteroperability.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| help.go | Adds CommandGroup and grouped rendering logic to BasicHelpFunc while keeping the original flat output when no groups are passed. |
| help_test.go | Adds unit tests for flat/grouped help rendering plus an end-to-end CLI.Run -h grouped output test. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // printSection writes a titled block of commands. Commands that are | ||
| // not present in the commands map are silently skipped. | ||
| printSection := func(title string, keys []string) { | ||
| var present []string | ||
| for _, k := range keys { | ||
| if _, ok := commands[k]; ok { | ||
| present = append(present, k) | ||
| } | ||
| } | ||
| if len(present) == 0 { | ||
| return | ||
| } | ||
| sort.Strings(present) | ||
| buf.WriteString(title + "\n") | ||
| for _, key := range present { | ||
| commandFunc := commands[key] | ||
| command, err := commandFunc() | ||
| if err != nil { | ||
| fmt.Fprintf(os.Stderr, "[ERR] cli: Command '%s' failed to load: %s\n", key, err) | ||
| continue | ||
| } | ||
| padded := key + strings.Repeat(" ", maxKeyLen-len(key)) | ||
| buf.WriteString(fmt.Sprintf(" %s %s\n", padded, command.Synopsis())) | ||
| } | ||
| } |
There was a problem hiding this comment.
If the same command key appears more than once in a group's Commands list (or appears in multiple groups), it will be rendered multiple times and its CommandFactory will be invoked multiple times. Consider de-duplicating command keys (within a section and/or globally with a rendered set so “first group wins”) to avoid confusing help output and redundant command loading when groups are misconfigured.
| key = fmt.Sprintf("%s%s", key, strings.Repeat(" ", maxKeyLen-len(key))) | ||
| buf.WriteString(fmt.Sprintf(" %s %s\n", key, command.Synopsis())) | ||
| for _, g := range groups { | ||
| printSection(g.Name+":", g.Commands) |
There was a problem hiding this comment.
Groups with an empty or whitespace-only Name currently render a bare ":" heading (since the code always appends ":"). It would be safer to skip such groups (e.g., trim and require non-empty) or provide a default heading to avoid odd output.
| printSection(g.Name+":", g.Commands) | |
| title := strings.TrimSpace(g.Name) | |
| if title == "" { | |
| // Skip groups with empty or whitespace-only names to avoid | |
| // rendering a bare ":" heading. | |
| continue | |
| } | |
| printSection(title+":", g.Commands) |
| } | ||
|
|
||
| // --------------------------------------------------------------------------- | ||
| // Backward compatibility: CLI wired with no groups renders flat output |
There was a problem hiding this comment.
The section header says this test covers backward compatibility / "no groups renders flat output", but the test actually configures BasicHelpFunc with groups and asserts grouped headings. Please update the comment (or test name) so it matches what the test is validating.
| // Backward compatibility: CLI wired with no groups renders flat output | |
| // Backward compatibility: CLI wired with groups renders grouped output |
Summary
Type of change
Checklist
go test -race ./...passes locallygolangci-lint run ./...passes locally (or lint issues are intentional and explained)CHANGELOG.mdupdated under## [Unreleased](for features and bug fixes)(
feat: ...,fix: ...,docs: ..., etc.)Testing notes
Breaking change migration guide
No breaking changes