package git import ( "bytes" "fmt" "os" "os/exec" "strings" "time" ) // Service defines the interface for git operations type Service interface { CheckConnection(url string) error FetchContents(url string) error GetModifications(days int) (map[string]string, error) } type gitService struct { repoDir string } // NewGitService creates a new Git service func NewGitService() Service { return &gitService{ repoDir: "./cloned_repo", } } func (s *gitService) CheckConnection(url string) error { cmd := exec.Command("git", "ls-remote", url) if err := cmd.Run(); err != nil { return fmt.Errorf("failed to check git connection: %w", err) } return nil } func (s *gitService) FetchContents(url string) error { // Remove the repo directory if it already exists from a previous run _ = os.RemoveAll(s.repoDir) cmd := exec.Command("git", "clone", url, s.repoDir) var stderr bytes.Buffer cmd.Stderr = &stderr if err := cmd.Run(); err != nil { return fmt.Errorf("failed to fetch contents: %w, stderr: %s", err, stderr.String()) } return nil } func (s *gitService) GetModifications(days int) (map[string]string, error) { mods := make(map[string]string) // Determine the commit to diff against (the latest commit *before* 'days' ago) since := time.Now().AddDate(0, 0, -days).Format(time.RFC3339) cmdBase := exec.Command("git", "rev-list", "-1", "--before", since, "HEAD") cmdBase.Dir = s.repoDir out, err := cmdBase.Output() baseCommit := strings.TrimSpace(string(out)) if err != nil || baseCommit == "" { // If there is no commit before 'days' ago, diff against the empty tree // (this gets all files created in the repository's entire history if it's newer than 'days') baseCommit = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" } // Get the list of modified files between the base commit and HEAD cmdFiles := exec.Command("git", "diff", "--name-only", baseCommit, "HEAD") cmdFiles.Dir = s.repoDir filesOut, err := cmdFiles.Output() if err != nil { return nil, fmt.Errorf("failed to get modified files: %w", err) } files := strings.Split(strings.TrimSpace(string(filesOut)), "\n") for _, file := range files { if file == "" { continue } // Filter only .md files if !strings.HasSuffix(file, ".md") { continue } // Remove first folder from file path file = strings.Join(strings.Split(file, "/")[1:], "/") // Get the specific diff for this file cmdDiff := exec.Command("git", "diff", baseCommit, "HEAD", "--", file) cmdDiff.Dir = s.repoDir diffOut, err := cmdDiff.Output() if err != nil { return nil, fmt.Errorf("failed to get diff for file %s: %w", file, err) } mods[file] = string(diffOut) } return mods, nil }