···11+{{ define "title" }}new comparison{{ end }}22+33+{{ define "repoContent" }}44+ <h2 class="font-bold text-sm mb-4 uppercase dark:text-white">55+ Compare changes66+ </h2>77+ <p>Choose any two refs to compare.</p>88+99+ <div class="flex items-center gap-2 py-4">1010+ <div>1111+ base:1212+ <select1313+ class="p-1 border max-w-32 border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700"1414+ >1515+ <optgroup1616+ label="branches ({{ len .Branches }})"1717+ class="bold text-sm"1818+ >1919+ {{ range .Branches }}2020+ <option2121+ value="{{ .Reference.Name }}"2222+ class="py-1"2323+ {{ if .IsDefault }}2424+ selected2525+ {{ end }}2626+ >2727+ {{ .Reference.Name }}2828+ </option>2929+ {{ end }}3030+ </optgroup>3131+ <optgroup label="tags ({{ len .Tags }})" class="bold text-sm">3232+ {{ range .Tags }}3333+ <option value="{{ .Reference.Name }}" class="py-1">3434+ {{ .Reference.Name }}3535+ </option>3636+ {{ else }}3737+ <option class="py-1" disabled>no tags found</option>3838+ {{ end }}3939+ </optgroup>4040+ </select>4141+ </div>4242+ {{ i "arrow-left" "w-4 h-4" }}4343+ <div>4444+ compare:4545+ <select4646+ class="p-1 border max-w-32 border-gray-200 bg-white dark:bg-gray-800 dark:text-white dark:border-gray-700"4747+ >4848+ <optgroup4949+ label="branches ({{ len .Branches }})"5050+ class="bold text-sm"5151+ >5252+ {{ range .Branches }}5353+ <option value="{{ .Reference.Name }}" class="py-1">5454+ {{ .Reference.Name }}5555+ </option>5656+ {{ end }}5757+ </optgroup>5858+ <optgroup label="tags ({{ len .Tags }})" class="bold text-sm">5959+ {{ range .Tags }}6060+ <option value="{{ .Reference.Name }}" class="py-1">6161+ {{ .Reference.Name }}6262+ </option>6363+ {{ else }}6464+ <option class="py-1" disabled>no tags found</option>6565+ {{ end }}6666+ </optgroup>6767+ </select>6868+ </div>6969+ </div>7070+{{ end }}7171+7272+{{ define "repoAfter" }}7373+ <div id="compare-diff"></div>7474+{{ end }}
+84
appview/state/repo.go
···20542054 return20552055 }20562056}20572057+20582058+func (s *State) RepoCompare(w http.ResponseWriter, r *http.Request) {20592059+ user := s.oauth.GetUser(r)20602060+ f, err := s.fullyResolvedRepo(r)20612061+ if err != nil {20622062+ log.Println("failed to get repo and knot", err)20632063+ return20642064+ }20652065+20662066+ us, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)20672067+ if err != nil {20682068+ log.Printf("failed to create unsigned client for %s", f.Knot)20692069+ s.pages.Error503(w)20702070+ return20712071+ }20722072+20732073+ branches, err := us.Branches(f.OwnerDid(), f.RepoName)20742074+ if err != nil {20752075+ s.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")20762076+ log.Println("failed to reach knotserver", err)20772077+ return20782078+ }20792079+20802080+ tags, err := us.Tags(f.OwnerDid(), f.RepoName)20812081+ if err != nil {20822082+ s.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")20832083+ log.Println("failed to reach knotserver", err)20842084+ return20852085+ }20862086+20872087+ forks, err := db.GetForksByDid(s.db, user.Did)20882088+ if err != nil {20892089+ s.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")20902090+ log.Println("failed to get forks", err)20912091+ return20922092+ }20932093+20942094+ s.pages.RepoCompare(w, pages.RepoCompareParams{20952095+ LoggedInUser: user,20962096+ RepoInfo: f.RepoInfo(s, user),20972097+ Forks: forks,20982098+ Branches: branches.Branches,20992099+ Tags: tags.Tags,21002100+ })21012101+}21022102+21032103+func (s *State) RepoCompareDiff(w http.ResponseWriter, r *http.Request) {21042104+ f, err := s.fullyResolvedRepo(r)21052105+ if err != nil {21062106+ log.Println("failed to get repo and knot", err)21072107+ return21082108+ }21092109+ user := s.oauth.GetUser(r)21102110+21112111+ rest := chi.URLParam(r, "*") // master...feature/xyz21122112+ parts := strings.SplitN(rest, "...", 2)21132113+ if len(parts) != 2 {21142114+ s.pages.Notice(w, "compare-error", "Invalid ref format.")21152115+ return21162116+ }21172117+21182118+ ref1 := parts[0]21192119+ ref2 := parts[1]21202120+21212121+ us, err := knotclient.NewUnsignedClient(f.Knot, s.config.Core.Dev)21222122+ if err != nil {21232123+ s.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")21242124+ log.Println("failed to reach knotserver", err)21252125+ return21262126+ }21272127+21282128+ formatPatch, err := us.Compare(f.OwnerDid(), f.RepoName, ref1, ref2)21292129+ if err != nil {21302130+ s.pages.Notice(w, "compare-error", "Failed to produce comparison. Try again later.")21312131+ log.Println("failed to compare", err)21322132+ return21332133+ }21342134+21352135+ s.pages.RepoCompareDiff(w, pages.RepoCompareDiffParams{21362136+ LoggedInUser: user,21372137+ RepoInfo: f.RepoInfo(s, user),21382138+ FormatPatch: *formatPatch,21392139+ })21402140+}
+11
appview/state/router.go
···118118 })119119 })120120121121+ r.Route("/compare", func(r chi.Router) {122122+ r.Get("/", s.RepoCompare)123123+124124+ // we have to wildcard here since we want to support GitHub's compare syntax125125+ // /compare/{ref1}...{ref2}126126+ // for example:127127+ // /compare/master...some/feature128128+ // /compare/master...example.com:another/feature <- this is a fork129129+ r.Get("/*", s.RepoCompareDiff)130130+ })131131+121132 r.Route("/pulls", func(r chi.Router) {122133 r.Get("/", s.RepoPulls)123134 r.With(middleware.AuthMiddleware(s.oauth)).Route("/new", func(r chi.Router) {