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) ([]*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()
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) ListTags(name string) ([]*object.Tag, error) {
132 r := g.configRepo.GetByName(name)
133 if r == nil {
134 return nil, RepositoryNotFoundErr
135 }
136
137 repo, err := git.OpenRepository(r.Path)
138 if err != nil {
139 return nil, err
140 }
141 return repo.Tags()
142}
143
144func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, 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.Branches()
155}
156
157func (g *GitService) GetHead(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
168 return repo.Head()
169}