DEV Community

ZNY
ZNY

Posted on

DEV.TO ARTICLE 49: Automated Code Review with Claude: A Complete GitHub Integration Guide

Target Keyword: "automated code review claude github integration"
Tags: github,code-review,ai,programming,developer-tools
Type: Tutorial


Content

Automated Code Review with Claude: A Complete GitHub Integration Guide

Manual code review doesn't scale. AI-powered automated review catches issues before humans look at code. Here's how to integrate Claude into your GitHub code review workflow.

GitHub Actions Setup

# .github/workflows/claude-review.yml
name: Claude Code Review

on:
  pull_request:
    types: [opened, synchronize]
  push:
    branches: [main]

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Run Claude Review
        uses: ./review-action
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          OFOX_API_KEY: ${{ secrets.OFOX_API_KEY }}
Enter fullscreen mode Exit fullscreen mode

The Review Action

#!/usr/bin/env python3
"""
GitHub Action for Claude-powered code review.
"""
import os
import json
import subprocess
from github import Github

def get_pr_diff(repo, pr_number):
    """Get the diff of a pull request."""
    pr = repo.get_pull(pr_number)
    return pr.get_files()

def call_claude_review(diff_content, api_key):
    """Call Claude to review the diff."""
    import httpx
    import asyncio

    async def review():
        async with httpx.AsyncClient(timeout=120.0) as client:
            response = await client.post(
                "https://api.ofox.ai/v1/chat/completions",
                headers={
                    "Authorization": f"Bearer {api_key}",
                    "Content-Type": "application/json"
                },
                json={
                    "model": "claude-3-5-sonnet-20241022",
                    "messages": [{
                        "role": "user",
                        "content": f"""You are an expert code reviewer. Review this code diff and provide feedback.

Focus on:
1. Bugs and logic errors
2. Security vulnerabilities
3. Performance issues
4. Code quality and best practices
5. Potential edge cases

Format your response as:
## Summary
[One sentence summary]

## Issues Found
- [Issue description] (Line X)
- ...

## Suggestions
- [Suggestion]

## Approval Status
APPROVE / REQUEST_CHANGES / COMMENT

Diff:
{diff_content}"""
                    }],
                    "max_tokens": 2000,
                    "temperature": 0.3
                }
            )
            return response.json()["choices"][0]["message"]["content"]

    return asyncio.run(review())

def post_review_comment(github_token, repo_name, pr_number, review_body):
    """Post review as a PR comment."""
    g = Github(github_token)
    repo = g.get_repo(repo_name)
    pr = repo.get_pull(pr_number)
    pr.create_issue_comment(review_body)

def main():
    github_token = os.environ["GITHUB_TOKEN"]
    api_key = os.environ["OFOX_API_KEY"]

    # Get context from GitHub
    event_path = os.environ["GITHUB_EVENT_PATH"]
    with open(event_path) as f:
        event = json.load(f)

    repo_name = os.environ["GITHUB_REPOSITORY"]
    pr_number = event.get("pull_request", {}).get("number")

    if not pr_number:
        print("Not a PR event, skipping")
        return

    # Get changed files
    g = Github(github_token)
    repo = g.get_repo(repo_name)
    pr = repo.get_pull(pr_number)

    diff_text = ""
    for file in pr.get_files():
        diff_text += f"\n### {file.filename}\n"
        diff_text += f"```
{% endraw %}
diff\n{file.patch}\n
{% raw %}
```\n"

    # Get Claude's review
    review = call_claude_review(diff_text, api_key)

    # Post comment
    post_review_comment(github_token, repo_name, pr_number, review)
    print("Review posted successfully")

if __name__ == "__main__":
    main()
Enter fullscreen mode Exit fullscreen mode

Handling Large Diffs

def split_diff_for_review(files, max_tokens=8000):
    """Split large diffs into reviewable chunks."""
    chunks = []
    current_chunk = []
    current_size = 0

    for file in files:
        file_size = len(file.patch or "")

        if current_size + file_size > max_tokens:
            chunks.append(current_chunk)
            current_chunk = [file]
            current_size = file_size
        else:
            current_chunk.append(file)
            current_size += file_size

    if current_chunk:
        chunks.append(current_chunk)

    return chunks
Enter fullscreen mode Exit fullscreen mode

Security Scanning Integration

# .github/workflows/security-review.yml
name: Security + AI Review

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Run Semgrep
        run: |
          pip install semgrep
          semgrep --config=auto --json > semgrep-results.json .

      - name: Claude Security Review
        env:
          SEMGREP_RESULTS: semgrep-results.json
          OFOX_API_KEY: ${{ secrets.OFOX_API_KEY }}
        run: |
          python -c "
          import os, json
          results = json.load(open('$SEMGREP_RESULTS'))

          # Format security findings
          findings = '\n'.join([
            f'- {r[\"check_id\"]}: {r[\"message\"]} at {r[\"path\"]}:{r[\"start\"][\"line\"]}'
            for r in results.get('results', [])[:20]
          ])

          # Send to Claude for analysis
          import httpx
          async def analyze():
            async with httpx.AsyncClient() as client:
              resp = await client.post(
                'https://api.ofox.ai/v1/chat/completions',
                headers={'Authorization': 'Bearer $OFOX_API_KEY'},
                json={
                  'model': 'claude-3-5-sonnet-20241022',
                  'messages': [{
                    'role': 'user',
                    'content': f'Analyze these security findings and prioritize by severity:\n{findings}'
                  }]
                }
              )
              print(resp.json()['choices'][0]['message']['content'])
          import asyncio
          asyncio.run(analyze())
          "
Enter fullscreen mode Exit fullscreen mode

Review Summary Dashboard

def create_review_dashboard(repo_name, reviews):
    """Generate a markdown summary of all reviews."""
    summary = f"""
# AI Code Review Summary

**Repository:** {repo_name}
**Date:** {datetime.now().strftime('%Y-%m-%d')}

## Stats
- Total PRs reviewed: {len(reviews)}
- Issues found: {sum(r.issue_count for r in reviews)}
- Suggestions made: {sum(r.suggestion_count for r in reviews)}

## Recent Reviews
"""
    for review in reviews[-10:]:
        summary += f"""
### PR #{review.pr_number}: {review.pr_title}
- Issues: {review.issue_count}
- Suggestions: {review.suggestion_count}
- Status: {review.approval_status}
"""
    return summary
Enter fullscreen mode Exit fullscreen mode

Getting Started

Power your code review with Claude via ofox.ai — their API provides reliable, fast responses perfect for automated code review workflows.

👉 Get started with ofox.ai


This article contains affiliate links.


Tags: github,code-review,ai,programming,developer-tools
Canonical URL: https://dev.to/zny10289

Top comments (0)