From e3705f35c642e578625ce4574d189fa0b0869403 Mon Sep 17 00:00:00 2001 From: "Gabriel A. Giovanini" Date: Sat, 1 Jun 2024 19:59:43 +0200 Subject: feat: Add ref support Now log and tree can be loaded using a given reference. --- pkg/git/git.go | 82 +++++++++++++++++++++++++++++----------------- pkg/handler/git/handler.go | 33 ++++++++++++++++--- pkg/handler/router.go | 6 ++-- pkg/service/git.go | 50 +++++++++++++++++++++++++--- 4 files changed, 129 insertions(+), 42 deletions(-) (limited to 'pkg') diff --git a/pkg/git/git.go b/pkg/git/git.go index 7ef23f7..ce72465 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -13,19 +13,50 @@ import ( var () var ( - MissingHeadErr = errors.New("Head not found") + MissingRefErr = errors.New("Reference not found") ) type ( GitRepository struct { - path string + path string + repository *git.Repository + + ref plumbing.Hash + // this is setRef when ref is setRef + setRef bool } ) -func NewGitRepository(dir string) *GitRepository { - return &GitRepository{ +func OpenRepository(dir string) (*GitRepository, error) { + g := &GitRepository{ path: dir, } + + repo, err := git.PlainOpen(dir) + if err != nil { + return nil, err + } + g.repository = repo + + return g, nil +} + +func (g *GitRepository) SetRef(ref string) error { + if ref == "" { + head, err := g.repository.Head() + if err != nil { + return errors.Join(MissingRefErr, err) + } + g.ref = head.Hash() + } else { + hash, err := g.repository.ResolveRevision(plumbing.Revision(ref)) + if err != nil { + return errors.Join(MissingRefErr, err) + } + g.ref = *hash + } + g.setRef = true + return nil } func (g *GitRepository) Path() string { @@ -33,17 +64,12 @@ func (g *GitRepository) Path() string { } func (g *GitRepository) LastCommit() (*object.Commit, error) { - repo, err := git.PlainOpen(g.path) + err := g.validateRef() if err != nil { return nil, err } - ref, err := repo.Head() - if err != nil { - return nil, errors.Join(MissingHeadErr, err) - } - - c, err := repo.CommitObject(ref.Hash()) + c, err := g.repository.CommitObject(g.ref) if err != nil { return nil, err } @@ -51,17 +77,12 @@ func (g *GitRepository) LastCommit() (*object.Commit, error) { } func (g *GitRepository) Commits() ([]*object.Commit, error) { - repo, err := git.PlainOpen(g.path) + err := g.validateRef() if err != nil { return nil, err } - ref, err := repo.Head() - if err != nil { - return nil, errors.Join(MissingHeadErr, err) - } - - ci, err := repo.Log(&git.LogOptions{From: ref.Hash()}) + ci, err := g.repository.Log(&git.LogOptions{From: g.ref}) if err != nil { return nil, fmt.Errorf("commits from ref: %w", err) } @@ -84,13 +105,12 @@ func (g *GitRepository) Commits() ([]*object.Commit, error) { return commits, nil } -func (g *GitRepository) Tags() ([]*object.Tag, error) { - repo, err := git.PlainOpen(g.path) - if err != nil { - return nil, err - } +func (g *GitRepository) Head() (*plumbing.Reference, error) { + return g.repository.Head() +} - ti, err := repo.TagObjects() +func (g *GitRepository) Tags() ([]*object.Tag, error) { + ti, err := g.repository.TagObjects() if err != nil { return nil, err } @@ -108,12 +128,7 @@ func (g *GitRepository) Tags() ([]*object.Tag, error) { } func (g *GitRepository) Branches() ([]*plumbing.Reference, error) { - repo, err := git.PlainOpen(g.path) - if err != nil { - return nil, err - } - - bs, err := repo.Branches() + bs, err := g.repository.Branches() if err != nil { return nil, err } @@ -129,3 +144,10 @@ func (g *GitRepository) Branches() ([]*plumbing.Reference, error) { return branches, nil } + +func (g *GitRepository) validateRef() error { + if !g.setRef { + return g.SetRef("") + } + return nil +} diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go index d090f22..b77bcfc 100644 --- a/pkg/handler/git/handler.go +++ b/pkg/handler/git/handler.go @@ -18,9 +18,10 @@ type ( gitService interface { ListRepositories() ([]*service.Repository, error) - ListCommits(string) ([]*object.Commit, error) - ListTags(string) ([]*object.Tag, error) - ListBranches(string) ([]*plumbing.Reference, error) + ListCommits(name string, ref string) ([]*object.Commit, error) + GetHead(name string) (*plumbing.Reference, error) + ListTags(name string) ([]*object.Tag, error) + ListBranches(name string) ([]*plumbing.Reference, error) } ) @@ -43,8 +44,15 @@ func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) { func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) { name := mux.Vars(r)["name"] + ref, err := g.gitService.GetHead(name) + if err != nil { + slog.Error("Error loading head", "error", err) + return + } + gitList := &templates.GitItemPage{ Name: name, + Ref: ref.Name().Short(), GitItemBase: &templates.GitItemSummaryPage{}, } templates.WritePageTemplate(w, gitList) @@ -52,8 +60,14 @@ func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) { func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) { name := mux.Vars(r)["name"] + ref, err := g.gitService.GetHead(name) + if err != nil { + slog.Error("Error loading head", "error", err) + return + } gitList := &templates.GitItemPage{ Name: name, + Ref: ref.Name().Short(), GitItemBase: &templates.GitItemAboutPage{}, } templates.WritePageTemplate(w, gitList) @@ -74,8 +88,15 @@ func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) { return } + ref, err := g.gitService.GetHead(name) + if err != nil { + slog.Error("Error loading head", "error", err) + return + } + gitList := &templates.GitItemPage{ Name: name, + Ref: ref.Name().Short(), GitItemBase: &templates.GitItemRefsPage{ Tags: tags, Branches: branches, @@ -86,8 +107,10 @@ func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) { func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) { name := mux.Vars(r)["name"] + ref := mux.Vars(r)["ref"] gitList := &templates.GitItemPage{ Name: name, + Ref: ref, GitItemBase: &templates.GitItemTreePage{}, } templates.WritePageTemplate(w, gitList) @@ -95,8 +118,9 @@ func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) { func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) { name := mux.Vars(r)["name"] + ref := mux.Vars(r)["ref"] - commits, err := g.gitService.ListCommits(name) + commits, err := g.gitService.ListCommits(name, ref) if err != nil { slog.Error("Error loading commits", "error", err) return @@ -104,6 +128,7 @@ func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) { gitList := &templates.GitItemPage{ Name: name, + Ref: ref, GitItemBase: &templates.GitItemLogPage{ Commits: commits, }, diff --git a/pkg/handler/router.go b/pkg/handler/router.go index f73e9fb..79f70f1 100644 --- a/pkg/handler/router.go +++ b/pkg/handler/router.go @@ -34,10 +34,10 @@ func MountHandler( mux.PathPrefix("/static").Handler(staticHandler) mux.HandleFunc("/{name}/about", gitHandler.About) - mux.HandleFunc("/{name}/summary", gitHandler.Summary) + mux.HandleFunc("/{name}", gitHandler.Summary) mux.HandleFunc("/{name}/refs", gitHandler.Refs) - mux.HandleFunc("/{name}/tree", gitHandler.Tree) - mux.HandleFunc("/{name}/log", gitHandler.Log) + mux.HandleFunc("/{name}/tree/{ref}", gitHandler.Tree) + mux.HandleFunc("/{name}/log/{ref}", gitHandler.Log) mux.HandleFunc("/config", configHander) mux.HandleFunc("/about", aboutHandler.About) mux.HandleFunc("/", gitHandler.List) diff --git a/pkg/service/git.go b/pkg/service/git.go index 57b9b6e..9bf11f4 100644 --- a/pkg/service/git.go +++ b/pkg/service/git.go @@ -15,6 +15,7 @@ type ( Title string LastCommitMessage string LastCommitDate string + Ref string } GitService struct { @@ -41,29 +42,50 @@ func (g *GitService) ListRepositories() ([]*Repository, error) { repos := make([]*Repository, len(rs)) for i, r := range rs { - repo := git.NewGitRepository(r.Path) + repo, err := git.OpenRepository(r.Path) + if err != nil { + return nil, err + } + if err != nil { + return nil, err + } + obj, err := repo.LastCommit() if err != nil { return nil, err } + head, err := repo.Head() + if err != nil { + return nil, err + } + baseName := path.Base(r.Path) repos[i] = &Repository{ Name: baseName, Title: baseName, LastCommitMessage: obj.Message, LastCommitDate: obj.Author.When.Format(timeFormat), + Ref: head.Name().Short(), } } return repos, nil } -func (g *GitService) ListCommits(name string) ([]*object.Commit, error) { +func (g *GitService) ListCommits(name, ref string) ([]*object.Commit, error) { // TODO: handle nil r := g.configRepo.GetByName(name) - repo := git.NewGitRepository(r.Path) + repo, err := git.OpenRepository(r.Path) + if err != nil { + return nil, err + } + + err = repo.SetRef(ref) + if err != nil { + return nil, err + } return repo.Commits() } @@ -71,7 +93,10 @@ func (g *GitService) ListTags(name string) ([]*object.Tag, error) { // TODO: handle nil r := g.configRepo.GetByName(name) - repo := git.NewGitRepository(r.Path) + repo, err := git.OpenRepository(r.Path) + if err != nil { + return nil, err + } return repo.Tags() } @@ -79,6 +104,21 @@ func (g *GitService) ListBranches(name string) ([]*plumbing.Reference, error) { // TODO: handle nil r := g.configRepo.GetByName(name) - repo := git.NewGitRepository(r.Path) + repo, err := git.OpenRepository(r.Path) + if err != nil { + return nil, err + } return repo.Branches() } + +func (g *GitService) GetHead(name string) (*plumbing.Reference, error) { + // TODO: handle nil + r := g.configRepo.GetByName(name) + + repo, err := git.OpenRepository(r.Path) + if err != nil { + return nil, err + } + + return repo.Head() +} -- cgit v1.2.3