cerrado @ 2fb43cc1271572d26298da70f823814cae87a3a0

  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) Diff(name, ref string) (string, error) {
144	r := g.configRepo.GetByName(name)
145	if r == nil {
146		return "", ErrRepositoryNotFound
147	}
148
149	repo, err := git.OpenRepository(r.Path)
150	if err != nil {
151		return "", err
152	}
153
154	err = repo.SetRef(ref)
155	if err != nil {
156		return "", err
157	}
158
159	return repo.Diff()
160}
161
162func (g *GitService) GetTree(name, ref, path string) (*object.Tree, error) {
163	r := g.configRepo.GetByName(name)
164	if r == nil {
165		return nil, ErrRepositoryNotFound
166	}
167
168	repo, err := git.OpenRepository(r.Path)
169	if err != nil {
170		return nil, err
171	}
172	err = repo.SetRef(ref)
173	if err != nil {
174		return nil, err
175	}
176
177	return repo.Tree(path)
178}
179
180func (g *GitService) IsBinary(name, ref, path string) (bool, error) {
181	r := g.configRepo.GetByName(name)
182	if r == nil {
183		return false, ErrRepositoryNotFound
184	}
185
186	repo, err := git.OpenRepository(r.Path)
187	if err != nil {
188		return false, err
189	}
190	err = repo.SetRef(ref)
191	if err != nil {
192		return false, err
193	}
194
195	return repo.IsBinary(path)
196}
197
198func (g *GitService) GetFileContent(name, ref, path string) ([]byte, error) {
199	r := g.configRepo.GetByName(name)
200	if r == nil {
201		return nil, ErrRepositoryNotFound
202	}
203
204	repo, err := git.OpenRepository(r.Path)
205	if err != nil {
206		return nil, err
207	}
208	err = repo.SetRef(ref)
209	if err != nil {
210		return nil, err
211	}
212
213	return repo.FileContent(path)
214}
215
216func (g *GitService) GetAbout(name string) ([]byte, error) {
217	r := g.configRepo.GetByName(name)
218	if r == nil {
219		return nil, ErrRepositoryNotFound
220	}
221
222	repo, err := git.OpenRepository(r.Path)
223	if err != nil {
224		return nil, err
225	}
226	err = repo.SetRef("")
227	if err != nil {
228		return nil, err
229	}
230
231	file, err := repo.FileContent(r.About)
232	if err != nil {
233		return nil, err
234	}
235
236	return file, nil
237}
238
239func (g *GitService) ListTags(name string) ([]*git.TagReference, error) {
240	r := g.configRepo.GetByName(name)
241	if r == nil {
242		return nil, ErrRepositoryNotFound
243	}
244
245	repo, err := git.OpenRepository(r.Path)
246	if err != nil {
247		return nil, err
248	}
249	return repo.Tags()
250}
251
252func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) {
253	r := g.configRepo.GetByName(name)
254	if r == nil {
255		return nil, ErrRepositoryNotFound
256	}
257
258	repo, err := git.OpenRepository(r.Path)
259	if err != nil {
260		return nil, err
261	}
262	return repo.Branches()
263}
264
265func (g *GitService) GetHead(name string) (*plumbing.Reference, error) {
266	r := g.configRepo.GetByName(name)
267	if r == nil {
268		return nil, ErrRepositoryNotFound
269	}
270
271	repo, err := git.OpenRepository(r.Path)
272	if err != nil {
273		return nil, err
274	}
275
276	return repo.Head()
277}