fix: multiline comment invalidation (#12950)

Found issues during the process of invalidation of a multiline comment (link to #12582):
* Update a line in the middle of the comment
* Update/Delete the last line of the comment

No problem with:
* Deleting a line in the middle of the comment
* Update/Delete the first line of the comment

I added all these cases in the pull_review_test.go

### Tests for Go changes

- I added test coverage for Go changes...
  - [X] in their respective `*_test.go` for unit tests.
- I ran...
  - [X] `make pr-go` before pushing

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/12950
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
This commit is contained in:
steven.guiheux
2026-06-09 03:07:56 +02:00
committed by Mathieu Fenniak
parent c2dcdc9ba7
commit 3dc2b52b5f
4 changed files with 242 additions and 5 deletions
+47
View File
@@ -278,6 +278,53 @@ func CutDiffAroundLine(originalDiff io.Reader, line int64, old bool, numbersOfLi
return strings.Join(newHunk, "\n"), nil
}
// PatchRightSideContent parses a unified diff patch (such as a stored code-comment
// Patch) and returns the content of each line on the right (new) side, keyed by its
// new line number. Added ('+') and context (' ') lines are included; removed ('-')
// lines and the "\ No newline at end of file" marker are skipped. It lets callers
// recover the file content captured when a comment was created, to detect whether
// the commented lines were changed afterwards.
func PatchRightSideContent(patch string) map[int64]string {
result := make(map[int64]string)
scanner := bufio.NewScanner(strings.NewReader(patch))
scanner.Buffer(make([]byte, 0, 64*1024), 4*1024*1024)
var rightLine int64
inHunk := false
for scanner.Scan() {
line := scanner.Text()
if strings.HasPrefix(line, "@@") {
submatches := hunkRegex.FindStringSubmatch(line)
if submatches == nil {
inHunk = false
continue
}
for i, name := range hunkRegex.SubexpNames() {
if name == "beginNew" {
rightLine, _ = strconv.ParseInt(submatches[i], 10, 64)
}
}
inHunk = rightLine > 0
continue
}
if !inHunk || len(line) == 0 {
continue
}
switch line[0] {
case '+', ' ':
result[rightLine] = line[1:]
rightLine++
case '-', '\\':
// '-' is left-only; '\' is the "no newline at end of file" marker
break
default:
// a non-hunk line (e.g. the next "diff --git" header); stop this hunk
inHunk = false
}
}
return result
}
var ErrLineNotFound = errors.New("line not found in diff")
type LinePlacement struct {