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