feat(log): show commit authors as their ~account when known
5 files changed, +41 −6
- forge/extra.go modified +5 −1
- forge/feature_test.go modified +23 −0
- forge/web.go modified +11 −3
- web/templates/blame.tmpl modified +1 −1
- web/templates/meta.tmpl modified +1 −1
forge/extra.go modified
| @@ -112,6 +112,7 @@ func (s *Server) archiveRepo(w http.ResponseWriter, r *http.Request, repo Repo) | ||
| 112 | 112 | type BlameLine struct { |
| 113 | 113 | Hash string |
| 114 | 114 | Author string |
| 115 | + Email string | |
| 115 | 116 | Time time.Time |
| 116 | 117 | Line int |
| 117 | 118 | Text string |
| @@ -146,10 +147,13 @@ func (g Git) Blame(commit, filePath string) ([]BlameLine, error) { | ||
| 146 | 147 | base = &BlameLine{Hash: f[0]} |
| 147 | 148 | meta[f[0]] = base |
| 148 | 149 | } |
| 149 | - cur = &BlameLine{Hash: f[0], Author: base.Author, Time: base.Time, Subject: base.Subject, Line: n} | |
| 150 | + cur = &BlameLine{Hash: f[0], Author: base.Author, Email: base.Email, Time: base.Time, Subject: base.Subject, Line: n} | |
| 150 | 151 | case strings.HasPrefix(line, "author "): |
| 151 | 152 | meta[cur.Hash].Author = strings.TrimPrefix(line, "author ") |
| 152 | 153 | cur.Author = meta[cur.Hash].Author |
| 154 | + case strings.HasPrefix(line, "author-mail "): | |
| 155 | + meta[cur.Hash].Email = strings.Trim(strings.TrimPrefix(line, "author-mail "), "<>") | |
| 156 | + cur.Email = meta[cur.Hash].Email | |
| 153 | 157 | case strings.HasPrefix(line, "author-time "): |
| 154 | 158 | t, _ := strconv.ParseInt(strings.TrimPrefix(line, "author-time "), 10, 64) |
| 155 | 159 | meta[cur.Hash].Time = time.Unix(t, 0) |
forge/feature_test.go modified
| @@ -553,3 +553,26 @@ func TestDomains(t *testing.T) { | ||
| 553 | 553 | t.Error("removed domain still served") |
| 554 | 554 | } |
| 555 | 555 | } |
| 556 | + | |
| 557 | +func TestCommitAccount(t *testing.T) { | |
| 558 | + if _, err := exec.LookPath("git"); err != nil { | |
| 559 | + t.Skip("git not installed") | |
| 560 | + } | |
| 561 | + s, h := testServer(t) | |
| 562 | + tee, _ := s.store.CreateUser("tee", "correct horse") | |
| 563 | + _, g := newRepo(t, s, tee, "proj", Public) | |
| 564 | + hash := addEntry(t, g, g.Head(), "100644", "README.md", "hello") | |
| 565 | + link := `<a href="/~tee" title="T">~tee</a>` | |
| 566 | + paths := []string{"/~tee/proj/log", "/~tee/proj/commit/" + hash, "/~tee/proj/blame/" + g.Head() + "/README.md"} | |
| 567 | + for _, p := range paths { | |
| 568 | + if w := pagesGet(h, "example.org", p); w.Code != 200 || strings.Contains(w.Body.String(), link) { | |
| 569 | + t.Errorf("%s before verification: %d", p, w.Code) | |
| 570 | + } | |
| 571 | + } | |
| 572 | + s.store.MarkVerified(tee.ID, "[email protected]") | |
| 573 | + for _, p := range paths { | |
| 574 | + if w := pagesGet(h, "example.org", p); w.Code != 200 || !strings.Contains(w.Body.String(), link) { | |
| 575 | + t.Errorf("%s after verification: %d", p, w.Code) | |
| 576 | + } | |
| 577 | + } | |
| 578 | +} | |
forge/web.go modified
| @@ -99,9 +99,10 @@ func newServer(store *Store, root, host, name string, sshUser string) *Server { | ||
| 99 | 99 | s := strings.TrimSuffix(string(b), "\n") |
| 100 | 100 | return strings.Split(s, "\n") |
| 101 | 101 | }, |
| 102 | - "inc": func(i int) int { return i + 1 }, | |
| 103 | - "perm": perm, | |
| 104 | - "signer": s.signer, | |
| 102 | + "inc": func(i int) int { return i + 1 }, | |
| 103 | + "perm": perm, | |
| 104 | + "signer": s.signer, | |
| 105 | + "account": s.account, | |
| 105 | 106 | "lang": func(r Repo) language { |
| 106 | 107 | if l := s.repoLanguages(r); len(l) > 0 { |
| 107 | 108 | return l[0] |
| @@ -503,6 +504,13 @@ func (s *Server) create(w http.ResponseWriter, r *http.Request) { | ||
| 503 | 504 | http.Redirect(w, r, "/"+repo.Path(), http.StatusSeeOther) |
| 504 | 505 | } |
| 505 | 506 | |
| 507 | +func (s *Server) account(c Commit) string { | |
| 508 | + if u, ok := s.personByEmail(c.Email); ok { | |
| 509 | + return u.Name | |
| 510 | + } | |
| 511 | + return s.signer(c) | |
| 512 | +} | |
| 513 | + | |
| 506 | 514 | func (s *Server) signer(c Commit) string { |
| 507 | 515 | switch c.Signature { |
| 508 | 516 | case "G", "U": |
web/templates/blame.tmpl modified
| @@ -7,5 +7,5 @@ | ||
| 7 | 7 | <span class="spacer"></span> |
| 8 | 8 | {{with .Data.LastCommit}}<span class="lastcommit"><a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}">{{short .Hash}}</a> {{.Subject}} <span class="muted">{{ago .Time}}</span></span>{{end}} |
| 9 | 9 | </div> |
| 10 | -<div class="code"><table class="blame">{{range .Data.Lines}}<tr{{if .First}} class="first"{{end}}><td class="who">{{if .First}}<a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}" title="{{.Subject}}">{{short .Hash}}</a> {{.Author}} <span class="muted">{{ago .Time}}</span>{{end}}</td><td class="n" id="L{{.Line}}"><a href="#L{{.Line}}">{{.Line}}</a></td><td class="l">{{.Text}}</td></tr>{{end}}</table></div> | |
| 10 | +<div class="code"><table class="blame">{{range .Data.Lines}}<tr{{if .First}} class="first"{{end}}><td class="who">{{if .First}}<a class="hash" href="/{{$p.Repo.Path}}/commit/{{.Hash}}" title="{{.Subject}}">{{short .Hash}}</a> {{$a := .Author}}{{with person .Email}}<a href="/~{{.}}" title="{{$a}}">~{{.}}</a>{{else}}{{$a}}{{end}} <span class="muted">{{ago .Time}}</span>{{end}}</td><td class="n" id="L{{.Line}}"><a href="#L{{.Line}}">{{.Line}}</a></td><td class="l">{{.Text}}</td></tr>{{end}}</table></div> | |
| 11 | 11 | {{end}} |
web/templates/meta.tmpl modified
| @@ -8,7 +8,7 @@ | ||
| 8 | 8 | {{else if .Assignees}}{{range .Assignees}}<a href="/~{{.Name}}">~{{.Name}}</a> {{end}}{{else}}<p class="muted small">Nobody</p>{{end}} |
| 9 | 9 | </div> |
| 10 | 10 | {{end}} |
| 11 | -{{define "who"}}{{with person .Email}}<a href="/~{{.}}">{{$.Author}}</a>{{else}}{{.Author}}{{end}}{{end}} | |
| 11 | +{{define "who"}}{{with account .}}<a href="/~{{.}}" title="{{$.Author}}">~{{.}}</a>{{else}}{{.Author}}{{end}}{{end}} | |
| 12 | 12 | {{define "repoitem"}}<div class="event repo"><h4><a href="/{{.Path}}">{{.Name}}</a>{{if .Private}} <span class="tag">private</span>{{else if .Unlisted}} <span class="tag">unlisted</span>{{end}}</h4>{{if .Description}}<p>{{.Description}}</p>{{end}}{{if .Tags}}<p class="tags">{{range .Tags}}<a href="/search?q=tag:{{.}}">#{{.}}</a> {{end}}</p>{{end}}{{template "repometa" .}}</div>{{end}} |
| 13 | 13 | {{define "repometa"}}{{$l := lang .}}<p class="repometa">{{with $l.Name}}<span><i class="dot" style="background:{{$l.Colour}}"></i>{{.}}</span>{{end}}<span title="{{.Stars}} star{{if ne .Stars 1}}s{{end}}"><svg viewBox="0 0 16 16" aria-hidden="true"><path d="M8 1.6l1.9 4 4.4.5-3.3 3 .9 4.3L8 11.2 4.1 13.4l.9-4.3-3.3-3 4.4-.5z"/></svg>{{.Stars}}</span><span title="{{.Forks}} fork{{if ne .Forks 1}}s{{end}}"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="4" cy="3" r="1.6"/><circle cx="12" cy="3" r="1.6"/><circle cx="8" cy="13" r="1.6"/><path d="M4 4.6v1.4a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2V4.6M8 8v3.4"/></svg>{{.Forks}}</span></p>{{end}} |
| 14 | 14 | {{define "pushed"}}{{$p := .Page}}{{range .Pushed}}<div class="pushnote"><svg viewBox="0 0 16 16" aria-hidden="true"><circle cx="4" cy="3" r="1.6"/><circle cx="4" cy="13" r="1.6"/><circle cx="12" cy="5" r="1.6"/><path d="M4 4.6v6.8M12 6.6c0 3-4 2.6-7.4 5.2"/></svg><span><strong>{{.Name}}</strong> had recent pushes {{ago .Time}}, {{.Ahead}} commit{{if ne .Ahead 1}}s{{end}} ahead of {{$p.Ref}}</span><a class="btn primary" href="/{{$p.Repo.Path}}/pulls/new?source={{$p.Repo.Path}}:{{.Name}}&target={{$p.Ref}}">Open pull request ▸</a></div>{{end}}{{end}} |