Skip to content

Commit fc28e14

Browse files
authored
Merge pull request #303 from netwrix/dev
Fix YAML heredoc break from unindented FOOTER lines
2 parents d61958f + 2c32ea2 commit fc28e14

1 file changed

Lines changed: 57 additions & 12 deletions

File tree

.github/workflows/claude-documentation-reviewer.yml

Lines changed: 57 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ jobs:
111111
env:
112112
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
113113
PR_NUMBER: ${{ github.event.pull_request.number }}
114+
BASE_SHA: ${{ github.event.pull_request.base.sha }}
114115
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
115116
REPO: ${{ github.repository }}
116117
run: |
@@ -121,14 +122,17 @@ jobs:
121122
import os
122123
import sys
123124
124-
FOOTER = """
125-
---
126-
127-
There are two ways to apply fixes:
128-
- View them in the comments and apply them individually or in a batch. This only applies to changes made to the file.
129-
- Reply with `@claude` here, followed by your instructions (e.g. `@claude fix all issues` or `@claude fix only the spelling errors` or `@claude fix all other existing issues`). You can use this option to fix preexisting issues.
130-
131-
Note: Automated fixes are only available for branches in this repository, not forks."""
125+
FOOTER = (
126+
"\n---\n\n"
127+
"There are two ways to apply fixes:\n"
128+
"- View them in the comments and apply them individually or in a batch."
129+
" This only applies to changes made to the file.\n"
130+
"- Reply with `@claude` here, followed by your instructions"
131+
" (e.g. `@claude fix all issues` or `@claude fix only the spelling errors`"
132+
" or `@claude fix all other existing issues`)."
133+
" You can use this option to fix preexisting issues.\n\n"
134+
"Note: Automated fixes are only available for branches in this repository, not forks."
135+
)
132136
133137
def parse_diff_to_suggestions(diff_text):
134138
suggestions = []
@@ -217,6 +221,33 @@ Note: Automated fixes are only available for branches in this repository, not fo
217221
comment['start_side'] = 'RIGHT'
218222
return comment
219223
224+
def get_pr_diff_valid_lines(base_sha, head_sha):
225+
"""Return the set of (file, line_number) in HEAD visible in the PR diff."""
226+
result = subprocess.run(
227+
['git', 'diff', '--unified=10', base_sha, head_sha],
228+
capture_output=True, text=True,
229+
)
230+
valid = set()
231+
current_file = None
232+
new_line_num = 0
233+
for line in result.stdout.split('\n'):
234+
if line.startswith('+++ b/'):
235+
current_file = line[6:]
236+
elif line.startswith('@@'):
237+
match = re.match(r'@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@', line)
238+
if match:
239+
new_line_num = int(match.group(1))
240+
elif line.startswith('+') and not line.startswith('+++'):
241+
if current_file:
242+
valid.add((current_file, new_line_num))
243+
new_line_num += 1
244+
elif line.startswith(' '):
245+
if current_file:
246+
valid.add((current_file, new_line_num))
247+
new_line_num += 1
248+
# '-' lines don't exist in HEAD, skip
249+
return valid
250+
220251
# Read the review summary Claude wrote
221252
summary_path = '/tmp/review-summary.md'
222253
if os.path.exists(summary_path):
@@ -227,14 +258,28 @@ Note: Automated fixes are only available for branches in this repository, not fo
227258
228259
review_body += FOOTER
229260
261+
pr_number = os.environ['PR_NUMBER']
262+
head_sha = os.environ['HEAD_SHA']
263+
base_sha = os.environ['BASE_SHA']
264+
repo = os.environ['REPO']
265+
230266
# Get diff of Claude's local edits vs HEAD
231267
result = subprocess.run(['git', 'diff', 'HEAD'], capture_output=True, text=True)
232268
diff_text = result.stdout
233-
suggestions = parse_diff_to_suggestions(diff_text) if diff_text.strip() else []
269+
all_suggestions = parse_diff_to_suggestions(diff_text) if diff_text.strip() else []
234270
235-
pr_number = os.environ['PR_NUMBER']
236-
head_sha = os.environ['HEAD_SHA']
237-
repo = os.environ['REPO']
271+
# Filter to only lines visible in the PR diff — GitHub rejects suggestions
272+
# on lines outside the diff context with HTTP 422.
273+
pr_valid_lines = get_pr_diff_valid_lines(base_sha, head_sha)
274+
suggestions = []
275+
for s in all_suggestions:
276+
start = s.get('start_line', s['line'])
277+
end = s['line']
278+
if all((s['path'], ln) in pr_valid_lines for ln in range(start, end + 1)):
279+
suggestions.append(s)
280+
else:
281+
print(f"Skipping out-of-diff suggestion: {s['path']} line {s['line']}")
282+
print(f"{len(suggestions)}/{len(all_suggestions)} suggestions are within the PR diff.")
238283
239284
review_payload = {
240285
'commit_id': head_sha,

0 commit comments

Comments
 (0)