Goit

Simple and lightweight Git web server
git clone https://git.omkov.net/Goit
git clone [email protected]:Goit
Log | Tree | Refs | README | Download

AuthorJakob Wakeling <[email protected]>
Date2025-01-14 09:25:25
Commit6412f37785022dec163b53dc749742764030fd69
Parent54413b9514588efb4ac91826eff31595a2e9b6e9
Tag 0.2.1

Display commit associated branches and tags

Diffstat

M res/repo/commit.html | 20 ++++++++++++++++++++
M res/repo/log.html | 6 ++++++
M src/goit/git.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
M src/repo/commit.go | 28 +++++++++++++++++++++++++++-
M src/repo/log.go | 39 ++++++++++++++++++++++++++++-----------

5 files changed, 148 insertions, 12 deletions

diff --git a/res/repo/commit.html b/res/repo/commit.html
index c5b6117..adcda39 100644
--- a/res/repo/commit.html
+++ b/res/repo/commit.html
@@ -11,6 +11,26 @@
 				{{range $i, $h := .Parents}}
 					<tr><td>Parent</td><td><a href="/{{$.Name}}/commit/{{$h}}">{{$h}}</a></td></tr>
 				{{end}}
+				{{if .Branches}}
+					<tr>
+						<td>Branch{{if gt (len .Branches) 1}}es{{end}}</td>
+						<td>
+							{{range $i, $_ := .Branches}}{{if $i}},{{- end}}
+								{{.}}
+							{{- end}}
+						</td>
+					</tr>
+				{{end}}
+				{{if .Tags}}
+					<tr>
+						<td>Tag{{if gt (len .Tags) 1}}s{{end}}</td>
+						<td>
+							{{range $i, $_ := .Tags}}{{if $i}},{{- end}}
+								<a href="/{{$.Name}}/tag/{{.}}">{{.}}</a>
+							{{- end}}
+						</td>
+					</tr>
+				{{end}}
 			</table>
 			<p>{{.MessageSubject}}</p>
 			<p>{{.MessageBody}}</p>
diff --git a/res/repo/log.html b/res/repo/log.html
index 779c398..f6e6856 100644
--- a/res/repo/log.html
+++ b/res/repo/log.html
@@ -13,6 +13,7 @@
 						<td><b>Files</b></td>
 						<td><b>+</b></td>
 						<td><b>-</b></td>
+						<td><b>Tag(s)</b></td>
 					</tr>
 				</thead>
 				<tbody>
@@ -25,6 +26,11 @@
 								<td style="text-align: right;">{{.Files}}</td>
 								<td style="text-align: right; color: #008800;">{{.Additions}}</td>
 								<td style="text-align: right; color: #AA0000;">{{.Deletions}}</td>
+								<td>
+								{{range $i, $_ := .Tags}}{{if $i}},{{- end}}
+									<a href="/{{$.Name}}/tag/{{.}}">{{.}}</a>
+								{{- end}}
+								</td>
 							</tr>
 						{{end}}
 					{{else}}
diff --git a/src/goit/git.go b/src/goit/git.go
index 0c93c50..2b9fad6 100644
--- a/src/goit/git.go
+++ b/src/goit/git.go
@@ -16,6 +16,7 @@ import (
 	"sync"
 
 	"github.com/go-chi/chi/v5"
+	"github.com/go-git/go-git/v5"
 	"github.com/go-git/go-git/v5/plumbing"
 	"github.com/go-git/go-git/v5/plumbing/format/diff"
 	"github.com/go-git/go-git/v5/plumbing/object"
@@ -369,3 +370,69 @@ func GetFileType(file *object.File) (string, error) {
 
 	return http.DetectContentType(buf), nil
 }
+
+type RefCommit struct {
+	Ref    *plumbing.Reference
+	Commit *object.Commit
+}
+
+/* Return an array of tag referenced commits for a repository. */
+func TaggedCommits(gr *git.Repository) ([]RefCommit, error) {
+	var taggedCommits []RefCommit
+
+	tags, err := gr.Tags()
+	if err != nil {
+		return nil, err
+	}
+
+	if err := tags.ForEach(func(ref *plumbing.Reference) error {
+		var commit *object.Commit
+
+		tag, err := gr.TagObject(ref.Hash())
+		switch err {
+		case nil:
+			if commit, err = gr.CommitObject(tag.Target); err != nil {
+				return err
+			}
+		case plumbing.ErrObjectNotFound:
+			if commit, err = gr.CommitObject(ref.Hash()); err != nil {
+				return err
+			}
+		default:
+			return err
+		}
+
+		taggedCommits = append(taggedCommits, RefCommit{ref, commit})
+
+		return nil
+	}); err != nil {
+		return nil, err
+	}
+
+	return taggedCommits, nil
+}
+
+/* Return an array of branch referenced commits for a repository. */
+func BranchCommits(gr *git.Repository) ([]RefCommit, error) {
+	var branchCommits []RefCommit
+
+	branches, err := gr.Branches()
+	if err != nil {
+		return nil, err
+	}
+
+	if err := branches.ForEach(func(ref *plumbing.Reference) error {
+		commit, err := gr.CommitObject(ref.Hash())
+		if err != nil {
+			return err
+		}
+
+		branchCommits = append(branchCommits, RefCommit{ref, commit})
+
+		return nil
+	}); err != nil {
+		return nil, err
+	}
+
+	return branchCommits, nil
+}
diff --git a/src/repo/commit.go b/src/repo/commit.go
index 35000b0..e6b690b 100644
--- a/src/repo/commit.go
+++ b/src/repo/commit.go
@@ -47,7 +47,7 @@ func HandleCommit(w http.ResponseWriter, r *http.Request) {
 		HeaderFields
 		Title                       string
 		Author, Date, Commit        string
-		Parents                     []string
+		Parents, Branches, Tags     []string
 		MessageSubject, MessageBody string
 		Stats                       []stat
 		Summary                     string
@@ -98,6 +98,32 @@ func HandleCommit(w http.ResponseWriter, r *http.Request) {
 		data.Parents = append(data.Parents, h.String())
 	}
 
+	branchCommits, err := goit.BranchCommits(gr)
+	if err != nil {
+		util.PrintFuncError(err)
+		goit.HttpError(w, http.StatusInternalServerError)
+		return
+	}
+
+	for _, branchCommit := range branchCommits {
+		if branchCommit.Ref.Hash().String() == commit.Hash.String() {
+			data.Branches = append(data.Branches, branchCommit.Ref.Name().Short())
+		}
+	}
+
+	taggedCommits, err := goit.TaggedCommits(gr)
+	if err != nil {
+		util.PrintFuncError(err)
+		goit.HttpError(w, http.StatusInternalServerError)
+		return
+	}
+
+	for _, taggedCommit := range taggedCommits {
+		if taggedCommit.Ref.Hash().String() == commit.Hash.String() {
+			data.Tags = append(data.Tags, taggedCommit.Ref.Name().Short())
+		}
+	}
+
 	data.MessageSubject, data.MessageBody, _ = strings.Cut(commit.Message, "\n")
 
 	st, err := goit.DiffStats(commit)
diff --git a/src/repo/log.go b/src/repo/log.go
index 248b9ba..ddc1c1d 100644
--- a/src/repo/log.go
+++ b/src/repo/log.go
@@ -7,7 +7,6 @@ import (
 	"errors"
 	"fmt"
 	"io"
-	"log"
 	"net/http"
 	"path/filepath"
 	"strconv"
@@ -26,7 +25,7 @@ const PAGE = 100
 func HandleLog(w http.ResponseWriter, r *http.Request) {
 	auth, user, err := goit.Auth(w, r, true)
 	if err != nil {
-		log.Println("[repo/log]", err.Error())
+		util.PrintFuncError(err)
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
 	}
@@ -52,7 +51,11 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 		}
 	}
 
-	type row struct{ Hash, Date, Message, Author, Files, Additions, Deletions string }
+	type row struct {
+		Hash, Date, Message, Author, Files, Additions, Deletions string
+		Tags                                                     []string
+	}
+
 	data := struct {
 		HeaderFields
 		Title                        string
@@ -69,7 +72,7 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 
 	gr, err := git.PlainOpen(goit.RepoPath(repo.Name, true))
 	if err != nil {
-		log.Println("[/repo/log]", err.Error())
+		util.PrintFuncError(err)
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
 	}
@@ -79,7 +82,7 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 		data.NextOffset = 0
 		goto execute
 	} else if err != nil {
-		log.Println("[/repo/log]", err.Error())
+		util.PrintFuncError(err)
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
 	}
@@ -96,7 +99,7 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 			return tpath == "" || s == tpath || strings.HasPrefix(s, tpath+"/")
 		},
 	}); err != nil {
-		log.Println("[/repo/log]", err.Error())
+		util.PrintFuncError(err)
 		goit.HttpError(w, http.StatusInternalServerError)
 		return
 	} else {
@@ -107,19 +110,26 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 					goto execute
 				}
 
-				log.Println("[/repo/log]", err.Error())
+				util.PrintFuncError(err)
 				goit.HttpError(w, http.StatusInternalServerError)
 				return
 			}
 		}
 
+		taggedCommits, err := goit.TaggedCommits(gr)
+		if err != nil {
+			util.PrintFuncError(err)
+			goit.HttpError(w, http.StatusInternalServerError)
+			return
+		}
+
 		for i := 0; i < PAGE; i += 1 {
 			c, err := iter.Next()
 			if errors.Is(err, io.EOF) {
 				data.NextOffset = 0
 				goto execute
 			} else if err != nil {
-				log.Println("[/repo/log]", err.Error())
+				util.PrintFuncError(err)
 				goit.HttpError(w, http.StatusInternalServerError)
 				return
 			}
@@ -127,7 +137,7 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 			var files, additions, deletions int
 
 			if stats, err := goit.DiffStats(c); err != nil {
-				log.Println("[/repo/log]", err.Error())
+				util.PrintFuncError(err)
 			} else {
 				files = len(stats)
 				for _, s := range stats {
@@ -136,10 +146,17 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 				}
 			}
 
+			var tags []string
+			for _, taggedCommit := range taggedCommits {
+				if taggedCommit.Ref.Hash().String() == c.Hash.String() {
+					tags = append(tags, taggedCommit.Ref.Name().Short())
+				}
+			}
+
 			data.Commits = append(data.Commits, row{
 				Hash: c.Hash.String(), Date: c.Author.When.UTC().Format(time.DateTime),
 				Message: strings.SplitN(c.Message, "\n", 2)[0], Author: c.Author.Name, Files: fmt.Sprint(files),
-				Additions: "+" + fmt.Sprint(additions), Deletions: "-" + fmt.Sprint(deletions),
+				Additions: "+" + fmt.Sprint(additions), Deletions: "-" + fmt.Sprint(deletions), Tags: tags,
 			})
 		}
 
@@ -150,6 +167,6 @@ func HandleLog(w http.ResponseWriter, r *http.Request) {
 
 execute:
 	if err := goit.Tmpl.ExecuteTemplate(w, "repo/log", data); err != nil {
-		log.Println("[/repo/log]", err.Error())
+		util.PrintFuncError(err)
 	}
 }