diff options
| -rw-r--r-- | pkg/git/git.go | 35 | ||||
| -rw-r--r-- | pkg/handler/git/handler.go | 15 | ||||
| -rw-r--r-- | pkg/service/git.go | 10 | ||||
| -rw-r--r-- | scss/main.scss | 35 | ||||
| -rw-r--r-- | templates/base.qtpl | 6 | ||||
| -rw-r--r-- | templates/base.qtpl.go | 184 | ||||
| -rw-r--r-- | templates/gititem.qtpl | 2 | ||||
| -rw-r--r-- | templates/gititem.qtpl.go | 2 | ||||
| -rw-r--r-- | templates/gititemlog.qtpl | 19 | ||||
| -rw-r--r-- | 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) %}  <html lang="en"> 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(`  <html lang="en">      <head>          <meta charset="utf-8">          <link rel="icon" href="data:,">          <title>cerrado | `) -//line base.qtpl:33 +//line base.qtpl:39  	p.StreamTitle(qw422016) -//line base.qtpl:33 +//line base.qtpl:39  	qw422016.N().S(`</title>           <link rel="stylesheet" href="/static/main`) -//line base.qtpl:34 +//line base.qtpl:40  	qw422016.E().S(Slug) -//line base.qtpl:34 +//line base.qtpl:40  	qw422016.N().S(`.css">          <meta name="viewport" content="width=device-width, initial-scale=1" />      </head>      <body>          `) -//line base.qtpl:38 +//line base.qtpl:44  	p.StreamNavbar(qw422016) -//line base.qtpl:38 +//line base.qtpl:44  	qw422016.N().S(`          <div class="container">              `) -//line base.qtpl:40 +//line base.qtpl:46  	p.StreamContent(qw422016) -//line base.qtpl:40 +//line base.qtpl:46  	qw422016.N().S(`          </div>      </body>      `) -//line base.qtpl:43 +//line base.qtpl:49  	p.StreamScript(qw422016) -//line base.qtpl:43 +//line base.qtpl:49  	qw422016.N().S(`  </html>  `) -//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 {  <div class="row">  {%= p.Nav(p.Name) %}  </div> -<div class="row"> +<div class="container">  {%= p.GitContent() %}  </div>  {% 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(`  </div> -<div class="row"> +<div class="container">  `)  //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() %} -<h4>Log</h4> +<div class="logs"> +  {% for _, c := range g.Commits %} +  <div class="row"> +      <div class="col-sm-2"> +       {%s TimeFormat(c.Committer.When) %} +      </div> +      <div class="col-sm-7"> +       <pre>{%s c.Message %}</pre> +      </div> +      <div class="col-sm-3"> +       {%s c.Committer.Name %} +      </div> +  </div> +  {% endfor %} +</div>  {% 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(` +<div class="logs"> +  `) +//line gititemlog.qtpl:13 +	for _, c := range g.Commits { +//line gititemlog.qtpl:13 +		qw422016.N().S(` +  <div class="row"> +      <div class="col-sm-2"> +       `) +//line gititemlog.qtpl:16 +		qw422016.E().S(TimeFormat(c.Committer.When)) +//line gititemlog.qtpl:16 +		qw422016.N().S(` +      </div> +      <div class="col-sm-7"> +       <pre>`) +//line gititemlog.qtpl:19 +		qw422016.E().S(c.Message) +//line gititemlog.qtpl:19 +		qw422016.N().S(`</pre> +      </div> +      <div class="col-sm-3"> +       `) +//line gititemlog.qtpl:22 +		qw422016.E().S(c.Committer.Name) +//line gititemlog.qtpl:22 +		qw422016.N().S(` +      </div> +  </div> +  `) +//line gititemlog.qtpl:25 +	} +//line gititemlog.qtpl:25  	qw422016.N().S(` -<h4>Log</h4> +</div>  `) -//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  } | 
