fix: CLI consistency - usage paths, trial --quiet, pr verbose, secrets examples#18380
fix: CLI consistency - usage paths, trial --quiet, pr verbose, secrets examples#18380
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
…verbose flag, secrets examples Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
|
Hey A couple of things worth addressing before this is ready to merge:
|
There was a problem hiding this comment.
Pull request overview
Fixes several CLI help-text inconsistencies to make command docs and usage output consistent across subcommands, especially ensuring command paths include gh aw rather than gh.
Changes:
- Updates
trialhelp examples to remove a non-existent--quietflag reference. - Removes a shadowing
-v/--verboseflag onpr transferso the global persistent flag is used consistently. - Adds missing
secrets bootstrapexamples and introduces a rootSetUsageFuncto rewrite usage lines fromgh <cmd>togh aw <cmd>.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/cli/trial_command.go | Fixes a broken help example by removing a non-existent flag. |
| pkg/cli/tokens_bootstrap.go | Adds secrets bootstrap CLI examples. |
| pkg/cli/pr_command.go | Removes a local verbose flag that shadowed the global persistent verbose flag. |
| cmd/gh-aw/main.go | Adds a custom usage renderer to ensure usage lines include gh aw in command paths. |
| .devcontainer/devcontainer.json | Reorders the GitHub CLI devcontainer feature entry (no functional change). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Fix usage lines so subcommands show "gh aw <cmd>" instead of "gh <cmd>". | ||
| // Cobra derives the root name from the first word of Use ("gh" from "gh aw"), | ||
| // so CommandPath() for subcommands omits "aw". We use SetUsageFunc to | ||
| // post-process the default output, replacing "gh " with "gh aw " in the | ||
| // two lines that reference the command path. | ||
| rootCmd.SetUsageFunc(func(cmd *cobra.Command) error { | ||
| fixPath := func(s string) string { | ||
| if s == "gh" { | ||
| return "gh aw" | ||
| } | ||
| if strings.HasPrefix(s, "gh ") && !strings.HasPrefix(s, "gh aw") { | ||
| return "gh aw " + s[3:] | ||
| } | ||
| return s | ||
| } | ||
| out := cmd.OutOrStderr() | ||
| fmt.Fprint(out, "Usage:") | ||
| if cmd.Runnable() { | ||
| fmt.Fprintf(out, "\n %s", fixPath(cmd.UseLine())) | ||
| } | ||
| if cmd.HasAvailableSubCommands() { | ||
| fmt.Fprintf(out, "\n %s [command]", fixPath(cmd.CommandPath())) | ||
| } | ||
| if len(cmd.Aliases) > 0 { | ||
| fmt.Fprintf(out, "\n\nAliases:\n %s", cmd.NameAndAliases()) | ||
| } | ||
| if cmd.HasExample() { | ||
| fmt.Fprintf(out, "\n\nExamples:\n%s", cmd.Example) | ||
| } | ||
| if cmd.HasAvailableSubCommands() { | ||
| cmds := cmd.Commands() | ||
| if len(cmd.Groups()) == 0 { | ||
| fmt.Fprint(out, "\n\nAvailable Commands:") | ||
| for _, sub := range cmds { | ||
| if sub.IsAvailableCommand() || sub.Name() == "help" { | ||
| fmt.Fprintf(out, "\n %-11s %s", sub.Name(), sub.Short) | ||
| } | ||
| } | ||
| } else { | ||
| for _, group := range cmd.Groups() { | ||
| fmt.Fprintf(out, "\n\n%s", group.Title) | ||
| for _, sub := range cmds { | ||
| if sub.GroupID == group.ID && (sub.IsAvailableCommand() || sub.Name() == "help") { | ||
| fmt.Fprintf(out, "\n %-11s %s", sub.Name(), sub.Short) | ||
| } | ||
| } | ||
| } | ||
| if !cmd.AllChildCommandsHaveGroup() { | ||
| fmt.Fprint(out, "\n\nAdditional Commands:") | ||
| for _, sub := range cmds { | ||
| if sub.GroupID == "" && (sub.IsAvailableCommand() || sub.Name() == "help") { | ||
| fmt.Fprintf(out, "\n %-11s %s", sub.Name(), sub.Short) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| if cmd.HasAvailableLocalFlags() { | ||
| fmt.Fprintf(out, "\n\nFlags:\n%s", strings.TrimRight(cmd.LocalFlags().FlagUsages(), " \t\n")) | ||
| } | ||
| if cmd.HasAvailableInheritedFlags() { | ||
| fmt.Fprintf(out, "\n\nGlobal Flags:\n%s", strings.TrimRight(cmd.InheritedFlags().FlagUsages(), " \t\n")) | ||
| } | ||
| if cmd.HasAvailableSubCommands() { | ||
| fmt.Fprintf(out, "\n\nUse \"%s [command] --help\" for more information about a command.\n", fixPath(cmd.CommandPath())) | ||
| } else { | ||
| fmt.Fprintln(out) | ||
| } | ||
| return nil | ||
| }) |
There was a problem hiding this comment.
This introduces custom usage rendering to fix the gh vs gh aw command path in help output, but there’s no test asserting the corrected prefix in --help output (only that “Usage:” exists). Since this behavior is user-facing and easy to regress, please add/extend a CLI help/usage test to verify usage lines include gh aw for at least one subcommand (e.g., pr or trial).
| // so CommandPath() for subcommands omits "aw". We use SetUsageFunc to | ||
| // post-process the default output, replacing "gh " with "gh aw " in the | ||
| // two lines that reference the command path. |
There was a problem hiding this comment.
The comment says this “post-process[es] the default output”, but the implementation fully re-renders the usage output (Available Commands/Flags/etc.) rather than modifying Cobra’s default output. This is misleading and also makes it easy for this usage text to drift from upstream Cobra behavior; either update the comment to match what the code does, or prefer wrapping the existing usage output and only rewriting the affected command-path substrings.
| // so CommandPath() for subcommands omits "aw". We use SetUsageFunc to | |
| // post-process the default output, replacing "gh " with "gh aw " in the | |
| // two lines that reference the command path. | |
| // so CommandPath() for subcommands omits "aw". We install a custom usage | |
| // renderer via SetUsageFunc that prints the usage text itself, adjusting | |
| // command paths from "gh" to "gh aw" where needed. |
| if len(cmd.Groups()) == 0 { | ||
| fmt.Fprint(out, "\n\nAvailable Commands:") | ||
| for _, sub := range cmds { | ||
| if sub.IsAvailableCommand() || sub.Name() == "help" { | ||
| fmt.Fprintf(out, "\n %-11s %s", sub.Name(), sub.Short) | ||
| } |
There was a problem hiding this comment.
The Available Commands rendering uses a hard-coded padding width (%-11s). This breaks alignment for longer command names (e.g., hash-frontmatter) and can drift as commands are added/renamed. Consider using Cobra’s dynamic padding (cmd.NamePadding()) or computing the max subcommand name length for the current command when formatting the list.
Four CLI consistency issues identified by automated inspection: broken example flag reference, duplicate verbose flag definition, incorrect usage line prefixes across all subcommands, and missing examples section.
Changes
trialcommand — Removed--quietfrom the "Repeat and cleanup" example; that flag does not existpr transfercommand — Removed local-v/--verboseflag definition that shadowed the root persistent flag;--verbosenow correctly appears underGlobal Flagssecrets bootstrapcommand — Added missingExamplefield with three representative invocationsAll subcommands — usage line prefix fix — Cobra derives the root command name from the first word of
Use: "gh aw", yielding"gh". This caused every subcommand'sCommandPath()to producegh <cmd>instead ofgh aw <cmd>. Added a customSetUsageFuncon the root command that rewrites the affected lines:Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://api.github.com/repos/actions/github-script/git/ref/tags/v8/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha "prettier" --wriGOINSECURE /opt/hostedtoolcGOMOD 64/bin/go /tmp/go-build412go -trimpath run-script/lib/n-json node /opt�� prettier --write 64/bin/go !../../../pkg/wonode --ignore-path ../../../.prettiprettier go(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha echo "��� FormatGOINSECURE go 64/bin/go tierignore GO111MODULE 64/bin/go go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha npx prettier --wGOINSECURE go 64/bin/go -json GO111MODULE 64/bin/go go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts/usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env th .prettierignore GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE k/gh-aw/gh-aw/actions/setup/js/node_modules/.bin/node GOINSECURE GOMOD GOMODCACHE go k/gh�� -json GO111MODULE ache/go/1.25.0/x64/pkg/tool/linux_amd64/asm GOINSECURE GOMOD erignore ache/go/1.25.0/xtest@example.com(http block)/usr/bin/gh gh run download 1 --dir test-logs/run-1 npx /usr/bin/git --write scripts/**/*.js 64/bin/go git rev-�� --show-toplevel sh bash "prettier" --wrigit go(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts/usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env th .prettierignore GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE p/bin/sh GOINSECURE GOMOD GOMODCACHE go env ck '**/*.cjs' '*@{u} GO111MODULE tnet/tools/bash GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 12345 --dir test-logs/run-12345 node /usr/bin/gh --write **/*.cjs 64/bin/go gh run list --json ache/node/24.13.0/x64/bin/bash --workflow nonexistent-workrev-parse --limit git(http block)https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts/usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE sh GOINSECURE GOMOD GOMODCACHE go env th .prettierigno@{u} GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE tnet/tools/sh GOINSECURE GOMOD GOMODCACHE go env ck '**/*.cjs' '**/*.ts' '**/*.json' --ignore-path ../../../.prettierignore GO111MODULE bash GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 12346 --dir test-logs/run-12346 node /usr/bin/infocmp --write **/*.cjs 64/bin/go infocmp -1 xterm-color sh k/_temp/ghcca-node/node/bin/bash "prettier" --wrigit go 64/bin/go git(http block)https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts/usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env th .prettierigno.github/workflows/test.md GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE k/gh-aw/gh-aw/actions/setup/node_modules/.bin/node GOINSECURE GOMOD GOMODCACHE go k/gh�� -json GO111MODULE ache/go/1.25.0/x64/pkg/tool/linux_amd64/cgo GOINSECURE GOMOD erignore ache/go/1.25.0/x64/pkg/tool/linurev-parse(http block)/usr/bin/gh gh run download 2 --dir test-logs/run-2 config /usr/bin/git remote.origin.urgit **/*.cjs 64/bin/go git init�� ../../../.prettinpx prettier --check '**/*.cjs' '**/*.ts' '**/*.json' --ignore-path ../../../.prgit sh tnet/tools/bash "prettier" --wrigit go /sh git(http block)https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts/usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env th .prettierigno@{u} GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE k/gh-aw/node_modules/.bin/node GOINSECURE GOMOD GOMODCACHE go k/gh�� -json GO111MODULE ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD layTitle ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh gh run download 3 --dir test-logs/run-3 config /usr/bin/git remote.origin.urgit --write 64/bin/go git rev-�� --show-toplevel sh /usr/bin/git "prettier" --wrigit go 64/bin/go git(http block)https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts/usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env th .prettierignore GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE k/gh-aw/gh-aw/actions/node_modules/.bin/node GOINSECURE GOMOD GOMODCACHE go k/gh�� -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD erignore go(http block)/usr/bin/gh gh run download 4 --dir test-logs/run-4 rev-parse /usr/bin/git prettier --write 64/bin/go git init�� 64/bin/go sh ash "prettier" --wrigit go 64/bin/go git(http block)https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts/usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env th .prettierignore GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE k/gh-aw/gh-aw/node_modules/.bin/node GOINSECURE GOMOD GOMODCACHE go k/gh�� -json GO111MODULE ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet GOINSECURE GOMOD erignore ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet(http block)/usr/bin/gh gh run download 5 --dir test-logs/run-5 rev-parse /usr/bin/git prettier --write 64/bin/go git init�� 64/bin/go sh Name,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle "prettier" --wrigit go 64/bin/go git(http block)https://api.github.com/repos/github/gh-aw/actions/workflows/usr/bin/gh gh workflow list --json name,state,path --write **/*.cjs 64/bin/go **/*.json --ignore-path ../../../.prettirun sh -c "prettier" --wriGOSUMDB go 64/bin/go -json GO111MODULE run-script/lib/n"prettier" --check 'scripts/**/*.js' --ignore-path .prettierignore go(http block)/usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100 GO111MODULE x_amd64/vet go env h ../../../.prettierignore GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 GOMOD GOMODCACHE go ode_�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/nonexistent/repo/actions/runs/12345/usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE go ules�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE go ache�� -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion remote.origin.urgit go 64/bin/go git rev-�� --show-toplevel node tnet/tools/bash --write ../../../**/*.jsrev-parse /node git(http block)https://api.github.com/repos/owner/repo/actions/workflows/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go **/*.json --ignore-path ../../../.prettinpx prettier --check '**/*.cjs' '**/*.ts' '**/*.json' --ignore-path ../../../.pr**/*.json sh -c "prettier" --wriGOSUMDB go 64/bin/go -json GO111MODULE x_amd64/vet go(http block)/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go **/*.json --ignore-path ../../../.prettinpx prettier --check '**/*.cjs' '**/*.ts' '**/*.json' --ignore-path ../../../.pr**/*.json sh -c "prettier" --wriGOSUMDB go /sh -json GO111MODULE x_amd64/vet go(http block)/usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ules/.bin/sh GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/owner/repo/contents/file.md/tmp/go-build1621784976/b377/cli.test /tmp/go-build1621784976/b377/cli.test -test.testlogfile=/tmp/go-build1621784976/b377/testlog.txt -test.paniconexit0 -test.timeout=10m0s -c "prettier" --wriGOINSECURE /opt/hostedtoolcGOMOD 64/bin/go /tmp/go-build412go -trimpath 64/bin/go sh -c npx prettier --wGOINSECURE go 64/bin/go -json GO111MODULE 64/bin/go go(http block)/tmp/go-build2328939417/b001/cli.test /tmp/go-build2328939417/b001/cli.test -test.testlogfile=/tmp/go-build2328939417/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s ode_�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)/tmp/go-build2461684847/b001/cli.test /tmp/go-build2461684847/b001/cli.test -test.testlogfile=/tmp/go-build2461684847/b001/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.short=true -json GO111MODULE bin/node GOINSECURE GOMOD GOMODCACHE erignore estl�� -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)https://api.github.com/repos/test-owner/test-repo/actions/secrets/usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name --write **/*.cjs 64/bin/go **/*.json --ignore-path ../../../.prettirun sh -c "prettier" --wriGOSUMDB go 64/bin/go -json GO111MODULE x_amd64/vet go(http block)/usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name th .prettierignore GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/node GOINSECURE GOMOD GOMODCACHE go(http block)/usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name ck '**/*.cjs' '**/*.ts' '**/*.json' --ignore-path ../../../.prettierignore GO111MODULE x_amd64/cgo GOINSECURE GOMOD ode-gyp-bin/node--show-toplevel x_amd64/cgo env -json GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go(http block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
This section details on the original issue you should resolve
<issue_title>[cli-consistency] CLI Consistency Issues - 2026-02-25</issue_title>
<issue_description>### Summary
Automated CLI consistency inspection (run 22399090301) found 4 inconsistencies in command help text that should be addressed for better user experience.
Breakdown by Severity
Inspection Details
--helpexecuted for all commands and subcommands)--helpflags and analyzed actual outputFindings Summary
✅ No issues found in these areas:
trial)pr transfer)docs/src/content/docs/setup/cli.mdv0.1is used consistently in both description and flag default)trialhelp text — broken example references non-existent--quietflagpr transfer— defines-v/--verboseas a local flag instead of inheriting from global flagsgh (cmd)instead ofgh aw (cmd)secrets bootstrap— missingExamples:sectionDetailed Findings
1.
trialExample References Non-Existent--quietFlagCommand Affected:
gh aw trialPriority: High
Type: Broken example / missing flag
Current Output (from running
./gh-aw trial --help):