# gh-stack config.Config Struct and Test Overrides: Complete Configuration Guide

> Explore gh-stack config.Config struct and test overrides to centralize runtime settings including I/O streams and service dependencies for deterministic testing. Learn configuration options now.

- Repository: [GitHub/gh-stack](https://github.com/github/gh-stack)
- Tags: api-reference
- Published: 2026-08-03

---

**The `config.Config` struct centralizes all runtime settings for the gh-stack extension, bundling I/O streams, color formatting helpers, interactive prompt callbacks, and service overrides that enable deterministic testing through dependency injection.**

The `github/gh-stack` repository implements a centralized configuration pattern to manage CLI behavior and facilitate unit testing. Understanding the **gh-stack config.Config struct and test overrides** is essential for extending functionality or debugging interaction flows. This configuration object aggregates everything from stdout/stderr writers to mockable GitHub client interfaces into a single injectable dependency consumed by all subcommands.

## Config Struct Fields Overview

The `Config` struct defined in [`internal/config/config.go`](https://github.com/github/gh-stack/blob/main/internal/config/config.go) exposes several field categories that control both runtime behavior and testability.

### I/O Streams and Color Formatting

The struct captures output destinations and text styling functions to ensure consistent terminal rendering across platforms:

- **Stdout** and **Stderr** (`io.Writer`): Destination writers for normal and error output. In production, these map to `os.Stdout` and `os.Stderr`, while tests replace them with `bytes.Buffer` instances via `config.NewTestConfig`.
- **ColorFn**, **BoldFn**, **ErrorFn**, **InfoFn**, **SuccessFn**, **WarningFn** (`func(string) string`): Helper functions that apply ANSI escape codes for terminal styling. Production implementations wrap text in color codes, whereas tests substitute identity functions (`func(s string) string { return s }`) to produce deterministic output.

### Interactive Prompt Hooks

To enable non-interactive testing, the struct includes function fields that replace user input mechanisms:

- **Interactive** (`bool`): Global flag indicating whether the environment supports user interaction. Set to `false` in CI environments and most test scenarios.
- **SelectFn** (`func(prompt, defaultValue string, options []string) (int, error)`): Replaces the "select one of N options" UI. Tests stub this to return predetermined indices.
- **ConfirmFn** (`func(prompt string, defaultValue bool) (bool, error)`): Hook for yes/no prompts. Test implementations return fixed boolean values.
- **InputFn** (`func(prompt, defaultValue string) (string, error)`): Handles free-form text input. Tests provide deterministic string responses.

### Service and Repository Overrides

The struct supports dependency injection for external services:

- **RepoOverride** (`string`): Forces commands to target a specific repository instead of detecting the current working directory's remote. Used extensively in tests with temporary fixture repositories.
- **GitHubClientOverride** (`github.ClientOps`): Swaps the live GitHub API client with a mock implementation (`github.MockClient`). The `config.NewTestConfig` helper automatically initializes this field for test configurations.
- **GitOverride** (`git.Ops`): Though the field exists in `Config` primarily for completeness and is not always stored directly, it allows replacement of git operations with `git.MockOps` via the global `git.SetOps()` function.

### Internal Testing Flags

- **TestMode** (`bool`): Signals execution under the test harness, enabling additional sanity checks such as strict mock restoration verification.

## Test Configuration Patterns

The [`internal/config/testing.go`](https://github.com/github/gh-stack/blob/main/internal/config/testing.go) file provides the `NewTestConfig` constructor that standardizes test setup across the suite.

### Creating Test Configurations

The helper function returns a fully initialized config along with capture buffers:

```go
func NewTestConfig() (*Config, *bytes.Buffer, *bytes.Buffer) {
    stdout := new(bytes.Buffer)
    stderr := new(bytes.Buffer)
    cfg := &Config{
        Stdout:      stdout,
        Stderr:      stderr,
        ColorFn:     func(s string) string { return s },
        BoldFn:      func(s string) string { return s },
        Interactive: false,
    }
    return cfg, stdout, stderr
}

```

This implementation disables color formatting and interactivity by default, ensuring tests produce stable, parseable output regardless of terminal capabilities.

### Customizing Test Behavior

Individual tests override specific hooks to simulate user interactions:

```go
cfg, stdout, stderr := config.NewTestConfig()

// Force selection of the second option (index 1)
cfg.SelectFn = func(_, _ string, _ []string) (int, error) { 
    return 1, nil 
}

// Always confirm prompts
cfg.ConfirmFn = func(_ string, _ bool) (bool, error) { 
    return true, nil 
}

// Provide deterministic text input
cfg.InputFn = func(_, _ string) (string, error) { 
    return "feature-branch", nil 
}

// Inject mock GitHub client
cfg.GitHubClientOverride = &github.MockClient{
    ListStacksFn: func(_ context.Context, _, _ string) ([]github.Stack, error) {
        return []github.Stack{{ID: "S1", Number: 42}}, nil
    },
}

```

## Implementation in Commands

Command implementations in the `cmd/` directory receive `*config.Config` as their primary dependency. According to [`cmd/utils.go`](https://github.com/github/gh-stack/blob/main/cmd/utils.go) (lines 1420-1430 and 1760-1770), commands check whether prompt hooks are `nil` before invoking them, falling back to real interactive implementations when running in production.

For example, a command consuming the configuration:

```go
func runAdd(cfg *config.Config, args []string) error {
    // Use configured stdout
    fmt.Fprintln(cfg.Stdout, "Processing...")
    
    // Check if running in interactive mode
    if cfg.Interactive && cfg.SelectFn != nil {
        idx, err := cfg.SelectFn("Choose stack", "", []string{"A", "B"})
        if err != nil {
            return err
        }
        // process selection...
    }
    
    // Use potentially mocked GitHub client
    client := cfg.GitHubClientOverride
    if client == nil {
        // initialize real client
    }
}

```

## Key Source File Locations

Understanding the complete configuration system requires examining these specific files in the `github/gh-stack` repository:

- **[`internal/config/config.go`](https://github.com/github/gh-stack/blob/main/internal/config/config.go)**: Defines the `Config` struct and its field types.
- **[`internal/config/testing.go`](https://github.com/github/gh-stack/blob/main/internal/config/testing.go)**: Implements `NewTestConfig` and test-specific initialization logic.
- **[`cmd/utils.go`](https://github.com/github/gh-stack/blob/main/cmd/utils.go)**: Contains UI helper functions that respect `SelectFn`, `ConfirmFn`, and `InputFn` overrides (see lines 1420-1430 and 1760-1770).
- **[`internal/github/mock_client.go`](https://github.com/github/gh-stack/blob/main/internal/github/mock_client.go)**: Provides the `MockClient` type used with `GitHubClientOverride`.
- **[`internal/git/mock_ops.go`](https://github.com/github/gh-stack/blob/main/internal/git/mock_ops.go)**: Defines `MockOps` for git operation substitution.

## Summary

- **`config.Config`** aggregates I/O writers, color helpers, prompt callbacks, and service overrides into a single injectable configuration object defined in [`internal/config/config.go`](https://github.com/github/gh-stack/blob/main/internal/config/config.go).
- **Test overrides** include `NewTestConfig` for standardized setup, buffer-based stdout/stderr capture, identity color functions, and mockable client interfaces.
- **Interactive hooks** (`SelectFn`, `ConfirmFn`, `InputFn`) allow deterministic simulation of user input without actual terminal interaction.
- **Service overrides** (`GitHubClientOverride`, `RepoOverride`) enable testing against mock GitHub API responses and temporary fixture repositories.
- **Source locations** span [`internal/config/config.go`](https://github.com/github/gh-stack/blob/main/internal/config/config.go), [`internal/config/testing.go`](https://github.com/github/gh-stack/blob/main/internal/config/testing.go), and [`cmd/utils.go`](https://github.com/github/gh-stack/blob/main/cmd/utils.go) for the core configuration logic.

## Frequently Asked Questions

### How do I disable color output when testing gh-stack commands?

Set the color helper fields to identity functions that return strings unchanged. The `config.NewTestConfig` helper does this automatically by assigning `func(s string) string { return s }` to `ColorFn`, `BoldFn`, and other styling fields in [`internal/config/testing.go`](https://github.com/github/gh-stack/blob/main/internal/config/testing.go), producing plain text suitable for assertions.

### What is the purpose of GitHubClientOverride in the Config struct?

`GitHubClientOverride` allows tests to substitute the live GitHub API client with a `github.MockClient` implementation. This field accepts any type satisfying the `github.ClientOps` interface, enabling deterministic testing of stack operations without network calls or authentication requirements.

### How does the Interactive field affect command execution?

When `Interactive` is `false`, commands skip user prompts entirely or use default values, making the tool suitable for CI pipelines. In test environments, `NewTestConfig` sets this to `false` by default, while individual tests can combine it with stubbed `SelectFn` or `ConfirmFn` functions to simulate specific user choices programmatically.

### Where are the mock implementations for git operations defined?

The [`internal/git/mock_ops.go`](https://github.com/github/gh-stack/blob/main/internal/git/mock_ops.go) file defines `MockOps`, which implements the git operation interface used throughout gh-stack. While `Config` contains fields for service overrides, git operations are typically replaced using `git.SetOps(&git.MockOps{...})` in test setup, allowing commands to execute against synthetic repository states without modifying the filesystem.