-
Notifications
You must be signed in to change notification settings - Fork 424
Migrate cobra command examples from Long: prose to Example: field #38946
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
Changes from all commits
7935ec4
df34114
6014653
e591daa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # ADR-38946: Use Cobra's `Example:` Field for Command Usage Examples | ||
|
|
||
| **Date**: 2026-06-12 | ||
| **Status**: Draft | ||
|
|
||
| ## Context | ||
|
|
||
| The CLI in `pkg/cli/` defines ~36 cobra commands, and historically every command embedded its usage examples as hand-written prose inside the `Long:` description field under an `Examples:` heading. Cobra provides a dedicated `Example:` field that is rendered separately in `--help` output and, critically, is consumed by `cobra/doc.GenMarkdownTree()` for documentation generation. Because the examples lived inside `Long:`, generated documentation could not surface them in the expected structured location, and the examples were not addressable for testing or tooling. This PR migrates all command definitions to use the native `Example:` field. The change is large by line count but mechanical and repetitive (moving example blocks between two struct fields). | ||
|
|
||
| ## Decision | ||
|
|
||
| We will store all cobra command usage examples in the native cobra `Example:` field rather than embedding them as `Examples:` prose inside the `Long:` field. Non-example prose that previously followed the `Examples:` section (e.g., "Workflow specifications:", "The command will:") is moved back into `Long:` where it belongs. Tests that previously asserted example strings appeared in `cmd.Long` are updated to assert against `cmd.Example`. This aligns the codebase with cobra's intended API contract, restores correct `GenMarkdownTree()` documentation output, and makes examples independently inspectable. | ||
|
|
||
| ## Alternatives Considered | ||
|
|
||
| ### Alternative 1: Keep examples in `Long:` prose | ||
|
|
||
| Leave the existing convention untouched and continue embedding examples under an `Examples:` heading inside `Long:`. Rejected because it breaks `cobra/doc.GenMarkdownTree()` documentation generation, keeps examples untestable as a distinct field, and diverges from cobra's documented usage of the `Example:` field. | ||
|
|
||
| ### Alternative 2: Custom help template / renderer | ||
|
|
||
| Introduce a custom cobra help/usage template that parses the `Examples:` section out of `Long:` at render time. Rejected as unnecessary complexity: it reimplements behavior cobra already provides natively, adds a maintenance burden, and still would not feed `GenMarkdownTree()` correctly. | ||
|
|
||
| ## Consequences | ||
|
|
||
| ### Positive | ||
| - `cobra/doc.GenMarkdownTree()` produces correct documentation with examples in their structured location. | ||
| - Examples become independently testable and inspectable via `cmd.Example`. | ||
| - Command definitions follow cobra's intended API convention, improving consistency across all ~36 commands. | ||
|
|
||
| ### Negative | ||
| - Large, repetitive diff (36 command files plus 8 secondary prose fixes and 5 test updates) that touches many files at once and must be reviewed for correctness. | ||
| - A standing convention contributors must remember to follow for new commands; without a lint check, regressions can reappear. | ||
|
|
||
| ### Neutral | ||
| - `--help` output formatting shifts slightly because the `Example:` field is rendered under cobra's own "Examples:" section heading rather than inline within the long description. | ||
| - Test assertions referencing example content move from `cmd.Long` to `cmd.Example`. | ||
|
|
||
| --- | ||
|
|
||
| *This is a DRAFT ADR generated by the [Design Decision Gate](https://github.com/github/gh-aw/actions/runs/27447688258) workflow. The PR author must review, complete, and finalize this document before the PR can merge.* |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -59,20 +59,6 @@ func NewAddCommand(validateEngine func(string) error) *cobra.Command { | |
| This command adds workflows directly without interactive prompts. Use 'add-wizard' | ||
| for a guided setup that configures secrets, creates a pull request, and more. | ||
|
|
||
| Examples: | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/daily-repo-status # Add workflow directly | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/repo-assist # Add package from repository root aw.yml | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/packages/repo-assist # Add package from nested aw.yml | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor@v1.0.0 # Add with version | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/workflows/ci-doctor.md@main | ||
| ` + string(constants.CLIExtensionPrefix) + ` add https://github.com/githubnext/agentics/blob/main/workflows/ci-doctor.md | ||
| ` + string(constants.CLIExtensionPrefix) + ` add https://example.com/my-workflow.md # Add workflow from any HTTPS URL | ||
| ` + string(constants.CLIExtensionPrefix) + ` add https://example.com/workflow.json # Import JSON workflow definition | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --create-pull-request --force | ||
| ` + string(constants.CLIExtensionPrefix) + ` add ./my-workflow.md # Add local workflow | ||
| ` + string(constants.CLIExtensionPrefix) + ` add ./*.md # Add all local workflows | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --dir .github/workflows/shared # Add to .github/workflows/shared/ | ||
|
|
||
| Workflow specifications: | ||
| - Two parts: "owner/repo[@version]" (loads repository-root aw.yml package) | ||
| - Three+ parts without .md: "owner/repo/folder[@version]" (loads nested aw.yml package when present) | ||
|
|
@@ -96,6 +82,19 @@ Note: In GitHub Enterprise repos, shorthand source specs resolve on your enterpr | |
| Use full https://github.com/... source URLs for other public github.com workflows. | ||
| Note: To create a new workflow from scratch, use the 'new' command instead. | ||
| Note: For guided interactive setup, use the 'add-wizard' command instead.`, | ||
| Example: ` ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/daily-repo-status # Add workflow directly | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/repo-assist # Add package from repository root aw.yml | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/packages/repo-assist # Add package from nested aw.yml | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor@v1.0.0 # Add with version | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/workflows/ci-doctor.md@main | ||
| ` + string(constants.CLIExtensionPrefix) + ` add https://github.com/githubnext/agentics/blob/main/workflows/ci-doctor.md | ||
| ` + string(constants.CLIExtensionPrefix) + ` add https://example.com/my-workflow.md # Add workflow from any HTTPS URL | ||
| ` + string(constants.CLIExtensionPrefix) + ` add https://example.com/workflow.json # Import JSON workflow definition | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --create-pull-request --force | ||
| ` + string(constants.CLIExtensionPrefix) + ` add ./my-workflow.md # Add local workflow | ||
| ` + string(constants.CLIExtensionPrefix) + ` add ./*.md # Add all local workflows | ||
| ` + string(constants.CLIExtensionPrefix) + ` add githubnext/agentics/ci-doctor --dir .github/workflows/shared # Add to .github/workflows/shared/ | ||
| `, | ||
| Args: func(cmd *cobra.Command, args []string) error { | ||
| if len(args) < 1 { | ||
| return fmt.Errorf("missing workflow specification\n\nUsage:\n %s <workflow>...\n\nExamples:\n %[1]s githubnext/agentics/daily-repo-status Add from repository\n %[1]s ./my-workflow.md Add local workflow\n\nRun '%[1]s --help' for more information", cmd.CommandPath()) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [/zoom-out] The 💡 Optional cleanupUpdate the error format string to use return fmt.Errorf(
"missing workflow specification\n\nUsage:\n %s <workflow>...\n\nExample:\n ...",
cmd.CommandPath(),
)This is non-blocking but keeps user-visible text consistent. |
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,7 +23,7 @@ func TestAuditCommandDescriptionsAreConsistent(t *testing.T) { | |
| func TestTrialCommandUsesStandardExamplesHeading(t *testing.T) { | ||
| cmd := NewTrialCommand(func(string) error { return nil }) | ||
|
|
||
| assert.Contains(t, cmd.Long, "Examples:", "trial long help should use the standard examples heading") | ||
| assert.NotEmpty(t, cmd.Example, "trial command should use cobra's Example field for examples") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [/tdd] 💡 Suggested extensionfunc TestAllCommandsHaveExampleField(t *testing.T) {
root := NewRootCommand()
for _, cmd := range root.Commands() {
if cmd.Runnable() {
assert.NotEmpty(t, cmd.Example, "%s should define cobra Example: field", cmd.Name())
}
for _, sub := range cmd.Commands() {
if sub.Runnable() {
assert.NotEmpty(t, sub.Example, "%s %s should define cobra Example: field", cmd.Name(), sub.Name())
}
}
}
}This acts as a lint guard preventing future regressions without any per-command boilerplate. |
||
| assert.NotContains(t, cmd.Long, "Single workflow:", "trial long help should avoid custom example section headings") | ||
| assert.NotContains(t, cmd.Long, "Multiple workflows (for comparison):", "trial long help should avoid custom example section headings") | ||
| assert.NotContains(t, cmd.Long, "Workflows from different repositories:", "trial long help should avoid custom example section headings") | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[/zoom-out] Trailing
\ninconsistency: this Example field ends with a blank line before the closing backtick, but the majority of the 36 migrated commands do not. Seven files share this pattern (add_command.go,add_wizard_command.go,mcp_add.go,mcp_inspect.go,mcp_list.go,mcp_list_tools.go,trial_command.go). Cobra normalises trailing whitespace in help output so this is invisible at runtime, but the source inconsistency will make future diffs noisier.💡 Suggested fix
Remove the blank line before the closing backtick in all seven files:
This makes the style consistent with the other 29 migrated commands.