cerrado @ 907c13566c775ac1210bc66de99f7273e7c8a507

feat: Add commit page
diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
index 096303374b4fa36a7a62cf4f97a4bea41cb44c73..fd62e44b540b98d3f9dc04ab4d463215200deafa 100644
--- a/pkg/handler/git/handler.go
+++ b/pkg/handler/git/handler.go
@@ -34,6 +34,7 @@
 	gitService interface {
 		ListRepositories() ([]*service.Repository, error)
 		ListCommits(name string, ref string, count int) ([]*object.Commit, error)
+		LastCommit(name string, ref string) (*object.Commit, error)
 		GetHead(name string) (*plumbing.Reference, error)
 		GetTree(name, ref, path string) (*object.Tree, error)
 		IsBinary(name, ref, path string) (bool, error)
@@ -325,6 +326,27 @@ 		Name: name,
 		Ref:  ref,
 		GitItemBase: &templates.GitItemLogPage{
 			Commits: commits,
+		},
+	}
+	templates.WritePageTemplate(w, gitList)
+	return nil
+}
+
+func (g *GitHandler) Commit(w http.ResponseWriter, r *http.Request) error {
+	ext.SetHTML(w)
+	name := r.PathValue("name")
+	ref := r.PathValue("ref")
+
+	commit, err := g.gitService.LastCommit(name, ref)
+	if err != nil {
+		return err
+	}
+
+	gitList := &templates.GitItemPage{
+		Name: name,
+		Ref:  ref,
+		GitItemBase: &templates.GitItemCommitPage{
+			Commit: commit,
 		},
 	}
 	templates.WritePageTemplate(w, gitList)
diff --git a/pkg/handler/router.go b/pkg/handler/router.go
index 6ee7ba344943842ee40233b224fda539bcb4392b..f464ac28e50750b95b3447333f7362f3c31e3c5a 100644
--- a/pkg/handler/router.go
+++ b/pkg/handler/router.go
@@ -41,6 +41,7 @@ 	mux.HandleFunc("/{name}/refs/{$}", gitHandler.Refs)
 	mux.HandleFunc("/{name}/tree/{ref}/{rest...}", gitHandler.Tree)
 	mux.HandleFunc("/{name}/blob/{ref}/{rest...}", gitHandler.Blob)
 	mux.HandleFunc("/{name}/log/{ref}/", gitHandler.Log)
+	mux.HandleFunc("/{name}/commit/{ref}/", gitHandler.Commit)
 	mux.HandleFunc("/{name}/archive/{file}", gitHandler.Archive)
 	mux.HandleFunc("/config", configHandler)
 	mux.HandleFunc("/about", aboutHandler.About)
diff --git a/pkg/service/git.go b/pkg/service/git.go
index 1d212043bc292f173d2e44ccb451871a4469f99e..df4e3aa36917ce74895247c02a4f2a4f39f868b8 100644
--- a/pkg/service/git.go
+++ b/pkg/service/git.go
@@ -94,6 +94,25 @@ 	}
 	return repo.Commits(count)
 }
 
+func (g *GitService) LastCommit(name, ref string) (*object.Commit, error) {
+	r := g.configRepo.GetByName(name)
+	if r == nil {
+		return nil, ErrRepositoryNotFound
+	}
+
+	repo, err := git.OpenRepository(r.Path)
+	if err != nil {
+		return nil, err
+	}
+
+	err = repo.SetRef(ref)
+	if err != nil {
+		return nil, err
+	}
+
+	return repo.LastCommit()
+}
+
 func (g *GitService) WriteTarGZip(w io.Writer, name, ref string, prefix string) error {
 	r := g.configRepo.GetByName(name)
 	if r == nil {
diff --git a/templates/gititemcommit.qtpl b/templates/gititemcommit.qtpl
new file mode 100644
index 0000000000000000000000000000000000000000..e685f23d3e39c7ac8b44f8291617624c97f9cf92
--- /dev/null
+++ b/templates/gititemcommit.qtpl
@@ -0,0 +1,19 @@
+{% import "github.com/go-git/go-git/v5/plumbing/object" %}
+
+{% code
+type GitItemCommitPage struct {
+    Commit *object.Commit
+}
+%}
+
+{% func (g *GitItemCommitPage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Log) %}{% endfunc %}
+
+{% func (g *GitItemCommitPage) GitContent(name, ref string) %}
+<div class="event-list">
+  {%= Commit(name, g.Commit) %}
+</div>
+
+<div class="alert alert-info text-center" role="alert">
+    This page is work in progress.
+</div>
+{% endfunc %}
diff --git a/templates/gititemcommit.qtpl.go b/templates/gititemcommit.qtpl.go
new file mode 100644
index 0000000000000000000000000000000000000000..13c1fa9ae3b12dc697d47280e043e8489b8c83cf
--- /dev/null
+++ b/templates/gititemcommit.qtpl.go
@@ -0,0 +1,104 @@
+// Code generated by qtc from "gititemcommit.qtpl". DO NOT EDIT.
+// See https://github.com/valyala/quicktemplate for details.
+
+//line gititemcommit.qtpl:1
+package templates
+
+//line gititemcommit.qtpl:1
+import "github.com/go-git/go-git/v5/plumbing/object"
+
+//line gititemcommit.qtpl:3
+import (
+	qtio422016 "io"
+
+	qt422016 "github.com/valyala/quicktemplate"
+)
+
+//line gititemcommit.qtpl:3
+var (
+	_ = qtio422016.Copy
+	_ = qt422016.AcquireByteBuffer
+)
+
+//line gititemcommit.qtpl:4
+type GitItemCommitPage struct {
+	Commit *object.Commit
+}
+
+//line gititemcommit.qtpl:9
+func (g *GitItemCommitPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
+//line gititemcommit.qtpl:9
+	StreamGitItemNav(qw422016, name, ref, Log)
+//line gititemcommit.qtpl:9
+}
+
+//line gititemcommit.qtpl:9
+func (g *GitItemCommitPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
+//line gititemcommit.qtpl:9
+	qw422016 := qt422016.AcquireWriter(qq422016)
+//line gititemcommit.qtpl:9
+	g.StreamNav(qw422016, name, ref)
+//line gititemcommit.qtpl:9
+	qt422016.ReleaseWriter(qw422016)
+//line gititemcommit.qtpl:9
+}
+
+//line gititemcommit.qtpl:9
+func (g *GitItemCommitPage) Nav(name, ref string) string {
+//line gititemcommit.qtpl:9
+	qb422016 := qt422016.AcquireByteBuffer()
+//line gititemcommit.qtpl:9
+	g.WriteNav(qb422016, name, ref)
+//line gititemcommit.qtpl:9
+	qs422016 := string(qb422016.B)
+//line gititemcommit.qtpl:9
+	qt422016.ReleaseByteBuffer(qb422016)
+//line gititemcommit.qtpl:9
+	return qs422016
+//line gititemcommit.qtpl:9
+}
+
+//line gititemcommit.qtpl:11
+func (g *GitItemCommitPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
+//line gititemcommit.qtpl:11
+	qw422016.N().S(`
+<div class="event-list">
+  `)
+//line gititemcommit.qtpl:13
+	StreamCommit(qw422016, name, g.Commit)
+//line gititemcommit.qtpl:13
+	qw422016.N().S(`
+</div>
+
+<div class="alert alert-info text-center" role="alert">
+    This page is work in progress.
+</div>
+`)
+//line gititemcommit.qtpl:19
+}
+
+//line gititemcommit.qtpl:19
+func (g *GitItemCommitPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
+//line gititemcommit.qtpl:19
+	qw422016 := qt422016.AcquireWriter(qq422016)
+//line gititemcommit.qtpl:19
+	g.StreamGitContent(qw422016, name, ref)
+//line gititemcommit.qtpl:19
+	qt422016.ReleaseWriter(qw422016)
+//line gititemcommit.qtpl:19
+}
+
+//line gititemcommit.qtpl:19
+func (g *GitItemCommitPage) GitContent(name, ref string) string {
+//line gititemcommit.qtpl:19
+	qb422016 := qt422016.AcquireByteBuffer()
+//line gititemcommit.qtpl:19
+	g.WriteGitContent(qb422016, name, ref)
+//line gititemcommit.qtpl:19
+	qs422016 := string(qb422016.B)
+//line gititemcommit.qtpl:19
+	qt422016.ReleaseByteBuffer(qb422016)
+//line gititemcommit.qtpl:19
+	return qs422016
+//line gititemcommit.qtpl:19
+}