fix(gitlab): preserve context lines in suggestions - #3168
IsmaelMartinez merged 2 commits into
Conversation
Code Review by Qodo
1. Patch parsing is tied to publishing
|
IsmaelMartinez
left a comment
There was a problem hiding this comment.
Thanks, and the reported case is fixed: both line numbers now go out for a context-line anchor. One blocker and one point about the fake, both inline with suggestions.
| if relevant_line_in_file: | ||
| edit_type, found, source_line_no, target_file, target_line_no = self.find_in_file( | ||
| target_file, relevant_line_in_file | ||
| ) | ||
| else: | ||
| found = False |
There was a problem hiding this comment.
| if relevant_line_in_file: | |
| edit_type, found, source_line_no, target_file, target_line_no = self.find_in_file( | |
| target_file, relevant_line_in_file | |
| ) | |
| else: | |
| found = False | |
| if relevant_line_in_file: | |
| # Classify the anchor positionally from the hunk headers. A content search | |
| # stops at the first line holding the same text, which moves the anchor when | |
| # that text repeats earlier in the patch, and the body is a -0+N window that | |
| # travels with it. | |
| edit_type, found, source_line_no, target_line_no = 'addition', False, -1, 0 | |
| old_line_no = new_line_no = 0 | |
| for patch_line in (target_file.patch or '').splitlines(): | |
| if patch_line.startswith('@@'): | |
| match = self.RE_HUNK_HEADER.match(patch_line) | |
| if match: | |
| old_line_no, new_line_no = int(match.group(1)), int(match.group(3)) | |
| continue | |
| if patch_line.startswith('\\'): | |
| continue | |
| if patch_line.startswith('-'): | |
| old_line_no += 1 | |
| continue | |
| if patch_line.startswith('+'): | |
| new_line_no += 1 | |
| else: | |
| old_line_no += 1 | |
| new_line_no += 1 | |
| if new_line_no - 1 == relevant_lines_start: | |
| edit_type = 'addition' if patch_line.startswith('+') else 'context' | |
| found, source_line_no, target_line_no = True, old_line_no, new_line_no | |
| break | |
| else: | |
| found = False |
find_in_file is a substring scan that stops at the first line containing the text and ignores relevant_lines_start, so any anchor whose text repeats earlier in the patch relocates. Measured against main:
- added line 8 whose text also appears as context line 2: main sends
new_line: 8, this sendsnew_line: 2 - added line 3 whose text also appears as a deleted line: main sends
new_line: 3, this sendsold_line: 1with nonew_lineat all, so the suggestion anchors on the old file
Both are right on main today. The body is still suggestion:-0+N, computed from relevant_lines_end minus relevant_lines_start before this runs, so the replacement window travels with the anchor and Apply overwrites the wrong lines.
The suggestion is the positional shape from #3131: walk the hunk headers of target_file.patch, classify the line at relevant_lines_start from its prefix, and leave the anchor where the model put it. Your if not found: fallback below stays exactly as written. I ran it: all three cases above come out right, your own test file still passes at 9, the full suite is unchanged at 4338 and ruff is clean.
| filename = "a.py" | ||
| old_filename = "a.py" | ||
| head_file = "line1\nline2\nline3\n" | ||
| patch = "@@ -1,3 +1,3 @@\n line1\n line2\n line3\n" |
There was a problem hiding this comment.
| patch = "@@ -1,3 +1,3 @@\n line1\n line2\n line3\n" | |
| patch = "@@ -1,2 +1,3 @@\n line1\n line2\n+line3\n" |
An all-context hunk is something git never emits, so as written the fake cannot exercise the added-line path at all. This makes +line3 a real addition, consistent with head_file, and all nine tests stay green under it either way; I checked both.
It still will not catch a relocated anchor, because every line in the fake is unique. For that, head_file needs a line whose text repeats, a fourth line reading line2 say, with a row anchoring relevant_lines_start on it. I could not fold that into the suggestion because head_file is not a changed line in this diff.
Applies the 8 Sep review suggestions: walk the patch hunks instead of find_in_file so a repeated or blank anchor line keeps its position, make the fake patch a real hunk, and add the relocation test. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpThzLDt7pgLathoucBkcL
|
Code review by qodo was updated up to the latest commit 64ea566 |
|
Thanks for the fix and the test file; sorry this sat for eight days after the review. I have pushed the two 8 September suggestions to your branch as 64ea566 rather than wait longer, since #3131 was picked up elsewhere today: the positional hunk walk (without the blank-line guard, so an empty context line also gets both numbers) and the real-hunk fake, plus a test that anchors on a repeated and on a blank context line. All eight anchor shapes I tried come out right, and the suite is green on today's main. Merging once CI is green so #3131 can close; the fix stays yours. |
IsmaelMartinez
left a comment
There was a problem hiding this comment.
Carried the 8 September suggestions myself (64ea566); eight anchor shapes verified, suite green on today's main.
What changed
Why
GitLab requires both line numbers for a context-line position. Previously, /improve suggestions anchored to context lines were rejected and degraded to a general note.
Validation
Closes #3131