Open-Source Wikis

/

GitHub CLI

/

Systems

/

Factory and cmdutil

cli/cli

Factory and cmdutil

Active contributors: Mislav, Sam Coe, William Martin

Purpose

cmdutil.Factory is the dependency-injection backbone of the CLI. Every command receives a *cmdutil.Factory and pulls only the functions it needs (HTTP client, prompter, base repo, IOStreams, ...). The package also collects the reusable building blocks that almost every command imports: typed errors, JSON output flags, mutually-exclusive-flag helper, and the auth-check guard.

Directory layout

pkg/cmdutil/
  factory.go               # The Factory struct
  errors.go                # FlagErrorf, SilentError, CancelError, PendingError, NoResultsError
  flags.go                 # NilStringFlag, NilBoolFlag, StringEnumFlag, StringSliceVar
  json_flags.go            # AddJSONFlags, Exporter, Write
  args.go                  # Cobra arg validators
  auth_check.go            # CheckAuth used by root.PersistentPreRunE
  cmdgroup.go              # AddGroup helper
  legacy.go                # Bridge for older patterns
  repo_override.go         # Implements --repo
  telemetry.go             # RecordTelemetryForSubcommands
  file_input.go            # Read body input from --body-file
  factory.go               # Factory struct definition

pkg/cmd/factory/
  default.go               # New: assembles the Factory in the real binary
  remote_resolver.go       # Smart resolver behind SmartBaseRepoFunc

Key abstractions

Symbol File Role
Factory pkg/cmdutil/factory.go The DI struct.
factory.New pkg/cmd/factory/default.go Builds the real factory: HTTP client, git client, prompter, browser, extension manager, base repo, branch.
BaseRepoFunc default.go Default base repo: first eligible remote.
SmartBaseRepoFunc default.go Network-resolving base repo: honours gh repo set-default and resolves fork networks via the API. Used by pr, issue, repo, etc.
HttpClientFunc default.go Lazily creates the HTTP client with the full transport stack.
cmdutil.AddJSONFlags json_flags.go Adds --json, --jq, --template flags backed by an Exporter.
cmdutil.MutuallyExclusive errors.go Returns an error when more than one of a set of flags is set.
cmdutil.CheckAuth / IsAuthCheckEnabled auth_check.go Used by the root command's PersistentPreRunE to require login.
RecordTelemetryForSubcommands telemetry.go Walks the Cobra tree and wraps each subcommand to emit a telemetry event.
NilStringFlag / NilBoolFlag flags.go Optional-flag helpers that distinguish "not set" from zero value.

How it works

graph TD
    A[ghcmd.Main] --> B[factory.New]
    B --> C[HttpClient lazy func]
    B --> D[GitClient eagerly created]
    B --> E[Remotes lazy func]
    B --> F[BaseRepo - simple lazy func]
    B --> G[Prompter]
    B --> H[Browser]
    B --> I[ExtensionManager]
    B --> J[Branch lazy func]

    A --> K[root.NewCmdRoot]
    K --> L[copy of factory with SmartBaseRepoFunc]
    L --> M[register pr/issue/repo/release/...]
    K --> N[register simple-resolver commands]

Lazy functions are everywhere because some commands run before a config exists (gh version, gh completion, gh auth login).

The smart resolver:

  1. Reads the local git remotes through git.Client.
  2. Filters to remotes whose hosts are authenticated.
  3. Sorts by upstream, github, origin, then alphabetical.
  4. Reads the resolved git config key on each remote: base keeps that remote, a owner/repo value pins to a specific repo regardless of remote.
  5. Falls back to the API to resolve fork networks if no resolution exists, then prompts the user to pick if interactive.

Integration points

  • Touched by every command. New commands typically declare IO, HttpClient, Config, and BaseRepo as fields on their FooOptions struct.
  • Errors of type cmdutil.SilentError exit with code 1 but suppress the message; commands use this when they have already printed.
  • cmdutil.CancelError is what propagates from a cancelled prompt; it maps to exit code 2.

Entry points for modification

  • Adding a dependency every command needs: extend Factory and update factory.New. Be very conservative: this is a hot path and any new field gets used hundreds of times.
  • Changing repo resolution: edit pkg/cmd/factory/remote_resolver.go and the BaseRepoFunc / SmartBaseRepoFunc in default.go. Cover changes with the existing tests in default_test.go and remote_resolver_test.go.
  • New common flag: add it under pkg/cmdutil/flags.go and share it via cmdutil.AddJSONFlags-style helpers.

Key source files

File Purpose
pkg/cmdutil/factory.go Factory struct.
pkg/cmd/factory/default.go Factory assembly.
pkg/cmd/factory/remote_resolver.go Remote ordering and filtering.
pkg/cmdutil/errors.go Typed errors.
pkg/cmdutil/json_flags.go JSON output flags.
pkg/cmdutil/auth_check.go Auth gate.
pkg/cmdutil/telemetry.go Per-command telemetry wrapping.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Factory and cmdutil – GitHub CLI wiki