package gitengine import ( "errors" "os/exec" "strings" ) var ErrInvalidGitInput = errors.New("invalid git input") type CommandRunner interface { Run(workdir string, args ...string) (string, error) } type CLI struct{} func (CLI) Run(workdir string, args ...string) (string, error) { if len(args) == 0 { return "", ErrInvalidGitInput } cmd := exec.Command("git", args...) if strings.TrimSpace(workdir) != "" { cmd.Dir = workdir } out, err := cmd.CombinedOutput() return string(out), err } type StatusResult struct { Clean bool Output string } func Status(runner CommandRunner, workdir string) (StatusResult, error) { output, err := runner.Run(workdir, "status", "--porcelain") if err != nil { return StatusResult{}, err } return StatusResult{ Clean: strings.TrimSpace(output) == "", Output: output, }, nil } func ChangedFiles(runner CommandRunner, workdir, before, after string) ([]string, error) { before = strings.TrimSpace(before) after = strings.TrimSpace(after) if before == "" || after == "" { return nil, ErrInvalidGitInput } output, err := runner.Run(workdir, "diff", "--name-only", before+".."+after) if err != nil { return nil, err } lines := strings.Split(output, "\n") files := make([]string, 0, len(lines)) for _, line := range lines { line = strings.TrimSpace(line) if line != "" { files = append(files, line) } } return files, nil }