cli/cli
Patterns and conventions
The conventions in this section are repeated across hundreds of command packages. Following them is mandatory; CI lint catches most deviations.
The Options + Factory pattern
Every gh foo bar lives in pkg/cmd/foo/bar/bar.go and exposes:
type BarOptions struct {
IO *iostreams.IOStreams
HttpClient func() (*http.Client, error)
Config func() (gh.Config, error)
BaseRepo func() (ghrepo.Interface, error)
// ...flags...
Limit int
State string
Web bool
}
func NewCmdBar(f *cmdutil.Factory, runF func(*BarOptions) error) *cobra.Command {
opts := &BarOptions{
IO: f.IOStreams,
HttpClient: f.HttpClient,
Config: f.Config,
}
cmd := &cobra.Command{
Use: "bar [<flags>]",
Short: "Do the thing",
Example: heredoc.Doc(`
# Do the thing
$ gh foo bar --flag value
`),
RunE: func(cmd *cobra.Command, args []string) error {
opts.BaseRepo = f.BaseRepo // lazy: must happen here, not above
if runF != nil {
return runF(opts)
}
return barRun(opts)
},
}
cmd.Flags().IntVarP(&opts.Limit, "limit", "L", 30, "Maximum results")
return cmd
}
func barRun(opts *BarOptions) error {
// business logic
}Rules that come up in code review:
opts.BaseRepo,opts.Branch, andopts.Remotesare assigned insideRunE, never insideNewCmdBar. The factory closures capture state that is not safe to evaluate at construction time (forgh version,gh completion, etc.).runFis the test injection point. Tests pass a stub that capturesoptsand asserts against it. Production callers leave it nil.- Business logic lives in
barRun(or similar). The constructor only handles flag parsing and validation.
Help text style
Use heredoc.Doc for Long and Example. Examples use # comment lines plus $ command lines. Example from gh issue list:
Example: heredoc.Doc(`
$ gh issue list -l "bug" -l "help wanted"
$ gh issue list -A monalisa
$ gh issue list -a "@me"
$ gh issue list -s "open"
`),JSON output
For list-style commands, add JSON flags via the shared helper:
cmdutil.AddJSONFlags(cmd, &opts.Exporter, []string{
"id", "number", "title", "state", "createdAt",
})In the run function:
if opts.Exporter != nil {
return opts.Exporter.Write(opts.IO, data)
}Pair the change with an entry in the jsonfieldstest so each declared field is asserted to exist on the struct.
Error types
pkg/cmdutil/errors.go defines the project's typed errors:
| Error | Use |
|---|---|
cmdutil.FlagErrorf("...") |
Flag validation. Cobra prints usage. |
cmdutil.SilentError |
Non-zero exit, no message (the command already printed). |
cmdutil.CancelError |
User cancelled. Maps to exit code 2. |
cmdutil.PendingError |
Asynchronous result pending. Maps to exit code 8. |
cmdutil.NoResultsError |
"no |
Mutually exclusive flags use cmdutil.MutuallyExclusive("message", cond1, cond2).
Feature detection
Capability differences between GitHub.com and GHES are handled at runtime with internal/featuredetection. Every detected branch needs a tracked cleanup ID:
// TODO ApiActorsSupported
if features.ApiActorsSupported {
// new path
} else {
// GHES fallback
}The // TODO <cleanupIdentifier> comment is required by the lint; it makes it trivial to grep for the cleanup work after the older GHES is no longer supported.
API access
client := api.NewClientFromHTTP(httpClient)
client.GraphQL(hostname, query, variables, &data)
client.REST(hostname, "GET", "repos/owner/repo", nil, &data)For host resolution, prefer cfg.Authentication().DefaultHost() over ghinstance.Default(), because the former honours GH_HOST and per-user defaults.
Code style
- Add godoc comments to all exported functions, types, and constants.
- Do not write inline comments that restate the code. Comment the why, not the what.
- Never use em dashes (
-) in code, comments, or docs. The lint enforces this via a customforbidigorule. - Prefer small, composable functions; commands should be testable end-to-end with mocked dependencies.
Cross-cutting subsystems
Pages that go deeper on shared infrastructure:
- API client -
api/. - Factory and cmdutil - the dependency-injection backbone.
- IOStreams - terminal abstraction.
- HTTP mocking - testing infrastructure.
- Feature detection - capability probing.
- Prompter and survey - interactive UI.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.