git

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: May 4, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package git is the I/O seam between monorel's planning logic and an underlying git repository.

Higher layers (planner, release applier, action orchestrator) take a Repo and never shell out themselves. The default implementation in this package shells out to the `git` CLI; tests use Fake.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Exec

type Exec struct {
	// Dir is the working directory git commands run in. Required.
	Dir string

	// Env is the environment passed to git invocations. Empty means
	// inherit os.Environ; tests override this to set GIT_AUTHOR_*
	// for deterministic commit metadata.
	Env []string
}

Exec is a Repo backed by shell-outs to the `git` CLI in a specific working directory.

Construct via Open; the zero value is not usable (Dir must be set).

func Open

func Open(dir string) *Exec

Open returns an Exec rooted at dir. The directory is not validated here; the first git invocation surfaces the error if dir is not inside a git repo.

func (*Exec) Add

func (e *Exec) Add(paths ...string) error

Add implements [Repo.Add].

func (*Exec) CheckoutBranch

func (e *Exec) CheckoutBranch(branch string) error

CheckoutBranch implements [Repo.CheckoutBranch].

func (*Exec) CheckoutNewBranch added in v0.15.0

func (e *Exec) CheckoutNewBranch(branch, startPoint string) error

CheckoutNewBranch implements [Repo.CheckoutNewBranch].

func (*Exec) Commit

func (e *Exec) Commit(message string) error

Commit implements [Repo.Commit].

func (*Exec) CreateTag

func (e *Exec) CreateTag(name, message string) error

CreateTag implements [Repo.CreateTag].

func (*Exec) CurrentSHA

func (e *Exec) CurrentSHA() (string, error)

CurrentSHA implements [Repo.CurrentSHA].

func (*Exec) DeletedFilesInCommitsMatching added in v0.8.0

func (e *Exec) DeletedFilesInCommitsMatching(messageGrep string) ([]string, error)

DeletedFilesInCommitsMatching implements [Repo.DeletedFilesInCommitsMatching].

Shells out to `git log --diff-filter=D --name-only --format= --fixed-strings --grep=<messageGrep>`, then dedupes/sorts the result. --fixed-strings makes the grep a literal substring match; --format= suppresses the commit header so stdout is just deleted paths.

func (*Exec) Fetch added in v0.15.0

func (e *Exec) Fetch(remote, ref string) error

Fetch implements [Repo.Fetch].

func (*Exec) HeadCommitMessage added in v0.4.0

func (e *Exec) HeadCommitMessage() (string, error)

HeadCommitMessage implements [Repo.HeadCommitMessage].

func (*Exec) IsClean

func (e *Exec) IsClean() (bool, error)

IsClean implements [Repo.IsClean].

func (*Exec) ListTags

func (e *Exec) ListTags(prefix string) ([]string, error)

ListTags implements [Repo.ListTags].

func (*Exec) Push

func (e *Exec) Push(remote, ref string, force bool) error

Push implements [Repo.Push].

func (*Exec) PushTags

func (e *Exec) PushTags(remote string) error

PushTags implements [Repo.PushTags].

func (*Exec) Remove

func (e *Exec) Remove(paths ...string) error

Remove implements [Repo.Remove].

func (*Exec) TagsAtHead

func (e *Exec) TagsAtHead() ([]string, error)

TagsAtHead implements [Repo.TagsAtHead].

type Fake

type Fake struct {

	// Tags is the current set of tags. Order is irrelevant; ListTags
	// sorts on output for deterministic comparisons.
	Tags []string

	// Branch tracks the currently-checked-out branch name.
	Branch string

	// HeadSHA is what CurrentSHA returns. Tests may set this to
	// anything; the default (empty) yields a deterministic placeholder.
	HeadSHA string

	// Staged is the set of paths Add has been called with since the
	// last Commit. Each Commit appends a snapshot to Commits and
	// clears Staged.
	Staged []string

	// Removed records every Remove(paths...) call's paths.
	Removed []string

	// Commits is one entry per Commit() call: {Message, Files}.
	Commits []FakeCommit

	// Pushes records every Push call as "<remote>:<ref>[:force]".
	Pushes []string

	// PushedTags records every PushTags(remote) call.
	PushedTags []string

	// Dirty toggles IsClean's return value. By default the fake
	// reports clean; set Dirty=true to make IsClean return false.
	Dirty bool

	// FailNext, when non-nil, is returned by the next operation
	// regardless of which one. Single-shot: cleared after firing.
	// Used to test error-handling paths in higher layers.
	FailNext error

	// Dir, when non-empty, is the repository root. When set,
	// [Fake.Remove] also physically deletes the named paths from disk
	// (mirroring `git rm -f`). Tests that verify working-tree state
	// after Remove should set Dir; tests that only inspect Removed
	// can leave it empty.
	Dir string
	// contains filtered or unexported fields
}

Fake is an in-memory Repo for unit tests of higher layers.

Operations record into the corresponding fields so tests can assert on them; it doesn't simulate every git invariant. Specifically:

  • Add/Remove just track which paths have been touched; there's no actual working tree.
  • Commit appends to Commits with the staged paths cleared.
  • CreateTag fails on duplicate names (matches git behavior).

Construct with NewFake; the zero value is usable but tests usually want to seed initial tags via NewFake's argument.

func NewFake

func NewFake(initialTags ...string) *Fake

NewFake returns an empty in-memory repo with the given initial tags. nil is fine for "no tags yet."

func (*Fake) Add

func (f *Fake) Add(paths ...string) error

Add implements [Repo.Add]. Records the paths in Staged.

func (*Fake) CheckoutBranch

func (f *Fake) CheckoutBranch(branch string) error

CheckoutBranch implements [Repo.CheckoutBranch].

func (*Fake) CheckoutNewBranch added in v0.15.0

func (f *Fake) CheckoutNewBranch(branch, startPoint string) error

CheckoutNewBranch implements [Repo.CheckoutNewBranch]. The fake records the new branch as the current branch; startPoint is observed but not simulated.

func (*Fake) Commit

func (f *Fake) Commit(message string) error

Commit implements [Repo.Commit]. Appends a FakeCommit with the staged paths and clears Staged.

func (*Fake) CreateTag

func (f *Fake) CreateTag(name, _ string) error

CreateTag implements [Repo.CreateTag]. Errors on duplicate.

func (*Fake) CurrentSHA

func (f *Fake) CurrentSHA() (string, error)

CurrentSHA implements [Repo.CurrentSHA].

func (*Fake) DeletedFilesInCommitsMatching added in v0.8.0

func (f *Fake) DeletedFilesInCommitsMatching(messageGrep string) ([]string, error)

DeletedFilesInCommitsMatching implements [Repo.DeletedFilesInCommitsMatching]. Walks the recorded Commits, collecting Deletions from any commit whose Message contains messageGrep as a literal substring.

func (*Fake) Fetch added in v0.15.0

func (f *Fake) Fetch(remote, ref string) error

Fetch implements [Repo.Fetch]. The fake runs the FailNext hook; it does not simulate any state change.

func (*Fake) HeadCommitMessage added in v0.4.0

func (f *Fake) HeadCommitMessage() (string, error)

HeadCommitMessage implements [Repo.HeadCommitMessage]. Returns the Message of the last FakeCommit in Commits, or "" when no commits have been recorded.

func (*Fake) IsClean

func (f *Fake) IsClean() (bool, error)

IsClean implements [Repo.IsClean].

func (*Fake) ListTags

func (f *Fake) ListTags(prefix string) ([]string, error)

ListTags implements [Repo.ListTags].

func (*Fake) Push

func (f *Fake) Push(remote, ref string, force bool) error

Push implements [Repo.Push]. Records a "remote:ref[:force]" entry.

func (*Fake) PushTags

func (f *Fake) PushTags(remote string) error

PushTags implements [Repo.PushTags].

func (*Fake) Remove

func (f *Fake) Remove(paths ...string) error

Remove implements [Repo.Remove]. Records the paths in Removed. When [Fake.Dir] is set, also physically removes each path from the working tree (mirroring `git rm -f`). Missing files are silently skipped.

func (*Fake) TagsAtHead

func (f *Fake) TagsAtHead() ([]string, error)

TagsAtHead implements [Repo.TagsAtHead]. The fake doesn't track per-tag SHAs; it returns every tag created via CreateTag since the last call to clear (which the fake doesn't have). Tests that need fine-grained "tags pointing at this specific commit" should override this with a custom impl.

type FakeCommit

type FakeCommit struct {
	Message string
	Files   []string

	// Deletions are the paths Remove(...) recorded for this commit.
	// Subset of Files. Tracked separately so
	// DeletedFilesInCommitsMatching can answer accurately without
	// the fake needing to know each path's add-vs-delete state.
	Deletions []string
}

FakeCommit is one recorded commit on a Fake.

type Repo

type Repo interface {
	// ListTags returns every tag whose name starts with prefix. An
	// empty prefix returns all tags. Order is unspecified; callers
	// that need semver order sort with semver.Compare.
	ListTags(prefix string) ([]string, error)

	// TagsAtHead returns every tag pointing at the current HEAD
	// commit (i.e. `git tag --points-at HEAD`). Used by `monorel
	// publish` to find which tags to create provider Releases for.
	// Order is unspecified.
	TagsAtHead() ([]string, error)

	// CurrentSHA returns the SHA at HEAD.
	CurrentSHA() (string, error)

	// HeadCommitMessage returns the full commit message of HEAD
	// (subject + body, including any trailers). Used by `monorel tag`
	// to read the trailers `monorel apply` writes for downstream
	// tag creation.
	HeadCommitMessage() (string, error)

	// Add stages the named paths. No-op when paths is empty.
	Add(paths ...string) error

	// Remove unstages and deletes the named paths from the working
	// tree (i.e. `git rm`). Used to consume changeset files at
	// release time.
	Remove(paths ...string) error

	// Commit creates a commit with the given message at HEAD.
	// Returns an error if there is nothing staged.
	Commit(message string) error

	// CreateTag creates an annotated tag at HEAD. message is the
	// tag annotation; pass an empty string for a lightweight tag.
	CreateTag(name, message string) error

	// Push pushes ref to remote (e.g. Push("origin", "main") or
	// Push("origin", "monorel/release"). force=true uses --force-
	// with-lease so a stale local view doesn't clobber an upstream
	// update we don't know about.
	Push(remote, ref string, force bool) error

	// PushTags pushes every local tag to remote. monorel pushes
	// tags after the release commit lands so the order in the
	// remote's reflog is "commit, then its tags."
	PushTags(remote string) error

	// Fetch updates remote-tracking refs for ref from remote
	// (`git fetch --no-tags <remote> <ref>`). Used by the auto
	// orchestrator to refresh origin/<base-branch> before creating
	// monorel/release from it. Empty ref fetches every ref the
	// remote advertises.
	//
	// Tags are not auto-fetched (--no-tags); the auto orchestrator
	// only needs the refs that affect the release branch's plan.
	// Call ListTags or a separate fetch if you need them.
	Fetch(remote, ref string) error

	// CheckoutBranch checks out branch, creating it from the
	// current HEAD if it doesn't exist (`git checkout -B`). For
	// creating a branch from a non-HEAD start point (e.g. a remote
	// tracking ref), use [Repo.CheckoutNewBranch].
	CheckoutBranch(branch string) error

	// CheckoutNewBranch creates branch at startPoint and checks it
	// out (`git checkout -B <branch> <startPoint>`). Used by the
	// auto orchestrator to create monorel/release from the freshly
	// fetched origin/<base>.
	CheckoutNewBranch(branch, startPoint string) error

	// IsClean reports whether the working tree has no uncommitted
	// or untracked changes (i.e. `git status --porcelain` is empty).
	// Pre-release safety check: monorel refuses to run release on
	// a dirty tree.
	IsClean() (bool, error)

	// DeletedFilesInCommitsMatching returns the union of every file
	// path deleted (`--diff-filter=D`) by a commit whose subject or
	// body literally contains messageGrep. The substring match is
	// case-sensitive and does NOT use regex.
	//
	// Used by `monorel doctor` to scan past `chore(release):`
	// commits for the changeset filenames they consumed, so a
	// stale-branch + squash-merge revival can be detected.
	//
	// Order: deduplicated, sorted lexicographically. Includes paths
	// that were re-added by later commits — callers intersect
	// against the live tree to flag that case.
	DeletedFilesInCommitsMatching(messageGrep string) ([]string, error)
}

Repo is the slice of git operations monorel needs. Methods are intentionally narrow: monorel does not implement git itself, just the handful of commands a release flow performs.

Implementations:

  • Exec (default) — shells out to the `git` CLI in a working directory. The CLI is already on every CI runner and dev box; we don't pull in go-git's 50k-LOC partial reimplementation just for these few commands.
  • Fake (in-memory) — for unit tests of higher layers.

All methods return wrapped errors that include the underlying git stderr output when shelling out fails.

Directories

Path Synopsis
Package testutil creates real on-disk git repositories for integration tests of monorel's higher layers.
Package testutil creates real on-disk git repositories for integration tests of monorel's higher layers.

Jump to

Keyboard shortcuts

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