cerrado @ 64d9bcc4e567a0f816a0388bf740baa4c01d2323

  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 (
 34	ErrRepositoryNotFound = errors.New("Repository not found")
 35)
 36
 37// TODO: make it configurable
 38const timeFormat = "2006.01.02 15:04:05"
 39
 40func NewGitService(configRepo configurationRepository) *GitService {
 41	return &GitService{
 42		configRepo: configRepo,
 43	}
 44}
 45
 46func (g *GitService) ListRepositories() ([]*Repository, error) {
 47	rs := g.configRepo.List()
 48
 49	repos := make([]*Repository, 0, len(rs))
 50	for _, r := range rs {
 51		repo, err := git.OpenRepository(r.Path)
 52		if err != nil {
 53			return nil, err
 54		}
 55
 56		obj, err := repo.LastCommit()
 57		if err != nil {
 58			slog.Error("Error fetching last commit", "repository", r.Path, "error", err)
 59			continue
 60		}
 61
 62		head, err := repo.Head()
 63		if err != nil {
 64			slog.Error("Error fetching head", "repository", r.Path, "error", err)
 65			continue
 66		}
 67
 68		repos = append(repos, &Repository{
 69			Name:           r.Name,
 70			Description:    r.Description,
 71			LastCommitDate: obj.Author.When.Format(timeFormat),
 72			Ref:            head.Name().Short(),
 73		})
 74	}
 75
 76	return repos, nil
 77}
 78
 79func (g *GitService) ListCommits(name, ref string, count int) ([]*object.Commit, error) {
 80	r := g.configRepo.GetByName(name)
 81	if r == nil {
 82		return nil, ErrRepositoryNotFound
 83	}
 84
 85	repo, err := git.OpenRepository(r.Path)
 86	if err != nil {
 87		return nil, err
 88	}
 89
 90	err = repo.SetRef(ref)
 91	if err != nil {
 92		return nil, err
 93	}
 94	return repo.Commits(count)
 95}
 96
 97func (g *GitService) LastCommit(name, ref string) (*object.Commit, error) {
 98	r := g.configRepo.GetByName(name)
 99	if r == nil {
100		return nil, ErrRepositoryNotFound
101	}
102
103	repo, err := git.OpenRepository(r.Path)
104	if err != nil {
105		return nil, err
106	}
107
108	err = repo.SetRef(ref)
109	if err != nil {
110		return nil, err
111	}
112
113	return repo.LastCommit()
114}
115
116func (g *GitService) WriteTarGZip(w io.Writer, name, ref string, prefix string) error {
117	r := g.configRepo.GetByName(name)
118	if r == nil {
119		return ErrRepositoryNotFound
120	}
121
122	repo, err := git.OpenRepository(r.Path)
123	if err != nil {
124		return err
125	}
126
127	err = repo.SetRef(ref)
128	if err != nil {
129		return err
130	}
131
132	gw := gzip.NewWriter(w)
133	defer gw.Close()
134
135	err = repo.WriteTar(gw, prefix)
136	if err != nil {
137		return err
138	}
139
140	return nil
141}
142
143func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
144	r := g.configRepo.GetByName(name)
145	if r == nil {
146		return nil, ErrRepositoryNotFound
147	}
148
149	repo, err := git.OpenRepository(r.Path)
150	if err != nil {
151		return nil, err
152	}
153	err = repo.SetRef(ref)
154	if err != nil {
155		return nil, err
156	}
157
158	return repo.Tree(path)
159}
160
161func (g *GitService) IsBinary(name, ref, path string) (bool, error) {
162	r := g.configRepo.GetByName(name)
163	if r == nil {
164		return false, ErrRepositoryNotFound
165	}
166
167	repo, err := git.OpenRepository(r.Path)
168	if err != nil {
169		return false, err
170	}
171	err = repo.SetRef(ref)
172	if err != nil {
173		return false, err
174	}
175
176	return repo.IsBinary(path)
177}
178
179func (g *GitService) GetFileContent(name, ref, path string) ([]byte, error) {
180	r := g.configRepo.GetByName(name)
181	if r == nil {
182		return nil, ErrRepositoryNotFound
183	}
184
185	repo, err := git.OpenRepository(r.Path)
186	if err != nil {
187		return nil, err
188	}
189	err = repo.SetRef(ref)
190	if err != nil {
191		return nil, err
192	}
193
194	return repo.FileContent(path)
195}
196
197func (g *GitService) GetAbout(name string) ([]byte, error) {
198	r := g.configRepo.GetByName(name)
199	if r == nil {
200		return nil, ErrRepositoryNotFound
201	}
202
203	repo, err := git.OpenRepository(r.Path)
204	if err != nil {
205		return nil, err
206	}
207	err = repo.SetRef("")
208	if err != nil {
209		return nil, err
210	}
211
212	file, err := repo.FileContent(r.About)
213	if err != nil {
214		return nil, err
215	}
216
217	return file, nil
218}
219
220func (g *GitService) ListTags(name string) ([]*git.TagReference, error) {
221	r := g.configRepo.GetByName(name)
222	if r == nil {
223		return nil, ErrRepositoryNotFound
224	}
225
226	repo, err := git.OpenRepository(r.Path)
227	if err != nil {
228		return nil, err
229	}
230	return repo.Tags()
231}
232
233func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) {
234	r := g.configRepo.GetByName(name)
235	if r == nil {
236		return nil, ErrRepositoryNotFound
237	}
238
239	repo, err := git.OpenRepository(r.Path)
240	if err != nil {
241		return nil, err
242	}
243	return repo.Branches()
244}
245
246func (g *GitService) GetHead(name string) (*plumbing.Reference, error) {
247	r := g.configRepo.GetByName(name)
248	if r == nil {
249		return nil, ErrRepositoryNotFound
250	}
251
252	repo, err := git.OpenRepository(r.Path)
253	if err != nil {
254		return nil, err
255	}
256
257	return repo.Head()
258}