Skip to content

Conversation

@mattwalsh
Copy link
Collaborator

No description provided.

@github-actions
Copy link

github-actions bot commented Nov 19, 2025

Review updated until commit 589ed46

Description

  • Introduces AI-powered PR review system supporting Gemini and Claude CLI

  • Adds core wrapper script for running AI tools with verdict checking

  • Implements GitHub Actions workflows for automated code review

  • Provides Docker testing environment and utility modules

Changes walkthrough

Relevant files
Enhancement
7 files
ai_cli_wrapper.py
Core wrapper for running Gemini/Claude CLI with verdict checking
+115/-0 
git_helpers.py
Git utility functions for SHA resolution and merge base computation
+34/-0   
pr_preflight_launcher.py
Main launcher orchestrating PR review process and AI backend selection
+151/-0 
utils.py
Utility functions for environment variables, directory creation, and
file operations
+34/-0   
proxy.js
Proxy handler for transforming AI CLI requests                     
+29/-0   
claude-code-review.yml
GitHub Actions workflow for Claude-based automated PR reviews
+131/-0 
gemini-cli-review.yml
GitHub Actions workflow for Gemini-based automated PR reviews
+85/-0   
Tests
4 files
review_test.json
Test data for PR review workflow testing                                 
+11/-0   
Dockerfile
Docker container setup for testing AI CLI review system   
+25/-0   
build_ai_cli_docker
Docker build script for AI CLI test environment                   
+5/-0     
run_ai_cli_docker
Docker run script for AI CLI testing with volume mounting
+6/-0     

PR Reviewer Guide

Here are some key observations to aid the review process:

🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review
Type annotation and string formatting issues

Line 22 has incorrect type annotation 'tool: None,' which should be 'tool: str | None'. Lines 103 and 108 have string formatting issues where f-string syntax is missing for variable interpolation. Line 38 has a missing closing quote in the error message string.

tool_args : list[str],
verdict_marker: str, 
output_dir: Path | str, 
timeout_seconds: int = 180
) -> int:


"""
Run Gemini / Claude CLI with the given prompt, check for verdict, and write outputs.
Returns an exit code: 0 (success), 3 (review failed), 4 (parsing error), 1/2 (errors).
"""
OUTPUT_DIR = Path(output_dir)
VERDICT_MARKER = verdict_marker.strip().upper()
ensure_dir(OUTPUT_DIR)

if tool == None:
   write_to_path(OUTPUT_DIR, "error.txt", f"Error (Exit 1 - no tool specified")
   return 1

try:
   # Invoke CLI; pass prompt as a single argument
   safety_instructions = (
       "CRITICAL RULE: If a tool execution fails, "
       "OR if I have exceeded my API quote, DO NOT retry. "
       "Stop immediately and report the error."
   )

   prompt = f"{safety_instructions}\n\n{prompt}"

   result = subprocess.run(
      [tool] + tool_args + [prompt],
      capture_output=True,
      text=True,
      timeout=timeout_seconds,
      check=False,
   )

   # Combine stdout and stderr for complete output
   full_output = result.stdout
   if result.stderr:
      full_output += f"\n\n--- STDERR ---\n{result.stderr}"

   # --- Phase 1: Check for Tool/API Failure (Exit Codes 1 or 2) ---
   if result.returncode != 0:
      error_text = (result.stderr or result.stdout or "").lower()
      # Try to detect API-ish errors
      if any(phrase in error_text for phrase in ["rate limit", "too many requests", "quota", "api error", "unauthorized", "permission"]):
         write_to_path(OUTPUT_DIR, "error.txt", f"API Error (Exit 2):\n{full_output}")
         return 2

      # All other subprocess errors (Exit 1)
      write_to_path(OUTPUT_DIR, "error.txt", f"Error (Exit 1 - Subprocess failed with code {result.returncode}):\n{full_output}")
      return 1

   # --- Phase 2: Tool Success - Analyze Output (Exit Codes 0, 3, or 4) ---
   write_to_path(OUTPUT_DIR, "success_raw_output.txt", full_output)

   # Look for the verdict marker
   verdict_line = next(
      (line.strip().upper() for line in full_output.splitlines() if line.strip().upper().startswith(VERDICT_MARKER)),
      None
   )

   if verdict_line is None:
      # Verdict marker not found
      write_to_path(OUTPUT_DIR, "error.txt", f"Parsing Error (Exit 4): Verdict marker '{VERDICT_MARKER}' not found in output.")
      return 4

   # Check the verdict
   if "PASSED" in verdict_line:
      write_to_path(OUTPUT_DIR, "review_verdict.txt", "VERDICT: PASSED")
      return 0
   elif "FAILED" in verdict_line:
      write_to_path(OUTPUT_DIR, "review_verdict.txt", "VERDICT: FAILED")
      return 3
   else:
      # Marker found, but value is ambiguous
      write_to_path(OUTPUT_DIR, "error.txt", f"Parsing Error (Exit 4): Found verdict line but value is ambiguous: {verdict_line}")
      return 4

except subprocess.TimeoutExpired:
   error_msg = "{tool} command timed out after {timeout_seconds} seconds"
   write_to_path(OUTPUT_DIR, "error.txt", error_msg)
   return 1

except FileNotFoundError:
   error_msg = "Error: '{tool}' command not found. Is it installed and in PATH?"
Code duplication and formatting

Line 123 contains duplicate 'ls' command in the ok_commands list. Line 124 has inconsistent formatting in the comment with missing space after comma.

ok_commands = ["git", "ls", "grep", "ls","stat"]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants