cerrado @ 3784181e4fad3c947dfa95081d8a0b34f5be12d4

  1package service
  2
  3import (
  4	"compress/gzip"
  5	"errors"
  6	"io"
  7	"log/slog"
  8
  9	"git.gabrielgio.me/cerrado/pkg/config"
 10	"git.gabrielgio.me/cerrado/pkg/git"
 11	"github.com/go-git/go-git/v5/plumbing"
 12	"github.com/go-git/go-git/v5/plumbing/object"
 13)
 14
 15type (
 16	Repository struct {
 17		Name           string
 18		Description    string
 19		LastCommitDate string
 20		Ref            string
 21	}
 22
 23	GitService struct {
 24		configRepo configurationRepository
 25	}
 26
 27	configurationRepository interface {
 28		List() []*config.GitRepositoryConfiguration
 29		GetByName(name string) *config.GitRepositoryConfiguration
 30	}
 31)
 32
 33var ErrRepositoryNotFound = errors.New("Repository not found")
 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, ErrRepositoryNotFound
 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) LastCommit(name, ref string) (*object.Commit, error) {
 96	r := g.configRepo.GetByName(name)
 97	if r == nil {
 98		return nil, ErrRepositoryNotFound
 99	}
100
101	repo, err := git.OpenRepository(r.Path)
102	if err != nil {
103		return nil, err
104	}
105
106	err = repo.SetRef(ref)
107	if err != nil {
108		return nil, err
109	}
110
111	return repo.LastCommit()
112}
113
114func (g *GitService) WriteTarGZip(w io.Writer, name, ref string, prefix string) error {
115	r := g.configRepo.GetByName(name)
116	if r == nil {
117		return ErrRepositoryNotFound
118	}
119
120	repo, err := git.OpenRepository(r.Path)
121	if err != nil {
122		return err
123	}
124
125	err = repo.SetRef(ref)
126	if err != nil {
127		return err
128	}
129
130	gw := gzip.NewWriter(w)
131	defer gw.Close()
132
133	err = repo.WriteTar(gw, prefix)
134	if err != nil {
135		return err
136	}
137
138	return nil
139}
140
141func (g *GitService) Diff(name, ref string) (string, error) {
142	r := g.configRepo.GetByName(name)
143	if r == nil {
144		return "", ErrRepositoryNotFound
145	}
146
147	repo, err := git.OpenRepository(r.Path)
148	if err != nil {
149		return "", err
150	}
151
152	err = repo.SetRef(ref)
153	if err != nil {
154		return "", err
155	}
156
157	return repo.Diff()
158}
159
160func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
161	r := g.configRepo.GetByName(name)
162	if r == nil {
163		return nil, ErrRepositoryNotFound
164	}
165
166	repo, err := git.OpenRepository(r.Path)
167	if err != nil {
168		return nil, err
169	}
170	err = repo.SetRef(ref)
171	if err != nil {
172		return nil, err
173	}
174
175	return repo.Tree(path)
176}
177
178func (g *GitService) IsBinary(name, ref, path string) (bool, error) {
179	r := g.configRepo.GetByName(name)
180	if r == nil {
181		return false, ErrRepositoryNotFound
182	}
183
184	repo, err := git.OpenRepository(r.Path)
185	if err != nil {
186		return false, err
187	}
188	err = repo.SetRef(ref)
189	if err != nil {
190		return false, err
191	}
192
193	return repo.IsBinary(path)
194}
195
196func (g *GitService) GetFileContent(name, ref, path string) ([]byte, error) {
197	r := g.configRepo.GetByName(name)
198	if r == nil {
199		return nil, ErrRepositoryNotFound
200	}
201
202	repo, err := git.OpenRepository(r.Path)
203	if err != nil {
204		return nil, err
205	}
206	err = repo.SetRef(ref)
207	if err != nil {
208		return nil, err
209	}
210
211	return repo.FileContent(path)
212}
213
214func (g *GitService) GetAbout(name string) ([]byte, error) {
215	r := g.configRepo.GetByName(name)
216	if r == nil {
217		return nil, ErrRepositoryNotFound
218	}
219
220	repo, err := git.OpenRepository(r.Path)
221	if err != nil {
222		return nil, err
223	}
224	err = repo.SetRef("")
225	if err != nil {
226		return nil, err
227	}
228
229	file, err := repo.FileContent(r.About)
230	if err != nil {
231		return nil, err
232	}
233
234	return file, nil
235}
236
237func (g *GitService) ListTags(name string) ([]*git.TagReference, error) {
238	r := g.configRepo.GetByName(name)
239	if r == nil {
240		return nil, ErrRepositoryNotFound
241	}
242
243	repo, err := git.OpenRepository(r.Path)
244	if err != nil {
245		return nil, err
246	}
247	return repo.Tags()
248}
249
250func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) {
251	r := g.configRepo.GetByName(name)
252	if r == nil {
253		return nil, ErrRepositoryNotFound
254	}
255
256	repo, err := git.OpenRepository(r.Path)
257	if err != nil {
258		return nil, err
259	}
260	return repo.Branches()
261}
262
263func (g *GitService) GetHead(name string) (*plumbing.Reference, error) {
264	r := g.configRepo.GetByName(name)
265	if r == nil {
266		return nil, ErrRepositoryNotFound
267	}
268
269	repo, err := git.OpenRepository(r.Path)
270	if err != nil {
271		return nil, err
272	}
273
274	return repo.Head()
275}