1package service
2
3import (
4 "errors"
5 "log/slog"
6 "os"
7 "path"
8
9 "git.gabrielgio.me/cerrado/pkg/config"
10 "git.gabrielgio.me/cerrado/pkg/git"
11 "git.gabrielgio.me/cerrado/pkg/u"
12 "github.com/go-git/go-git/v5/plumbing"
13 "github.com/go-git/go-git/v5/plumbing/object"
14)
15
16type (
17 Repository struct {
18 Name string
19 Description string
20 LastCommitDate string
21 Ref string
22 }
23
24 GitService struct {
25 configRepo configurationRepository
26 }
27
28 configurationRepository interface {
29 List() []*config.GitRepositoryConfiguration
30 GetByName(name string) *config.GitRepositoryConfiguration
31 }
32)
33
34var (
35 RepositoryNotFoundErr = errors.New("Repository not found")
36)
37
38// TODO: make it configurable
39const timeFormat = "2006.01.02 15:04:05"
40
41func NewGitService(configRepo configurationRepository) *GitService {
42 return &GitService{
43 configRepo: configRepo,
44 }
45}
46
47func (g *GitService) ListRepositories() ([]*Repository, error) {
48 rs := g.configRepo.List()
49
50 repos := make([]*Repository, 0, len(rs))
51 for _, r := range rs {
52 repo, err := git.OpenRepository(r.Path)
53 if err != nil {
54 return nil, err
55 }
56
57 obj, err := repo.LastCommit()
58 if err != nil {
59 slog.Error("Error fetching last commit", "repository", r.Path, "error", err)
60 continue
61 }
62
63 head, err := repo.Head()
64 if err != nil {
65 slog.Error("Error fetching head", "repository", r.Path, "error", err)
66 continue
67 }
68
69 d := path.Join(r.Path, "description")
70 description := ""
71 if u.FileExist(d) {
72 if b, err := os.ReadFile(d); err == nil {
73 description = string(b)
74 } else {
75 slog.Error("Error loading description file", "err", err)
76 }
77 }
78
79 repos = append(repos, &Repository{
80 Name: r.Name,
81 Description: description,
82 LastCommitDate: obj.Author.When.Format(timeFormat),
83 Ref: head.Name().Short(),
84 })
85 }
86
87 return repos, nil
88}
89
90func (g *GitService) ListCommits(name, ref string) ([]*object.Commit, error) {
91 r := g.configRepo.GetByName(name)
92 if r == nil {
93 return nil, RepositoryNotFoundErr
94 }
95
96 repo, err := git.OpenRepository(r.Path)
97 if err != nil {
98 return nil, err
99 }
100
101 err = repo.SetRef(ref)
102 if err != nil {
103 return nil, err
104 }
105 return repo.Commits()
106}
107
108func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
109 r := g.configRepo.GetByName(name)
110 if r == nil {
111 return nil, RepositoryNotFoundErr
112 }
113
114 repo, err := git.OpenRepository(r.Path)
115 if err != nil {
116 return nil, err
117 }
118 err = repo.SetRef(ref)
119 if err != nil {
120 return nil, err
121 }
122
123 return repo.Tree(path)
124}
125
126func (g *GitService) GetFileContent(name, ref, path string) (string, error) {
127 r := g.configRepo.GetByName(name)
128 if r == nil {
129 return "", RepositoryNotFoundErr
130 }
131
132 repo, err := git.OpenRepository(r.Path)
133 if err != nil {
134 return "", err
135 }
136 err = repo.SetRef(ref)
137 if err != nil {
138 return "", err
139 }
140
141 return repo.FileContent(path)
142}
143
144func (g *GitService) ListTags(name string) ([]*object.Tag, error) {
145 r := g.configRepo.GetByName(name)
146 if r == nil {
147 return nil, RepositoryNotFoundErr
148 }
149
150 repo, err := git.OpenRepository(r.Path)
151 if err != nil {
152 return nil, err
153 }
154 return repo.Tags()
155}
156
157func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) {
158 r := g.configRepo.GetByName(name)
159 if r == nil {
160 return nil, RepositoryNotFoundErr
161 }
162
163 repo, err := git.OpenRepository(r.Path)
164 if err != nil {
165 return nil, err
166 }
167 return repo.Branches()
168}
169
170func (g *GitService) GetHead(name string) (*plumbing.Reference, error) {
171 r := g.configRepo.GetByName(name)
172 if r == nil {
173 return nil, RepositoryNotFoundErr
174 }
175
176 repo, err := git.OpenRepository(r.Path)
177 if err != nil {
178 return nil, err
179 }
180
181 return repo.Head()
182}