diff options
Diffstat (limited to 'modules')
-rw-r--r-- | modules/git/diff.go | 30 | ||||
-rw-r--r-- | modules/git/diff_test.go | 64 | ||||
-rw-r--r-- | modules/migrations/gitea_uploader.go | 22 |
3 files changed, 94 insertions, 22 deletions
diff --git a/modules/git/diff.go b/modules/git/diff.go index 6f876e4964..6faad1c3c0 100644 --- a/modules/git/diff.go +++ b/modules/git/diff.go @@ -125,30 +125,39 @@ var hunkRegex = regexp.MustCompile(`^@@ -(?P<beginOld>[0-9]+)(,(?P<endOld>[0-9]+ const cmdDiffHead = "diff --git " -func isHeader(lof string) bool { - return strings.HasPrefix(lof, cmdDiffHead) || strings.HasPrefix(lof, "---") || strings.HasPrefix(lof, "+++") +func isHeader(lof string, inHunk bool) bool { + return strings.HasPrefix(lof, cmdDiffHead) || (!inHunk && (strings.HasPrefix(lof, "---") || strings.HasPrefix(lof, "+++"))) } // CutDiffAroundLine cuts a diff of a file in way that only the given line + numberOfLine above it will be shown // it also recalculates hunks and adds the appropriate headers to the new diff. // Warning: Only one-file diffs are allowed. -func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLine int) string { +func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLine int) (string, error) { if line == 0 || numbersOfLine == 0 { // no line or num of lines => no diff - return "" + return "", nil } + scanner := bufio.NewScanner(originalDiff) hunk := make([]string, 0) + // begin is the start of the hunk containing searched line // end is the end of the hunk ... // currentLine is the line number on the side of the searched line (differentiated by old) // otherLine is the line number on the opposite side of the searched line (differentiated by old) var begin, end, currentLine, otherLine int64 var headerLines int + + inHunk := false + for scanner.Scan() { lof := scanner.Text() // Add header to enable parsing - if isHeader(lof) { + + if isHeader(lof, inHunk) { + if strings.HasPrefix(lof, cmdDiffHead) { + inHunk = false + } hunk = append(hunk, lof) headerLines++ } @@ -157,6 +166,7 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi } // Detect "hunk" with contains commented lof if strings.HasPrefix(lof, "@@") { + inHunk = true // Already got our hunk. End of hunk detected! if len(hunk) > headerLines { break @@ -213,15 +223,19 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi } } } + err := scanner.Err() + if err != nil { + return "", err + } // No hunk found if currentLine == 0 { - return "" + return "", nil } // headerLines + hunkLine (1) = totalNonCodeLines if len(hunk)-headerLines-1 <= numbersOfLine { // No need to cut the hunk => return existing hunk - return strings.Join(hunk, "\n") + return strings.Join(hunk, "\n"), nil } var oldBegin, oldNumOfLines, newBegin, newNumOfLines int64 if old { @@ -256,5 +270,5 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi // construct the new hunk header newHunk[headerLines] = fmt.Sprintf("@@ -%d,%d +%d,%d @@", oldBegin, oldNumOfLines, newBegin, newNumOfLines) - return strings.Join(newHunk, "\n") + return strings.Join(newHunk, "\n"), nil } diff --git a/modules/git/diff_test.go b/modules/git/diff_test.go index 4258abfe50..363ff0b970 100644 --- a/modules/git/diff_test.go +++ b/modules/git/diff_test.go @@ -23,8 +23,28 @@ const exampleDiff = `diff --git a/README.md b/README.md + cut off + cut off` +const breakingDiff = `diff --git a/aaa.sql b/aaa.sql +index d8e4c92..19dc8ad 100644 +--- a/aaa.sql ++++ b/aaa.sql +@@ -1,9 +1,10 @@ + --some comment +--- some comment 5 ++--some coment 2 ++-- some comment 3 + create or replace procedure test(p1 varchar2) + is + begin +---new comment + dbms_output.put_line(p1); ++--some other comment + end; + / +` + func TestCutDiffAroundLine(t *testing.T) { - result := CutDiffAroundLine(strings.NewReader(exampleDiff), 4, false, 3) + result, err := CutDiffAroundLine(strings.NewReader(exampleDiff), 4, false, 3) + assert.NoError(t, err) resultByLine := strings.Split(result, "\n") assert.Len(t, resultByLine, 7) // Check if headers got transferred @@ -37,18 +57,50 @@ func TestCutDiffAroundLine(t *testing.T) { assert.Equal(t, "+ Build Status", resultByLine[4]) // Must be same result as before since old line 3 == new line 5 - newResult := CutDiffAroundLine(strings.NewReader(exampleDiff), 3, true, 3) + newResult, err := CutDiffAroundLine(strings.NewReader(exampleDiff), 3, true, 3) + assert.NoError(t, err) assert.Equal(t, result, newResult, "Must be same result as before since old line 3 == new line 5") - newResult = CutDiffAroundLine(strings.NewReader(exampleDiff), 6, false, 300) + newResult, err = CutDiffAroundLine(strings.NewReader(exampleDiff), 6, false, 300) + assert.NoError(t, err) assert.Equal(t, exampleDiff, newResult) - emptyResult := CutDiffAroundLine(strings.NewReader(exampleDiff), 6, false, 0) + emptyResult, err := CutDiffAroundLine(strings.NewReader(exampleDiff), 6, false, 0) + assert.NoError(t, err) assert.Empty(t, emptyResult) // Line is out of scope - emptyResult = CutDiffAroundLine(strings.NewReader(exampleDiff), 434, false, 0) + emptyResult, err = CutDiffAroundLine(strings.NewReader(exampleDiff), 434, false, 0) + assert.NoError(t, err) assert.Empty(t, emptyResult) + + // Handle minus diffs properly + minusDiff, err := CutDiffAroundLine(strings.NewReader(breakingDiff), 2, false, 4) + assert.NoError(t, err) + + expected := `diff --git a/aaa.sql b/aaa.sql +--- a/aaa.sql ++++ b/aaa.sql +@@ -1,9 +1,10 @@ + --some comment +--- some comment 5 ++--some coment 2` + assert.Equal(t, expected, minusDiff) + + // Handle minus diffs properly + minusDiff, err = CutDiffAroundLine(strings.NewReader(breakingDiff), 3, false, 4) + assert.NoError(t, err) + + expected = `diff --git a/aaa.sql b/aaa.sql +--- a/aaa.sql ++++ b/aaa.sql +@@ -1,9 +1,10 @@ + --some comment +--- some comment 5 ++--some coment 2 ++-- some comment 3` + + assert.Equal(t, expected, minusDiff) } func BenchmarkCutDiffAroundLine(b *testing.B) { @@ -69,7 +121,7 @@ func ExampleCutDiffAroundLine() { Docker Pulls + cut off + cut off` - result := CutDiffAroundLine(strings.NewReader(diff), 4, false, 3) + result, _ := CutDiffAroundLine(strings.NewReader(diff), 4, false, 3) println(result) } diff --git a/modules/migrations/gitea_uploader.go b/modules/migrations/gitea_uploader.go index 3be49b5c6c..aa1ea4bc09 100644 --- a/modules/migrations/gitea_uploader.go +++ b/modules/migrations/gitea_uploader.go @@ -6,7 +6,6 @@ package migrations import ( - "bytes" "context" "fmt" "io" @@ -802,13 +801,20 @@ func (g *GiteaLocalUploader) CreateReviews(reviews ...*base.Review) error { } var patch string - patchBuf := new(bytes.Buffer) - if err := git.GetRepoRawDiffForFile(g.gitRepo, pr.MergeBase, headCommitID, git.RawDiffNormal, comment.TreePath, patchBuf); err != nil { - // We should ignore the error since the commit maybe removed when force push to the pull request - log.Warn("GetRepoRawDiffForFile failed when migrating [%s, %s, %s, %s]: %v", g.gitRepo.Path, pr.MergeBase, headCommitID, comment.TreePath, err) - } else { - patch = git.CutDiffAroundLine(patchBuf, int64((&models.Comment{Line: int64(line + comment.Position - 1)}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines) - } + reader, writer := io.Pipe() + defer func() { + _ = reader.Close() + _ = writer.Close() + }() + go func() { + if err := git.GetRepoRawDiffForFile(g.gitRepo, pr.MergeBase, headCommitID, git.RawDiffNormal, comment.TreePath, writer); err != nil { + // We should ignore the error since the commit maybe removed when force push to the pull request + log.Warn("GetRepoRawDiffForFile failed when migrating [%s, %s, %s, %s]: %v", g.gitRepo.Path, pr.MergeBase, headCommitID, comment.TreePath, err) + } + _ = writer.Close() + }() + + patch, _ = git.CutDiffAroundLine(reader, int64((&models.Comment{Line: int64(line + comment.Position - 1)}).UnsignedLine()), line < 0, setting.UI.CodeCommentLines) var c = models.Comment{ Type: models.CommentTypeCode, |