git

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 21, 2026 License: BSD-2-Clause Imports: 8 Imported by: 0

Documentation

Overview

Package git wraps git shell-outs behind the GitOps interface so the execution and ai_review steps can be tested with a counterfeiter mock. Implementations are responsible for assembling argv slices, capturing stderr, and wrapping errors via bborbe/errors. They MUST NOT use sh -c or any shell-interpolated form — argv only.

Auth model: HTTPS clones with a GitHub token are handled by URL transformation at the call site (cloneURL → https://x-access-token:<tok>@github.com/...). The package itself takes the transformed URL — it does not know about tokens directly.

Deliberately NO Tag method exists on this interface (design § 7.0): versioning + tagging is the github-releaser agent's job on merge. The only push helper hardcodes --no-follow-tags and pushes a single branch ref — a tag physically cannot leak from this agent.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RedactToken

func RedactToken(s string) string

RedactToken exposes the unexported redactToken helper for callers outside this package that need to log wrapped err.Error() strings through the same redaction. Behavior is identical to redactToken.

Types

type BotIdentity

type BotIdentity struct {
	Name  string
	Email string
}

BotIdentity holds the commit author/committer identity. Hardcoded intentionally: the only consumer is github-update-go-agent, and a single value is the contract (mirrors github-releaser-agent).

func DefaultBotIdentity

func DefaultBotIdentity() BotIdentity

DefaultBotIdentity returns the fleet-standard bot identity. The osExecGitOps struct reads this internally on every Commit — there is no override path. Exposed publicly for test assertions.

type ErrorCategory

type ErrorCategory string

ErrorCategory is the closed enum returned by ClassifyError. The steps branch on these values to compose actionable failure messages.

The set is CLOSED — adding a new category requires a design amendment.

const (
	// ErrorCategoryAuth — git server rejected credentials (401/403, missing username).
	ErrorCategoryAuth ErrorCategory = "auth"
	// ErrorCategoryRepoNotFound — clone target does not exist on the server (404).
	// NOTE: GitHub returns "Repository not found" for BOTH a typo'd repo URL
	// AND an unauthenticated request for a private repo. The watcher emit +
	// App-IAT auth eliminate the private-repo confounder upstream, so a 404
	// truly means the repo does not exist (mirrors github-releaser-agent).
	ErrorCategoryRepoNotFound ErrorCategory = "repo_not_found"
	// ErrorCategoryProtectedBranchRejected — branch protection rejected the push.
	ErrorCategoryProtectedBranchRejected ErrorCategory = "protected_branch_rejected"
	// ErrorCategoryPushNonFastForward — remote moved between clone and push;
	// controller retry will re-fetch.
	ErrorCategoryPushNonFastForward ErrorCategory = "push_non_fast_forward"
	// ErrorCategoryUnexpectedDiff — the update commit touched a forbidden path
	// (.github/workflows/**). Set DIRECTLY by the execution step's
	// committed-files guard, NOT by ClassifyError — it is a semantic assertion
	// on the file set, so there is no stderr fragment to match.
	ErrorCategoryUnexpectedDiff ErrorCategory = "unexpected_diff"
	// ErrorCategoryUnknown — message does not match any known fragment. Bug
	// signal: if this fires repeatedly, add a new substring to the table.
	ErrorCategoryUnknown ErrorCategory = "unknown"
)

func ClassifyError

func ClassifyError(err error) ErrorCategory

ClassifyError maps a git stderr-wrapped error to the closed enum.

Returns the empty-string sentinel `ErrorCategory("")` when err is nil — this distinguishes "no error to classify" from ErrorCategoryUnknown ("an error occurred but no fragment matched").

unexpected_diff is NEVER returned by this function — that category is set by the execution step's guard layer, not at the git-stderr layer.

type GitOps

type GitOps interface {
	// CloneAtRef shells out `git clone <cloneURL> <workdir>` (full history —
	// the ref may be an arbitrary SHA) and checks out ref. ref may be a
	// commit SHA or a branch name (branch names resolve via checkout DWIM
	// against origin). cloneURL MUST already include any auth token.
	CloneAtRef(ctx context.Context, cloneURL, ref, workdir string) error

	// SwitchNewBranch creates and switches to a new local branch
	// (git switch -c <branch>).
	SwitchNewBranch(ctx context.Context, workdir, branch string) error

	// ChangedFiles returns the repo-relative paths of all uncommitted
	// changes (staged, unstaged, and untracked) via `git status --porcelain`.
	// The execution step uses it to build the explicit commit pathspec and
	// to run the workflow-edit guard BEFORE anything is committed.
	ChangedFiles(ctx context.Context, workdir string) ([]string, error)

	// Commit stages paths (relative to workdir) via explicit `git add -- <paths>`
	// and creates a commit with the bot identity. Returns the short SHA
	// (7 chars) of the new commit. The bot identity is set per-invocation
	// via -c user.name / -c user.email — never writes to the global gitconfig.
	Commit(ctx context.Context, workdir, message string, paths ...string) (sha string, err error)

	// CommittedFiles returns the repo-relative paths changed by the HEAD
	// commit (git diff-tree --no-commit-id --name-only -r HEAD). The
	// execution step uses it as a pre-push guard.
	CommittedFiles(ctx context.Context, workdir string) ([]string, error)

	// Push pushes the current HEAD to origin as refs/heads/<branch>,
	// hardcoding --no-follow-tags so a local tag can never reach origin.
	Push(ctx context.Context, workdir, branch string) error

	// LsRemoteTags shells out `git ls-remote --tags <cloneURL>` and returns
	// all SHAs sitting at tag refs (both tag-object SHAs and dereferenced
	// ^{} commit SHAs). The ai_review step checks that no branch commit
	// carries a tag. cloneURL MUST already include any auth token.
	LsRemoteTags(ctx context.Context, cloneURL string) ([]string, error)

	// RevList returns the commit SHAs on HEAD that are not reachable from
	// base (git rev-list <base>..HEAD) — the branch's own commits.
	RevList(ctx context.Context, workdir, base string) ([]string, error)

	// ShowFile returns the content of path at the given ref
	// (git show <ref>:<path>) — e.g. origin/master:CHANGELOG.md.
	ShowFile(ctx context.Context, workdir, ref, path string) ([]byte, error)
}

GitOps is the seam between the steps and the git binary.

All methods are context-aware — callers can cancel mid-operation. workdir is the absolute path to the checkout (created and owned by the caller; the package does not manage workdir lifecycle).

func NewOSExecGitOps

func NewOSExecGitOps() GitOps

NewOSExecGitOps returns a GitOps implementation that shells out to the git binary via os/exec. Zero-arg: the bot identity is constant via DefaultBotIdentity().

Jump to

Keyboard shortcuts

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