Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 57 additions & 12 deletions .github/workflows/claude-documentation-reviewer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event.pull_request.number }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
REPO: ${{ github.repository }}
run: |
Expand All @@ -121,14 +122,17 @@ jobs:
import os
import sys

FOOTER = """
---

There are two ways to apply fixes:
- View them in the comments and apply them individually or in a batch. This only applies to changes made to the file.
- 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.

Note: Automated fixes are only available for branches in this repository, not forks."""
FOOTER = (
"\n---\n\n"
"There are two ways to apply fixes:\n"
"- View them in the comments and apply them individually or in a batch."
" This only applies to changes made to the file.\n"
"- 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.\n\n"
"Note: Automated fixes are only available for branches in this repository, not forks."
)

def parse_diff_to_suggestions(diff_text):
suggestions = []
Expand Down Expand Up @@ -217,6 +221,33 @@ Note: Automated fixes are only available for branches in this repository, not fo
comment['start_side'] = 'RIGHT'
return comment

def get_pr_diff_valid_lines(base_sha, head_sha):
"""Return the set of (file, line_number) in HEAD visible in the PR diff."""
result = subprocess.run(
['git', 'diff', '--unified=10', base_sha, head_sha],
capture_output=True, text=True,
)
valid = set()
current_file = None
new_line_num = 0
for line in result.stdout.split('\n'):
if line.startswith('+++ b/'):
current_file = line[6:]
elif line.startswith('@@'):
match = re.match(r'@@ -\d+(?:,\d+)? \+(\d+)(?:,\d+)? @@', line)
if match:
new_line_num = int(match.group(1))
elif line.startswith('+') and not line.startswith('+++'):
if current_file:
valid.add((current_file, new_line_num))
new_line_num += 1
elif line.startswith(' '):
if current_file:
valid.add((current_file, new_line_num))
new_line_num += 1
# '-' lines don't exist in HEAD, skip
return valid

# Read the review summary Claude wrote
summary_path = '/tmp/review-summary.md'
if os.path.exists(summary_path):
Expand All @@ -227,14 +258,28 @@ Note: Automated fixes are only available for branches in this repository, not fo

review_body += FOOTER

pr_number = os.environ['PR_NUMBER']
head_sha = os.environ['HEAD_SHA']
base_sha = os.environ['BASE_SHA']
repo = os.environ['REPO']

# Get diff of Claude's local edits vs HEAD
result = subprocess.run(['git', 'diff', 'HEAD'], capture_output=True, text=True)
diff_text = result.stdout
suggestions = parse_diff_to_suggestions(diff_text) if diff_text.strip() else []
all_suggestions = parse_diff_to_suggestions(diff_text) if diff_text.strip() else []

pr_number = os.environ['PR_NUMBER']
head_sha = os.environ['HEAD_SHA']
repo = os.environ['REPO']
# Filter to only lines visible in the PR diff — GitHub rejects suggestions
# on lines outside the diff context with HTTP 422.
pr_valid_lines = get_pr_diff_valid_lines(base_sha, head_sha)
suggestions = []
for s in all_suggestions:
start = s.get('start_line', s['line'])
end = s['line']
if all((s['path'], ln) in pr_valid_lines for ln in range(start, end + 1)):
suggestions.append(s)
else:
print(f"Skipping out-of-diff suggestion: {s['path']} line {s['line']}")
print(f"{len(suggestions)}/{len(all_suggestions)} suggestions are within the PR diff.")

review_payload = {
'commit_id': head_sha,
Expand Down
Loading