Skip to content

chore: bump mdast-util-to-hast from 13.1.0 to 13.2.1 #1202

chore: bump mdast-util-to-hast from 13.1.0 to 13.2.1

chore: bump mdast-util-to-hast from 13.1.0 to 13.2.1 #1202

Workflow file for this run

name: Analyze PR Diff with LLM
on:
pull_request:
types: [opened, synchronize]
branches:
- "**"
# Add permissions needed to comment on PRs
permissions:
contents: read
pull-requests: write
issues: write
jobs:
analyze-diff:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Add requirements.txt file
run: |
echo "google-generativeai==0.8.4" > requirements.txt
echo "code2prompt==0.8.1" >> requirements.txt
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Cache Python dependencies
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Get PR diff
id: get-diff
run: |
# Get the PR diff and save it to a file
git diff ${{ github.event.pull_request.base.sha }} ${{ github.event.pull_request.head.sha }} > pr_diff.txt
echo "diff_size=$(stat -c%s pr_diff.txt)" >> $GITHUB_OUTPUT
- name: Create Python analysis script
run: |
cat > analyze_pr.py << 'EOFPY'
import sys
import os
import google.generativeai as genai
import code2prompt
from pathlib import Path
import tempfile
from typing import Optional, List
def get_codebase(
path: str,
exclude_patterns: Optional[List[str]] = None,
filter_patterns: Optional[List[str]] = None,
respect_gitignore: bool = True,
suppress_comments: bool = False,
add_line_numbers: bool = True
) -> str:
"""
Generate a comprehensive prompt from a codebase using Code2Prompt functionality.
Args:
path: Path to the directory or file to process
exclude_patterns: List of patterns to exclude (e.g. ["**/node_modules/**", "**/.git/**"])
filter_patterns: List of patterns to include (e.g. ["**.py", "**.js"])
respect_gitignore: Whether to respect .gitignore rules
suppress_comments: Whether to strip comments from the code
add_line_numbers: Whether to add line numbers to source code blocks
Returns:
String representation of the codebase in Markdown format
"""
from code2prompt.core.processor import CodebaseProcessor
from code2prompt.core.file_handler import FileHandler
from code2prompt.utils.token_counter import count_tokens
# Set default exclude patterns if none provided
if exclude_patterns is None:
exclude_patterns = ["**/node_modules/**", "**/.git/**", "**/__pycache__/**", "**/.venv/**"]
# Convert string path to Path object
path_obj = Path(path).resolve()
# Determine gitignore path if respecting gitignore
gitignore_path = None
if respect_gitignore:
gitignore_file = path_obj / ".gitignore" if path_obj.is_dir() else path_obj.parent / ".gitignore"
if gitignore_file.exists():
gitignore_path = str(gitignore_file)
# Initialize file handler with the given configurations
file_handler = FileHandler(
paths=[str(path_obj)],
gitignore_path=gitignore_path,
filter_patterns=filter_patterns,
exclude_patterns=exclude_patterns,
case_sensitive=False
)
# Process the codebase
processor = CodebaseProcessor(
file_handler=file_handler,
suppress_comments=suppress_comments,
add_line_numbers=add_line_numbers,
wrap_code_blocks=True
)
# Generate the prompt
codebase_representation = processor.generate_prompt()
return codebase_representation
# Set up Gemini API with your API key
GEMINI_API_KEY = os.environ.get("CODE_REVIEW_GEMINI_API_KEY")
if not GEMINI_API_KEY:
print("Error: GEMINI_API_KEY environment variable not set")
sys.exit(1)
# Configure the Gemini API
genai.configure(api_key=GEMINI_API_KEY)
# Function to call Gemini directly
def query_gemini(prompt, model="gemini-2.0-flash-001"):
"""Send a prompt to Gemini and get a response"""
try:
model = genai.GenerativeModel(model)
response = model.generate_content(prompt)
return response.text
except Exception as e:
print(f"Error calling Gemini API: {str(e)}")
return f"Error generating analysis: {str(e)}"
# Read the diff file
with open('pr_diff.txt', 'r') as f:
diff_content = f.read()
# Get the entire codebase
try:
print("Gathering codebase content...")
codebase_content = get_codebase(".")
print("Codebase content gathered successfully.")
except Exception as e:
print(f"Error gathering codebase: {str(e)}")
codebase_content = "Error: Could not retrieve codebase content."
# Get environment variables for PR info
github_repo = os.environ.get('GITHUB_REPOSITORY', 'Unknown repository')
pr_number = os.environ.get('PR_NUMBER', 'Unknown PR')
pr_title = os.environ.get('PR_TITLE', 'Unknown title')
# Prepare prompt for the LLM
prompt = f"""
You are a code reviewer analyzing a pull request. Provide a concise, actionable review that helps developers quickly understand the key points to consider.
You will be provided with both the diff and the entire codebase for context.
Pull Request: {github_repo}/pull/{pr_number}
Title: {pr_title}
DIFF:
```
{diff_content}
```
CODEBASE:
{codebase_content}
Please provide a brief review in the following format:
## Summary
[2-3 sentences maximum describing the main changes]
## Key Points to Review
- List 2-3 specific areas that need careful attention
- Focus on potential issues that could impact functionality or maintainability, and suggest improvements for each issue identified
- Include any security considerations (only if there are any)
## Style & Consistency
- Only include this section if there are notable deviations from the existing codebase style
- List specific suggestions for maintaining consistency
Keep the review concise and actionable. Focus on the most important points that would benefit from human review.
"""
# Send to LLM and get analysis
print("Sending to LLM for analysis...")
analysis = query_gemini(prompt)
# Print the analysis
print("\n--- LLM ANALYSIS OF PR DIFF ---\n")
print(analysis)
print("\n--- END OF ANALYSIS ---\n")
# Save analysis to a file for GitHub comment creation
with open('llm_analysis.md', 'w') as f:
f.write(analysis)
EOFPY
- name: Analyze diff with LLM
env:
CODE_REVIEW_GEMINI_API_KEY: ${{ secrets.CODE_REVIEW_GEMINI_API_KEY }}
GITHUB_REPOSITORY: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
PR_TITLE: ${{ github.event.pull_request.title }}
run: python analyze_pr.py
- name: Add LLM analysis as PR comment
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const fs = require('fs');
const analysis = fs.readFileSync('llm_analysis.md', 'utf8');
// Get the PR number from the event
const prNumber = ${{ github.event.pull_request.number }};
// Search for existing comments from our bot
const comments = await github.rest.issues.listComments({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100
});
// Find our bot's comment by looking for the specific header
const botComment = comments.data.find(comment =>
comment.body.startsWith('## LLM Analysis of PR Changes')
);
if (botComment) {
// Update existing comment
await github.rest.issues.updateComment({
comment_id: botComment.id,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## LLM Analysis of PR Changes\n\n${analysis}`
});
} else {
// Create new comment if none exists
await github.rest.issues.createComment({
issue_number: prNumber,
owner: context.repo.owner,
repo: context.repo.repo,
body: `## LLM Analysis of PR Changes\n\n${analysis}`
});
}