gittest

package
v0.13.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package gittest is the shared hermetic-git environment for tests that spawn git as a subprocess (iss-28).

The problem it closes: a test that builds `exec.Command("git", …)` and lets it inherit os.Environ() also inherits any ambient GIT_DIR/GIT_WORK_TREE/ GIT_INDEX_FILE/GIT_CONFIG_* the process was launched with. A pre-commit or prompt hook, for instance, exports GIT_DIR — which OVERRIDES `-C dir`/cmd.Dir and silently redirects the test's `git init`/`commit` onto the real repository. The developer's ~/.gitconfig identity/aliases leak in the same way. Both make a test non-hermetic, and the redirect can mutate the ambient repo.

Env(t) is the single fix: it reuses the SAME production scrub as gitutil.IsolatedEnv() (so a test git command runs under exactly the isolation production git runs under) and additionally pins HOME/XDG to a per-test temp dir. Assign its result to cmd.Env for every git command a test spawns.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Env

func Env(t *testing.T) []string

Env pins HOME and the XDG config/data dirs to a per-test temp location and returns the isolated environment a git subprocess must run under. The returned slice is gitutil.IsolatedEnv(): the parent environment with every repo-selection and config-injection variable stripped (GIT_DIR, GIT_WORK_TREE, GIT_INDEX_FILE, GIT_CONFIG_*, …) and the global/system config-file neutralisers appended.

Assign it to cmd.Env for each git command. It is safe to call once per test or once per git call — the HOME/XDG pin happens only on the first call within a test (see isolatedSentinel). A caller that needs a commit identity appends its own GIT_AUTHOR_*/GIT_COMMITTER_* (or sets git config) on top of the result; Env deliberately does NOT pin an identity, so config-based identity tests keep resolving the repo's own user.name/user.email.

If the test has ALREADY pointed HOME at a temp dir it owns (the common case for tests that stand up a hermetic ~/.abcd.noindex store), Env reuses that HOME rather than replacing it — replacing it would leave the process HOME and the test's captured home var pointing at different directories, so a store the test wrote under its own HOME would be invisible to the in-process production code under test. Env only mints a fresh temp HOME when HOME still points outside the test temp area.

Types

type Person added in v0.7.1

type Person struct{ Name, Email string }

Person is one git author identity — the pair the redactors key on.

func SplitIdentity added in v0.7.1

func SplitIdentity(t *testing.T, repo string) (global, local Person)

SplitIdentity gives the test process a caller whose git identity differs by scope — the everyday shape of a work checkout, and the one the identity redactors must cover in full: a GLOBAL identity in a per-test HOME's .gitconfig and a REPO-LOCAL persona in repo's .git/config.

GIT_CONFIG_GLOBAL is pinned to that file and the system config to os.DevNull, so the production probe — which keeps global config in effect on purpose (gitutil.ScrubbedEnv) — resolves exactly these two people and nothing from the machine. repo is initialised when it is not a repository yet. A machine with no usable git skips the test.

type Repo

type Repo struct {
	// contains filtered or unexported fields
}

Repo is a hermetic throwaway git repository for tests that must exercise real git objects.

It exists because three packages needed the same fixture. The release derivation, the surface guardrail, and the ship verb all read their inputs out of git trees (tags, blobs, set-differences), so a stubbed git would prove nothing about the behaviour under test — each one has to build an actual history. internal/core/changelog and internal/surface/cli each grew a private copy of this helper; this is the promotion those copies asked for, so a fourth caller extends one implementation instead of writing a fourth.

Every command runs under Env(t): the ambient GIT_DIR/GIT_WORK_TREE and the developer's global config are stripped, so a test can never be redirected onto the real repository.

func NewRepo

func NewRepo(t *testing.T) *Repo

NewRepo initialises an empty repository on a fixed branch name under a per-test temp directory. A machine with no usable git skips the test rather than failing it: the fixture's subject is abcd's behaviour, not git's presence.

func (*Repo) Commit

func (r *Repo) Commit(msg string)

Commit stages everything and records a commit. Empty commits are allowed so a fixture can advance history without touching a file.

func (*Repo) Env

func (r *Repo) Env() []string

Env is the isolated environment the fixture's git commands run under, for a caller that must spawn git itself.

func (*Repo) Git

func (r *Repo) Git(args ...string) string

Git runs one git command in the fixture and returns its trimmed output, failing the test on a non-zero exit. The identity is pinned per command rather than written into the repo's config, so a test that inspects the config sees only what it put there.

func (*Repo) Record

func (r *Repo) Record(rel, id, impact string)

Record writes a minimal record file carrying the given impact frontmatter — the shape the release derivation reads.

func (*Repo) Remove

func (r *Repo) Remove(rel string)

Remove deletes a repo-relative file from the working tree.

func (*Repo) Root

func (r *Repo) Root() string

Root is the repository's absolute path — what the code under test is handed.

func (*Repo) Write

func (r *Repo) Write(rel, content string)

Write creates (or overwrites) a repo-relative file, creating parents. The path is slash-separated so tests read the same on every platform.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL