Files
review-bot/gitea/diff.go
T
Rodin b0dc6d0c09
CI / test (pull_request) Successful in 14s
CI / review (gpt-4.1, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 23s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SONNET_REVIEW_TOKEN) (pull_request) Successful in 55s
CI / review (gpt-5, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 1m42s
fix: handle single-line hunks and no-newline markers in diff parser
- Hunk headers without comma ("@@ -1 +1 @@") now parse correctly by
  splitting on comma OR space instead of comma only
- Explicit skip for "\ No newline at end of file" lines (was already
  safe but now documents intent)
- Tests added for both edge cases (TDD: tests written first, confirmed
  failure, then fixed)

Addresses sonnet findings #1 and #2 from PR #26 review.
2026-05-01 22:10:49 -07:00

86 lines
2.0 KiB
Go

package gitea
import (
"strconv"
"strings"
)
// DiffLineRanges maps filenames to the set of new-file line numbers present in the diff.
type DiffLineRanges struct {
files map[string]map[int]bool
}
// Contains reports whether the given file+line is within the diff hunks.
func (d *DiffLineRanges) Contains(file string, line int) bool {
if d == nil || d.files == nil {
return false
}
lines, ok := d.files[file]
if !ok {
return false
}
return lines[line]
}
// ParseDiffNewLines parses a unified diff and extracts the new-file line numbers
// that appear in each hunk (both added and context lines).
func ParseDiffNewLines(diff string) *DiffLineRanges {
result := &DiffLineRanges{files: make(map[string]map[int]bool)}
var currentFile string
var newLine int
for _, line := range strings.Split(diff, "\n") {
// Track current file from +++ header
if strings.HasPrefix(line, "+++ b/") {
currentFile = strings.TrimPrefix(line, "+++ b/")
if result.files[currentFile] == nil {
result.files[currentFile] = make(map[int]bool)
}
continue
}
if strings.HasPrefix(line, "+++ /dev/null") {
currentFile = ""
continue
}
// Parse hunk header: @@ -old,count +new,count @@ or @@ -old +new @@
if strings.HasPrefix(line, "@@") && currentFile != "" {
// Extract the +N part — handle both "+10,8" and "+1" forms
parts := strings.Split(line, "+")
if len(parts) >= 2 {
// Take everything before comma or space
numStr := parts[1]
if idx := strings.IndexAny(numStr, ", "); idx != -1 {
numStr = numStr[:idx]
}
n, err := strconv.Atoi(numStr)
if err == nil {
newLine = n
}
}
continue
}
if currentFile == "" {
continue
}
// Skip diff metadata lines
if strings.HasPrefix(line, "\\") {
continue
}
// Count lines in hunk
if strings.HasPrefix(line, "+") || strings.HasPrefix(line, " ") {
result.files[currentFile][newLine] = true
newLine++
} else if strings.HasPrefix(line, "-") {
// Removed lines don't advance new line counter
continue
}
}
return result
}