ci/internal/git/repo.go (46 lines of code) (raw):
package git
import (
"bufio"
"bytes"
"context"
"fmt"
"os/exec"
"path/filepath"
)
// Repository represents a local Git repository.
type Repository struct {
dir string
}
// NewRepository creates a new repository for the given directory path.
func NewRepository(dir string) (*Repository, error) {
abs, err := filepath.Abs(dir)
if err != nil {
return nil, fmt.Errorf("getting absolute directory path: %w", err)
}
return &Repository{dir: abs}, nil
}
func (r *Repository) Dir() string {
return r.dir
}
// ModifiedFiles return a slice of filenames that were modified since the given commit.
func (r *Repository) ModifiedFiles(ctx context.Context, commit string) ([]string, error) {
return r.diffNameOnly(ctx, "M", commit)
}
func (r *Repository) diffNameOnly(ctx context.Context, filter, commit string) ([]string, error) {
var files []string
out, err := r.execGit(ctx, "diff", "--name-only", "--diff-filter="+filter, commit, "HEAD")
if err != nil {
return files, fmt.Errorf("running git diff command: %w (output: %s)", err, bytes.TrimSpace(out))
}
scanner := bufio.NewScanner(bytes.NewReader(out))
for scanner.Scan() {
line := string(bytes.TrimSpace(scanner.Bytes()))
if line == "" {
continue
}
files = append(files, filepath.Join(r.dir, line))
}
return files, nil
}
func (r *Repository) execGit(ctx context.Context, arg ...string) ([]byte, error) {
cmd := exec.CommandContext(ctx, "git", arg...)
cmd.Dir = r.dir
return cmd.CombinedOutput()
}