From 4ea63e98cc999ab05d1ac98b64875d7413e86972 Mon Sep 17 00:00:00 2001 From: "Gabriel A. Giovanini" Date: Sat, 1 Jun 2024 17:20:59 +0200 Subject: feat: Add initial log --- pkg/git/git.go | 35 ++++++++ pkg/handler/git/handler.go | 15 +++- pkg/service/git.go | 10 +++ scss/main.scss | 35 +++++++- templates/base.qtpl | 6 ++ templates/base.qtpl.go | 184 ++++++++++++++++++++++--------------------- templates/gititem.qtpl | 2 +- templates/gititem.qtpl.go | 2 +- templates/gititemlog.qtpl | 19 ++++- templates/gititemlog.qtpl.go | 104 ++++++++++++++++-------- 10 files changed, 282 insertions(+), 130 deletions(-) diff --git a/pkg/git/git.go b/pkg/git/git.go index b9ab235..80c0e46 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -2,6 +2,8 @@ package git import ( "errors" + "fmt" + "io" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing/object" @@ -46,3 +48,36 @@ func (g *GitRepository) LastCommit() (*object.Commit, error) { } return c, nil } + +func (g *GitRepository) Commits() ([]*object.Commit, error) { + repo, err := git.PlainOpen(g.path) + 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()}) + if err != nil { + return nil, fmt.Errorf("commits from ref: %w", err) + } + + commits := []*object.Commit{} + // TODO: for now only load first 1000 + for x := 0; x < 1000; x++ { + c, err := ci.Next() + if err != nil && errors.Is(err, io.EOF) { + break + } else if err != nil { + return nil, err + } + commits = append(commits, c) + } + if err != nil { + return nil, err + } + + return commits, nil +} diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go index 45cd865..ebfb37f 100644 --- a/pkg/handler/git/handler.go +++ b/pkg/handler/git/handler.go @@ -6,6 +6,7 @@ import ( "git.gabrielgio.me/cerrado/pkg/service" "git.gabrielgio.me/cerrado/templates" + "github.com/go-git/go-git/v5/plumbing/object" "github.com/gorilla/mux" ) @@ -16,6 +17,7 @@ type ( gitService interface { ListRepositories() ([]*service.Repository, error) + ListCommits(string) ([]*object.Commit, error) } ) @@ -74,9 +76,18 @@ 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"] + + commits, err := g.gitService.ListCommits(name) + if err != nil { + slog.Error("Error loading commits", "error", err) + return + } + gitList := &templates.GitItemPage{ - Name: name, - GitItemBase: &templates.GitItemLogPage{}, + Name: name, + GitItemBase: &templates.GitItemLogPage{ + Commits: commits, + }, } templates.WritePageTemplate(w, gitList) } diff --git a/pkg/service/git.go b/pkg/service/git.go index 2b1fe25..614770f 100644 --- a/pkg/service/git.go +++ b/pkg/service/git.go @@ -5,6 +5,7 @@ import ( "git.gabrielgio.me/cerrado/pkg/config" "git.gabrielgio.me/cerrado/pkg/git" + "github.com/go-git/go-git/v5/plumbing/object" ) type ( @@ -21,6 +22,7 @@ type ( configurationRepository interface { List() []*config.GitRepositoryConfiguration + GetByName(name string) *config.GitRepositoryConfiguration } ) @@ -55,3 +57,11 @@ func (g *GitService) ListRepositories() ([]*Repository, error) { return repos, nil } + +func (g *GitService) ListCommits(name string) ([]*object.Commit, error) { + // TODO: handle nil + r := g.configRepo.GetByName(name) + + repo := git.NewGitRepository(r.Path) + return repo.Commits() +} diff --git a/scss/main.scss b/scss/main.scss index deea23b..9f17dad 100644 --- a/scss/main.scss +++ b/scss/main.scss @@ -26,10 +26,6 @@ body { margin: 0; } -.card-body { - padding: 5px; -} - .navbar-nav { margin-top: 0px } @@ -65,3 +61,34 @@ body { display: grid; overflow-x: auto; } + +.logs { + >div:nth-child(odd) { + background: #f8f9fa; + } + + >div { + padding: 10px; + } + + pre { + white-space: break-spaces; + margin: 0; + } +} + +.logs pre::first-line { + font-weight: bold; +} + +@include media-breakpoint-down(sm) { + // add extra spacing then list is seen on vertical + .logs>div>div:first-child { + margin-bottom: 15px; + } + .logs>div>div:last-child { + margin-top: 15px; + } +} + + diff --git a/templates/base.qtpl b/templates/base.qtpl index ba32aad..16b8780 100644 --- a/templates/base.qtpl +++ b/templates/base.qtpl @@ -1,6 +1,7 @@ This is a base page template. All the other template pages implement this interface. {% import "strconv" %} +{% import "time" %} {% code var Slug = "" @@ -24,6 +25,11 @@ Page { } %} +{% code func TimeFormat(t time.Time) string { + return t.Format("2006-01-02") + } +%} + Page prints a page implementing Page interface. {% func PageTemplate(p Page) %} diff --git a/templates/base.qtpl.go b/templates/base.qtpl.go index 2f419c6..6d4d0a0 100644 --- a/templates/base.qtpl.go +++ b/templates/base.qtpl.go @@ -10,52 +10,55 @@ package templates //line base.qtpl:3 import "strconv" -//line base.qtpl:5 +//line base.qtpl:4 +import "time" + +//line base.qtpl:6 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line base.qtpl:5 +//line base.qtpl:6 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line base.qtpl:6 +//line base.qtpl:7 var Slug = "" -//line base.qtpl:10 +//line base.qtpl:11 type Page interface { -//line base.qtpl:10 +//line base.qtpl:11 Title() string -//line base.qtpl:10 +//line base.qtpl:11 StreamTitle(qw422016 *qt422016.Writer) -//line base.qtpl:10 +//line base.qtpl:11 WriteTitle(qq422016 qtio422016.Writer) -//line base.qtpl:10 +//line base.qtpl:11 Content() string -//line base.qtpl:10 +//line base.qtpl:11 StreamContent(qw422016 *qt422016.Writer) -//line base.qtpl:10 +//line base.qtpl:11 WriteContent(qq422016 qtio422016.Writer) -//line base.qtpl:10 +//line base.qtpl:11 Script() string -//line base.qtpl:10 +//line base.qtpl:11 StreamScript(qw422016 *qt422016.Writer) -//line base.qtpl:10 +//line base.qtpl:11 WriteScript(qq422016 qtio422016.Writer) -//line base.qtpl:10 +//line base.qtpl:11 Navbar() string -//line base.qtpl:10 +//line base.qtpl:11 StreamNavbar(qw422016 *qt422016.Writer) -//line base.qtpl:10 +//line base.qtpl:11 WriteNavbar(qq422016 qtio422016.Writer) -//line base.qtpl:10 +//line base.qtpl:11 } -//line base.qtpl:19 +//line base.qtpl:20 func FromUInttoString(u *uint) string { if u != nil { return strconv.FormatUint(uint64(*u), 10) @@ -63,174 +66,179 @@ func FromUInttoString(u *uint) string { return "" } +//line base.qtpl:28 +func TimeFormat(t time.Time) string { + return t.Format("2006-01-02") +} + // Page prints a page implementing Page interface. -//line base.qtpl:28 +//line base.qtpl:34 func StreamPageTemplate(qw422016 *qt422016.Writer, p Page) { -//line base.qtpl:28 +//line base.qtpl:34 qw422016.N().S(` cerrado | `) -//line base.qtpl:33 +//line base.qtpl:39 p.StreamTitle(qw422016) -//line base.qtpl:33 +//line base.qtpl:39 qw422016.N().S(` `) -//line base.qtpl:38 +//line base.qtpl:44 p.StreamNavbar(qw422016) -//line base.qtpl:38 +//line base.qtpl:44 qw422016.N().S(`
`) -//line base.qtpl:40 +//line base.qtpl:46 p.StreamContent(qw422016) -//line base.qtpl:40 +//line base.qtpl:46 qw422016.N().S(`
`) -//line base.qtpl:43 +//line base.qtpl:49 p.StreamScript(qw422016) -//line base.qtpl:43 +//line base.qtpl:49 qw422016.N().S(` `) -//line base.qtpl:45 +//line base.qtpl:51 } -//line base.qtpl:45 +//line base.qtpl:51 func WritePageTemplate(qq422016 qtio422016.Writer, p Page) { -//line base.qtpl:45 +//line base.qtpl:51 qw422016 := qt422016.AcquireWriter(qq422016) -//line base.qtpl:45 +//line base.qtpl:51 StreamPageTemplate(qw422016, p) -//line base.qtpl:45 +//line base.qtpl:51 qt422016.ReleaseWriter(qw422016) -//line base.qtpl:45 +//line base.qtpl:51 } -//line base.qtpl:45 +//line base.qtpl:51 func PageTemplate(p Page) string { -//line base.qtpl:45 +//line base.qtpl:51 qb422016 := qt422016.AcquireByteBuffer() -//line base.qtpl:45 +//line base.qtpl:51 WritePageTemplate(qb422016, p) -//line base.qtpl:45 +//line base.qtpl:51 qs422016 := string(qb422016.B) -//line base.qtpl:45 +//line base.qtpl:51 qt422016.ReleaseByteBuffer(qb422016) -//line base.qtpl:45 +//line base.qtpl:51 return qs422016 -//line base.qtpl:45 +//line base.qtpl:51 } -//line base.qtpl:47 +//line base.qtpl:53 type BasePage struct{} -//line base.qtpl:48 +//line base.qtpl:54 func (p *BasePage) StreamTitle(qw422016 *qt422016.Writer) { -//line base.qtpl:48 +//line base.qtpl:54 qw422016.N().S(`Empty`) -//line base.qtpl:48 +//line base.qtpl:54 } -//line base.qtpl:48 +//line base.qtpl:54 func (p *BasePage) WriteTitle(qq422016 qtio422016.Writer) { -//line base.qtpl:48 +//line base.qtpl:54 qw422016 := qt422016.AcquireWriter(qq422016) -//line base.qtpl:48 +//line base.qtpl:54 p.StreamTitle(qw422016) -//line base.qtpl:48 +//line base.qtpl:54 qt422016.ReleaseWriter(qw422016) -//line base.qtpl:48 +//line base.qtpl:54 } -//line base.qtpl:48 +//line base.qtpl:54 func (p *BasePage) Title() string { -//line base.qtpl:48 +//line base.qtpl:54 qb422016 := qt422016.AcquireByteBuffer() -//line base.qtpl:48 +//line base.qtpl:54 p.WriteTitle(qb422016) -//line base.qtpl:48 +//line base.qtpl:54 qs422016 := string(qb422016.B) -//line base.qtpl:48 +//line base.qtpl:54 qt422016.ReleaseByteBuffer(qb422016) -//line base.qtpl:48 +//line base.qtpl:54 return qs422016 -//line base.qtpl:48 +//line base.qtpl:54 } -//line base.qtpl:49 +//line base.qtpl:55 func (p *BasePage) StreamBody(qw422016 *qt422016.Writer) { -//line base.qtpl:49 +//line base.qtpl:55 qw422016.N().S(`HelloWorld`) -//line base.qtpl:49 +//line base.qtpl:55 } -//line base.qtpl:49 +//line base.qtpl:55 func (p *BasePage) WriteBody(qq422016 qtio422016.Writer) { -//line base.qtpl:49 +//line base.qtpl:55 qw422016 := qt422016.AcquireWriter(qq422016) -//line base.qtpl:49 +//line base.qtpl:55 p.StreamBody(qw422016) -//line base.qtpl:49 +//line base.qtpl:55 qt422016.ReleaseWriter(qw422016) -//line base.qtpl:49 +//line base.qtpl:55 } -//line base.qtpl:49 +//line base.qtpl:55 func (p *BasePage) Body() string { -//line base.qtpl:49 +//line base.qtpl:55 qb422016 := qt422016.AcquireByteBuffer() -//line base.qtpl:49 +//line base.qtpl:55 p.WriteBody(qb422016) -//line base.qtpl:49 +//line base.qtpl:55 qs422016 := string(qb422016.B) -//line base.qtpl:49 +//line base.qtpl:55 qt422016.ReleaseByteBuffer(qb422016) -//line base.qtpl:49 +//line base.qtpl:55 return qs422016 -//line base.qtpl:49 +//line base.qtpl:55 } -//line base.qtpl:50 +//line base.qtpl:56 func (p *BasePage) StreamScript(qw422016 *qt422016.Writer) { -//line base.qtpl:50 +//line base.qtpl:56 } -//line base.qtpl:50 +//line base.qtpl:56 func (p *BasePage) WriteScript(qq422016 qtio422016.Writer) { -//line base.qtpl:50 +//line base.qtpl:56 qw422016 := qt422016.AcquireWriter(qq422016) -//line base.qtpl:50 +//line base.qtpl:56 p.StreamScript(qw422016) -//line base.qtpl:50 +//line base.qtpl:56 qt422016.ReleaseWriter(qw422016) -//line base.qtpl:50 +//line base.qtpl:56 } -//line base.qtpl:50 +//line base.qtpl:56 func (p *BasePage) Script() string { -//line base.qtpl:50 +//line base.qtpl:56 qb422016 := qt422016.AcquireByteBuffer() -//line base.qtpl:50 +//line base.qtpl:56 p.WriteScript(qb422016) -//line base.qtpl:50 +//line base.qtpl:56 qs422016 := string(qb422016.B) -//line base.qtpl:50 +//line base.qtpl:56 qt422016.ReleaseByteBuffer(qb422016) -//line base.qtpl:50 +//line base.qtpl:56 return qs422016 -//line base.qtpl:50 +//line base.qtpl:56 } diff --git a/templates/gititem.qtpl b/templates/gititem.qtpl index 4a6c49a..d2fcea7 100644 --- a/templates/gititem.qtpl +++ b/templates/gititem.qtpl @@ -23,7 +23,7 @@ type GitItemPage struct {
{%= p.Nav(p.Name) %}
-
+
{%= p.GitContent() %}
{% endfunc %} diff --git a/templates/gititem.qtpl.go b/templates/gititem.qtpl.go index f978c4d..9709a43 100644 --- a/templates/gititem.qtpl.go +++ b/templates/gititem.qtpl.go @@ -124,7 +124,7 @@ func (p *GitItemPage) StreamContent(qw422016 *qt422016.Writer) { //line gititem.qtpl:24 qw422016.N().S(`
-
+
`) //line gititem.qtpl:27 p.StreamGitContent(qw422016) diff --git a/templates/gititemlog.qtpl b/templates/gititemlog.qtpl index ae88a52..a39fb77 100644 --- a/templates/gititemlog.qtpl +++ b/templates/gititemlog.qtpl @@ -1,10 +1,27 @@ +{% import "github.com/go-git/go-git/v5/plumbing/object" %} + {% code type GitItemLogPage struct { + Commits []*object.Commit } %} {% func (g *GitItemLogPage) Nav(name string) %}{%= GitItemNav(name, Log) %}{% endfunc %} {% func (g *GitItemLogPage) GitContent() %} -

Log

+
+ {% for _, c := range g.Commits %} +
+
+ {%s TimeFormat(c.Committer.When) %} +
+
+
{%s c.Message %}
+
+
+ {%s c.Committer.Name %} +
+
+ {% endfor %} +
{% endfunc %} diff --git a/templates/gititemlog.qtpl.go b/templates/gititemlog.qtpl.go index 2d559d7..cc5652d 100644 --- a/templates/gititemlog.qtpl.go +++ b/templates/gititemlog.qtpl.go @@ -5,86 +5,124 @@ package templates //line gititemlog.qtpl:1 +import "github.com/go-git/go-git/v5/plumbing/object" + +//line gititemlog.qtpl:3 import ( qtio422016 "io" qt422016 "github.com/valyala/quicktemplate" ) -//line gititemlog.qtpl:1 +//line gititemlog.qtpl:3 var ( _ = qtio422016.Copy _ = qt422016.AcquireByteBuffer ) -//line gititemlog.qtpl:2 +//line gititemlog.qtpl:4 type GitItemLogPage struct { + Commits []*object.Commit } -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 func (g *GitItemLogPage) StreamNav(qw422016 *qt422016.Writer, name string) { -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 StreamGitItemNav(qw422016, name, Log) -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 } -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 func (g *GitItemLogPage) WriteNav(qq422016 qtio422016.Writer, name string) { -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 qw422016 := qt422016.AcquireWriter(qq422016) -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 g.StreamNav(qw422016, name) -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 qt422016.ReleaseWriter(qw422016) -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 } -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 func (g *GitItemLogPage) Nav(name string) string { -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 qb422016 := qt422016.AcquireByteBuffer() -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 g.WriteNav(qb422016, name) -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 qs422016 := string(qb422016.B) -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 qt422016.ReleaseByteBuffer(qb422016) -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 return qs422016 -//line gititemlog.qtpl:6 +//line gititemlog.qtpl:9 } -//line gititemlog.qtpl:8 +//line gititemlog.qtpl:11 func (g *GitItemLogPage) StreamGitContent(qw422016 *qt422016.Writer) { -//line gititemlog.qtpl:8 +//line gititemlog.qtpl:11 + qw422016.N().S(` +
+ `) +//line gititemlog.qtpl:13 + for _, c := range g.Commits { +//line gititemlog.qtpl:13 + qw422016.N().S(` +
+
+ `) +//line gititemlog.qtpl:16 + qw422016.E().S(TimeFormat(c.Committer.When)) +//line gititemlog.qtpl:16 + qw422016.N().S(` +
+
+
`)
+//line gititemlog.qtpl:19
+		qw422016.E().S(c.Message)
+//line gititemlog.qtpl:19
+		qw422016.N().S(`
+
+
+ `) +//line gititemlog.qtpl:22 + qw422016.E().S(c.Committer.Name) +//line gititemlog.qtpl:22 + qw422016.N().S(` +
+
+ `) +//line gititemlog.qtpl:25 + } +//line gititemlog.qtpl:25 qw422016.N().S(` -

Log

+
`) -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 } -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 func (g *GitItemLogPage) WriteGitContent(qq422016 qtio422016.Writer) { -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 qw422016 := qt422016.AcquireWriter(qq422016) -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 g.StreamGitContent(qw422016) -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 qt422016.ReleaseWriter(qw422016) -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 } -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 func (g *GitItemLogPage) GitContent() string { -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 qb422016 := qt422016.AcquireByteBuffer() -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 g.WriteGitContent(qb422016) -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 qs422016 := string(qb422016.B) -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 qt422016.ReleaseByteBuffer(qb422016) -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 return qs422016 -//line gititemlog.qtpl:10 +//line gititemlog.qtpl:27 } -- cgit v1.2.3