internal/httpd/compare.go
93 lines · 2831 bytes
1package httpd
2
3import (
4 "net/http"
5 "strings"
6 "time"
7
8 "gitbay.org/gitbay/internal/gitutil"
9)
10
11// compare renders what head adds on top of base: the commits in
12// base..head and the diff from their merge base, the same range a merge
13// request shows before it exists (#118). /compare/{base}...{head} is the
14// link form; /compare?base=&head= is the form on the refs page.
15func (s *Server) compare(w http.ResponseWriter, r *http.Request) {
16 p, ok := s.repoFor(w, r, "")
17 if !ok {
18 return
19 }
20 p.Tab = "refs"
21 base, head := r.URL.Query().Get("base"), r.URL.Query().Get("head")
22 if rng := r.PathValue("range"); rng != "" {
23 if b, h, ok := strings.Cut(rng, "..."); ok {
24 base, head = b, h
25 } else if b, h, ok := strings.Cut(rng, ".."); ok {
26 base, head = b, h
27 }
28 }
29 if base == "" {
30 base = p.Repo.DefaultBranch
31 }
32 if head == "" {
33 http.Redirect(w, r, "/"+p.Repo.Path()+"/refs", http.StatusSeeOther)
34 return
35 }
36 baseSHA, err := gitutil.ResolveRef(p.Dir, base)
37 if err != nil {
38 s.notFound(w, r)
39 return
40 }
41 headSHA, err := gitutil.ResolveRef(p.Dir, head)
42 if err != nil {
43 s.notFound(w, r)
44 return
45 }
46 mergeBase, err := gitutil.MergeBase(p.Dir, baseSHA, headSHA)
47 if err != nil {
48 s.notFound(w, r)
49 return
50 }
51 patch, truncated, _ := gitutil.Diff(p.Dir, mergeBase, headSHA, 4<<20)
52 files := parseDiff(patch)
53 type row struct {
54 SHA, ShortSHA, Subject, AuthorName, AuthorUser, Date string
55 Sig sigView
56 }
57 names := s.authorNames()
58 var commits []row
59 shas, _ := gitutil.RevListRange(p.Dir, mergeBase, headSHA)
60 const maxCommits = 100
61 total := len(shas)
62 if len(shas) > maxCommits {
63 shas = shas[:maxCommits]
64 }
65 for _, sha := range shas {
66 v, parsed := s.sigFor(p.Repo, p.Dir, sha)
67 cr := row{SHA: sha, ShortSHA: sha[:10], Sig: v}
68 if parsed != nil {
69 cr.Subject = parsed.Subject
70 cr.AuthorName = names.name(parsed.AuthorEmail, parsed.AuthorName)
71 cr.AuthorUser, _ = names.account(parsed.AuthorEmail)
72 cr.Date = time.Unix(parsed.AuthorUnix, 0).UTC().Format(time.RFC3339)
73 }
74 commits = append(commits, cr)
75 }
76 layout := s.diffLayoutFor(r)
77 if layout.Split {
78 splitFiles(files)
79 }
80 canWrite := s.canWriteRepo(r, p.Repo)
81 canOpenMR := canWrite || len(s.writableForks(s.viewer(r), p.Repo)) > 0
82 s.render(w, "compare.html", struct {
83 repoPage
84 Base, Head, BaseSHA, HeadSHA, MergeBase string
85 Commits []row
86 CommitsTotal int
87 DiffFiles []diffFile
88 DiffTruncated bool
89 Stat diffStat
90 CanOpenMR bool
91 Layout diffLayout
92 }{p, base, head, baseSHA, headSHA, mergeBase, commits, total, files, truncated, statOf(files), canOpenMR, layout})
93}