main.go (view raw)
1package main
2
3import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "log"
8 "net/http"
9 "os"
10 "os/exec"
11 "path/filepath"
12
13 "github.com/joho/godotenv"
14)
15
16type Repo struct {
17 Name string `json:"name"`
18 HTMLUrl string `json:"html_url"`
19 Description string `json:"description"`
20}
21
22func getRepos(username, token string) ([]Repo, error) {
23 var allRepos []Repo
24 page := 1
25
26 for {
27 url := fmt.Sprintf("https://api.github.com/users/%s/repos?page=%d&per_page=100", username, page)
28 req, err := http.NewRequest("GET", url, nil)
29 if err != nil {
30 return nil, err
31 }
32 req.SetBasicAuth(username, token)
33
34 client := &http.Client{}
35 resp, err := client.Do(req)
36 if err != nil {
37 return nil, err
38 }
39 defer resp.Body.Close()
40
41 if resp.StatusCode != http.StatusOK {
42 return nil, fmt.Errorf("failed to fetch repositories: %s", resp.Status)
43 }
44
45 body, err := io.ReadAll(resp.Body)
46 if err != nil {
47 return nil, err
48 }
49
50 var repos []Repo
51 if err := json.Unmarshal(body, &repos); err != nil {
52 return nil, err
53 }
54
55 if len(repos) == 0 {
56 break
57 }
58
59 allRepos = append(allRepos, repos...)
60 page++
61 }
62
63 return allRepos, nil
64}
65
66func runGitCommand(args ...string) error {
67 cmd := exec.Command("git", args...)
68 cmd.Stdout = os.Stdout
69 cmd.Stderr = os.Stderr
70 return cmd.Run()
71}
72
73func writeDescription(repoPath, description string) error {
74 descriptionPath := filepath.Join(repoPath, "description")
75 return os.WriteFile(descriptionPath, []byte(description), 0644)
76}
77
78func syncRepo(repo Repo, targetDir string) error {
79 repoPath := filepath.Join(targetDir, repo.Name+".git")
80 if _, err := os.Stat(repoPath); os.IsNotExist(err) {
81 fmt.Printf("Cloning repository %s as bare...\n", repo.Name)
82 if err := runGitCommand("clone", "--bare", repo.HTMLUrl, repoPath); err != nil {
83 return err
84 }
85 } else {
86 fmt.Printf("Fetching updates for bare repository %s...\n", repo.Name)
87 cmd := exec.Command("git", "--git-dir", repoPath, "fetch", "--all")
88 cmd.Stdout = os.Stdout
89 cmd.Stderr = os.Stderr
90 if err := cmd.Run(); err != nil {
91 return err
92 }
93 }
94
95 // Write the repository description
96 if err := writeDescription(repoPath, repo.Description); err != nil {
97 return fmt.Errorf("failed to write description for %s: %v", repo.Name, err)
98 }
99
100 return nil
101}
102
103func main() {
104 err := godotenv.Load()
105 if err != nil {
106 println("Failed to load .env file: %v\n", err)
107 }
108
109 ghUser := os.Getenv("GITHUB_USERNAME")
110 ghToken := os.Getenv("GITHUB_TOKEN")
111 repoDir := os.Getenv("REPO_DIR")
112
113 if ghUser == "" || ghToken == "" || repoDir == "" {
114 log.Fatalf("GitHub username and token must be provided\n")
115 }
116
117 repos, err := getRepos(ghUser, ghToken)
118 if err != nil {
119 log.Fatalf("Failed to fetch repositories: %v\n", err)
120 }
121
122 for _, repo := range repos {
123 if err := syncRepo(repo, repoDir); err != nil {
124 log.Printf("Failed to sync repository %s: %v\n", repo.Name, err)
125 }
126 }
127}