repos / git-pr

a self-hosted git collaboration server
git clone https://github.com/picosh/git-pr.git

commit
78d8ea1
parent
09798a4
author
Eric Bower
date
2025-02-02 12:14:20 -0500 EST
fix(range-diff): properly handle removed files from a patchset
5 files changed,  +107, -25
M web.go
M range_diff.go
+49, -1
 1@@ -159,9 +159,16 @@ type RangeDiffFile struct {
 2 
 3 func outputDiff(patchA, patchB *PatchRange) []*RangeDiffFile {
 4 	diffs := []*RangeDiffFile{}
 5+
 6 	for _, fileA := range patchA.Files {
 7+		found := false
 8 		for _, fileB := range patchB.Files {
 9 			if fileA.NewName == fileB.NewName {
10+				found = true
11+				// this means both files have been deleted so we should skip
12+				if fileA.NewName == "" {
13+					continue
14+				}
15 				strA := ""
16 				for _, frag := range fileA.TextFragments {
17 					for _, line := range frag.Lines {
18@@ -185,7 +192,6 @@ func outputDiff(patchA, patchB *PatchRange) []*RangeDiffFile {
19 				if !hasDiff {
20 					continue
21 				}
22-				// curDiff := DoDiff(fileA.String(), fileB.String())
23 				fp := &RangeDiffFile{
24 					OldFile: fileA,
25 					NewFile: fileB,
26@@ -194,6 +200,48 @@ func outputDiff(patchA, patchB *PatchRange) []*RangeDiffFile {
27 				diffs = append(diffs, fp)
28 			}
29 		}
30+
31+		// find files in patchA but not in patchB
32+		if !found {
33+			strA := ""
34+			for _, frag := range fileA.TextFragments {
35+				for _, line := range frag.Lines {
36+					strA += line.String()
37+				}
38+			}
39+			fp := &RangeDiffFile{
40+				OldFile: fileA,
41+				NewFile: nil,
42+				Diff:    DoDiff(strA, ""),
43+			}
44+			diffs = append(diffs, fp)
45+		}
46+	}
47+
48+	// find files in patchB not in patchA
49+	for _, fileB := range patchB.Files {
50+		found := false
51+		for _, fileA := range patchA.Files {
52+			if fileA.NewName == fileB.NewName {
53+				found = true
54+				break
55+			}
56+		}
57+
58+		if !found {
59+			strB := ""
60+			for _, frag := range fileB.TextFragments {
61+				for _, line := range frag.Lines {
62+					strB += line.String()
63+				}
64+			}
65+			fp := &RangeDiffFile{
66+				OldFile: nil,
67+				NewFile: fileB,
68+				Diff:    DoDiff("", strB),
69+			}
70+			diffs = append(diffs, fp)
71+		}
72 	}
73 
74 	return diffs
M tmpl/patchset.html
+18, -0
 1@@ -24,7 +24,11 @@
 2 
 3           {{range $patch.PatchFiles}}
 4             <div class="flex justify-between items-center">
 5+              {{if .NewName}}
 6               <a class="flex-1 word-break-word mono" href="#patch-{{$patch.ID}}-{{.NewName}}">{{.NewName}}</a>
 7+              {{else}}
 8+              <a class="flex-1 word-break-word mono" href="#patch-{{$patch.ID}}-{{.OldName}}">{{.OldName}}</a>
 9+              {{end}}
10               <div class="flex gap">
11                 <code class="pill-success">+{{.Adds}}</code>
12                 <code class="pill-admin">-{{.Dels}}</code>
13@@ -49,6 +53,7 @@
14           {{if $patch.Body}}<pre class="w-full">{{$patch.Body}}</pre>{{end}}
15 
16           {{range $patch.PatchFiles}}
17+            {{if .NewName}}
18             <details class="details-min" open="true" id="patch-{{$patch.ID}}-{{.NewName}}">
19               <summary class="group-h patch-file">
20                 <span class="mono">{{.NewName}}</span>
21@@ -60,6 +65,19 @@
22               </summary>
23               <div>{{.DiffText}}</div>
24             </details>
25+            {{else}}
26+            <details class="details-min" open="true" id="patch-{{$patch.ID}}-{{.OldName}}">
27+              <summary class="group-h patch-file">
28+                <span class="mono">{{.OldName}}</span>
29+                <a href="#patch-{{$patch.ID}}-{{.OldName}}" class="word-break-word">link</a>
30+                <div class="flex gap">
31+                  <code class="pill-success">+{{.Adds}}</code>
32+                  <code class="pill-admin">-{{.Dels}}</code>
33+                </div>
34+              </summary>
35+              <div>{{.DiffText}}</div>
36+            </details>
37+            {{end}}
38           {{end}}
39         </div>
40         <hr class="my" />
M tmpl/pr-table.html
+2, -0
 1@@ -6,6 +6,7 @@
 2       <th class="text-left">Status</th>
 3       <th class="text-left">User</th>
 4       <th class="text-left">Title</th>
 5+      <th class="text-left">Patchsets</th>
 6       <th class="text-left">Created At</th>
 7     </tr>
 8   </thead>
 9@@ -22,6 +23,7 @@
10           <code>#{{.ID}}</code>
11           <a href="{{.PrLink.Url}}">{{.PrLink.Text}}</a>
12         </td>
13+        <td><code>{{.NumPatchsets}}</code></td>
14         <td><date>{{.Date}}</date></td>
15       </tr>
16     {{else}}
M tmpl/range-diff.html
+19, -13
 1@@ -47,7 +47,7 @@
 2       <div class="group">
 3         {{range .PatchsetData.RangeDiff}}
 4           <div id="{{.Header.OldIdx}}-{{.Header.NewIdx}}">
 5-            <div>
 6+            <div class="mb">
 7               <code class='{{if eq .Type "rm"}}pill-admin{{else if eq .Type "add"}}pill-success{{else if eq .Type "diff"}}pill-review{{end}}'>
 8                 {{.Header}}
 9               </code>
10@@ -58,15 +58,18 @@
11                 {{range .Files}}
12                   <div class="flex gap">
13                     <div class="flex-1" style="width: 48%;">
14-                      <div>{{.OldFile.NewName}}</div>
15-                      <pre>{{- range .Diff -}}
16-                        {{- if eq .InnerType "insert" -}}
17+                      <div>
18+                        {{if .OldFile.OldName}}<code>{{.OldFile.OldName}}</code>{{end}}
19+                        {{if .OldFile.NewName}}<code>{{.OldFile.NewName}}</code>{{end}}
20+                      </div>
21+                      <pre class="m-0">{{- range .Diff -}}
22+                        {{- if eq .OuterType "delete" -}}
23+                          <span style="background-color: tomato;">{{.Text}}</span>
24+                        {{- else if eq .OuterType "insert" -}}
25+                        {{- else if eq .InnerType "insert" -}}
26                           <span style="color: limegreen;">{{.Text}}</span>
27                         {{- else if eq .InnerType "delete" -}}
28                           <span style="color: tomato;">{{.Text}}</span>
29-                        {{- else if eq .OuterType "delete" -}}
30-                          <span style="background-color: tomato;">{{.Text}}</span>
31-                        {{- else if eq .OuterType "insert" -}}
32                         {{- else -}}
33                           <span>{{.Text}}</span>
34                         {{- end -}}
35@@ -74,15 +77,18 @@
36                     </div>
37 
38                     <div class="flex-1" style="width: 48%;">
39-                      <div>{{.NewFile.NewName}}</div>
40-                      <pre>{{- range .Diff -}}
41-                        {{- if eq .InnerType "insert" -}}
42+                      <div>
43+                        {{if .NewFile.OldName}}<code>{{.NewFile.OldName}}</code>{{end}}
44+                        {{if .NewFile.NewName}}<code>{{.NewFile.NewName}}</code>{{end}}
45+                      </div>
46+                      <pre class="m-0">{{- range .Diff -}}
47+                        {{- if eq .OuterType "insert" -}}
48+                          <span style="background-color: limegreen;">{{.Text}}</span>
49+                        {{- else if eq .OuterType "delete" -}}
50+                        {{- else if eq .InnerType "insert" -}}
51                           <span style="color: limegreen;">{{.Text}}</span>
52                         {{- else if eq .InnerType "delete" -}}
53                           <span style="color: tomato;">{{.Text}}</span>
54-                        {{- else if eq .OuterType "insert" -}}
55-                          <span style="background-color: limegreen;">{{.Text}}</span>
56-                        {{- else if eq .OuterType "delete" -}}
57                         {{- else -}}
58                           <span>{{.Text}}</span>
59                         {{- end -}}
M web.go
+19, -11
 1@@ -203,6 +203,12 @@ func getPrTableData(web *WebCtx, prs []*PatchRequest, query url.Values) ([]*PrLi
 2 			continue
 3 		}
 4 
 5+		ps, err := web.Pr.GetPatchsetsByPrID(curpr.ID)
 6+		if err != nil {
 7+			web.Logger.Error("cannot get patchsets for pr", "err", err)
 8+			continue
 9+		}
10+
11 		if hasFilter {
12 			if status != "" {
13 				if status != curpr.Status {
14@@ -241,9 +247,10 @@ func getPrTableData(web *WebCtx, prs []*PatchRequest, query url.Values) ([]*PrLi
15 				Url:  template.URL(fmt.Sprintf("/prs/%d", curpr.ID)),
16 				Text: curpr.Name,
17 			},
18-			DateOrig: curpr.CreatedAt,
19-			Date:     curpr.CreatedAt.Format(web.Backend.Cfg.TimeFormat),
20-			Status:   curpr.Status,
21+			NumPatchsets: len(ps),
22+			DateOrig:     curpr.CreatedAt,
23+			Date:         curpr.CreatedAt.Format(web.Backend.Cfg.TimeFormat),
24+			Status:       curpr.Status,
25 		}
26 		prdata = append(prdata, prls)
27 	}
28@@ -306,14 +313,15 @@ type MetaData struct {
29 
30 type PrListData struct {
31 	UserData
32-	RepoNs   string
33-	RepoLink LinkData
34-	PrLink   LinkData
35-	Title    string
36-	ID       int64
37-	DateOrig time.Time
38-	Date     string
39-	Status   string
40+	RepoNs       string
41+	RepoLink     LinkData
42+	PrLink       LinkData
43+	Title        string
44+	NumPatchsets int
45+	ID           int64
46+	DateOrig     time.Time
47+	Date         string
48+	Status       string
49 }
50 
51 func userDetailHandler(w http.ResponseWriter, r *http.Request) {