internal/httpd/compare.go

e2a32d5f8d59e4213571c602bd9009b6c8fa86ed
gitbay/internal/httpd/compare.go history · blame · raw

86 lines · 2603 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	s.render(w, "compare.html", struct {
77		repoPage
78		Base, Head, BaseSHA, HeadSHA, MergeBase string
79		Commits                                 []row
80		CommitsTotal                            int
81		DiffFiles                               []diffFile
82		DiffTruncated                           bool
83		Stat                                    diffStat
84		CanWrite                                bool
85	}{p, base, head, baseSHA, headSHA, mergeBase, commits, total, files, truncated, statOf(files), s.canWriteRepo(r, p.Repo)})
86}