feat: local git checkout for PR code review with real diff
- Add git_local.py: fetch, checkout PR branch, generate git diff against target, restore branch after review - Update fetch_pr_details to use local git diff when REPOS_BASE_DIR is set, with fallback to AzDo iteration API - Update run_code_review to restore repo to target branch after review - Refine Claude review prompt to only comment on diff changes, not pre-existing code - Update README: WSL venv gotcha, local git checkout flow, flow diagram
This commit is contained in:
71
README.md
71
README.md
@@ -51,7 +51,7 @@ interactive notifications.
|
||||
|---------|-------------|
|
||||
| **PR Discovery** | Webhook-based (push) or polling-based (pull) — or both |
|
||||
| **Auto-Create Jira Ticket** | When PR branch has no ticket ID, Claude generates summary + description and creates a Jira Story |
|
||||
| **AI Code Review** | Claude Code CLI reviews PRs with full repo context (Read/Glob/Grep), using your subscription |
|
||||
| **AI Code Review** | Claude Code CLI reviews PRs on the checked-out PR branch with full repo context (Read/Glob/Grep), using real `git diff` |
|
||||
| **CI/CD Integration** | Triggers CI builds after merge, polls for completion, handles CD release approval gates |
|
||||
| **Slack Interactive** | Approval requests with [Approve]/[Cancel] buttons, CI/CD status notifications |
|
||||
| **Human-in-the-loop** | 5 interrupt points where operator confirmation is required before destructive actions |
|
||||
@@ -120,7 +120,7 @@ All configuration is via environment variables. See `.env.example` for the full
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `REPOS_BASE_DIR` | `""` | Base dir with Billo repos (e.g., `/c/Users/yaoji/git/Billo`) |
|
||||
| `REPOS_BASE_DIR` | `""` | Base dir with Billo repos (e.g., `/home/kai/git/billo`). Each repo must be cloned with its AzDo name as the directory name. |
|
||||
| `WATCHED_REPOS` | `""` | Comma-separated repos to poll (e.g., `Billo.Platform.Payment,Billo.Platform.Document.DocumentAnalyser`) |
|
||||
| `PR_POLL_ENABLED` | `False` | Enable periodic PR polling |
|
||||
| `PR_POLL_INTERVAL_SECONDS` | `300` | Polling interval (5 min) |
|
||||
@@ -177,6 +177,11 @@ All configuration is via environment variables. See `.env.example` for the full
|
||||
|
||||
```
|
||||
parse_webhook -> fetch_pr_details -> route_after_fetch
|
||||
| |
|
||||
| +-- (local repo available?)
|
||||
| yes -> git fetch + checkout PR branch + git diff
|
||||
| no -> AzDo iteration API (file list only)
|
||||
|
|
||||
|-- merged -----------------> calculate_version -> update_staging -> CI build -> END
|
||||
|-- active_with_ticket -----> move_jira_code_review -+
|
||||
|-- active_no_ticket -------> auto_create_ticket ----+
|
||||
@@ -184,6 +189,7 @@ parse_webhook -> fetch_pr_details -> route_after_fetch
|
||||
run_code_review -> evaluate_review
|
||||
|-- approve -> [Slack: Merge?] -> merge_pr
|
||||
|-- request_changes -> notify -> END
|
||||
-> restore branch to develop
|
||||
-> Jira transitions -> calculate_version
|
||||
-> update_staging -> CI build -> notify -> END
|
||||
```
|
||||
@@ -311,6 +317,7 @@ src/release_agent/
|
||||
jira.py # Jira REST client (transitions + create_issue)
|
||||
slack.py # Slack dual-mode (webhook + Web API)
|
||||
claude_review.py # Claude Code CLI (review + ticket generation)
|
||||
git_local.py # Local git ops (fetch, checkout PR branch, diff)
|
||||
_http.py, _retry.py # Shared helpers
|
||||
services/
|
||||
pr_poller.py # Background PR polling loop
|
||||
@@ -340,32 +347,47 @@ The app runs best on **WSL (Ubuntu)** because:
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
# 1. Start PostgreSQL (from Windows or WSL)
|
||||
cd /mnt/c/Users/yaoji/git/Billo/billo-release-agent
|
||||
# 1. Clone the project to WSL native filesystem (NOT /mnt/c/)
|
||||
cd ~/git/billo
|
||||
git clone <repo-url> billo-release-agent
|
||||
cd billo-release-agent
|
||||
|
||||
# 2. Start PostgreSQL (from Windows or WSL)
|
||||
docker compose up -d db
|
||||
|
||||
# 2. Install uv in WSL (if needed)
|
||||
# 3. Install uv in WSL (if needed)
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
export PATH="$HOME/.local/bin:$PATH"
|
||||
|
||||
# 3. Install dependencies
|
||||
# 4. Create venv and install dependencies
|
||||
# IMPORTANT: Run from the WSL-native path, not /mnt/c/.
|
||||
# If .venv was created from /mnt/c/, delete and recreate:
|
||||
# rm -rf .venv && uv venv --python python3.12
|
||||
uv sync --all-extras
|
||||
|
||||
# 4. Configure .env
|
||||
# 5. Configure .env
|
||||
# Key settings:
|
||||
# CLAUDE_CMD=claude (not claude.cmd — WSL finds it via PATH)
|
||||
# REPOS_BASE_DIR=/mnt/c/Users/yaoji/git/Billo
|
||||
# PR_POLL_ENABLED=False (disable during dev to avoid noise)
|
||||
# SLACK_WEBHOOK_URL= (leave empty during dev)
|
||||
# CLAUDE_CMD=claude
|
||||
# REPOS_BASE_DIR=~/git/billo (WSL native path, not /mnt/c/)
|
||||
# PR_POLL_ENABLED=False (disable during dev to avoid noise)
|
||||
# SLACK_WEBHOOK_URL= (leave empty during dev)
|
||||
|
||||
# 5. Start the server
|
||||
# 6. Start the server
|
||||
uv run uvicorn release_agent.main:app --host 0.0.0.0 --port 8080
|
||||
|
||||
# 6. Test
|
||||
# 7. Test
|
||||
curl http://localhost:8080/status
|
||||
curl -X POST http://localhost:8080/manual/pr/10443
|
||||
```
|
||||
|
||||
### Important: venv Must Be Created from WSL Path
|
||||
|
||||
If the `.venv` was created while the working directory was `/mnt/c/...`, the
|
||||
uvicorn shebang will point to the Windows-mounted path. This causes the server
|
||||
to load stale code from the Windows filesystem instead of your WSL edits.
|
||||
|
||||
To fix: `rm -rf .venv && uv venv --python python3.12 && uv sync --all-extras`
|
||||
|
||||
### Windows-only (Fallback)
|
||||
|
||||
If you must run on Windows directly, use the provided `run.py` script which sets
|
||||
@@ -378,13 +400,22 @@ uv run python run.py
|
||||
Note: Claude CLI subprocess may return empty stdout on Windows due to event loop
|
||||
incompatibility. WSL is the recommended approach.
|
||||
|
||||
### Performance Note: WSL + /mnt/c
|
||||
### Local Git Checkout for Code Review
|
||||
|
||||
Claude Code CLI with `--allowedTools Read,Glob,Grep` on `/mnt/c` (Windows filesystem
|
||||
mounted in WSL) is very slow. For faster code reviews, either:
|
||||
When `REPOS_BASE_DIR` is set and the repo is cloned locally, the agent will:
|
||||
|
||||
1. **Clone repos to WSL native filesystem** (`~/git/Billo/`) and set `REPOS_BASE_DIR=~/git/Billo`
|
||||
2. **Remove `--allowedTools`** so Claude only reviews the diff text (faster but less thorough)
|
||||
1. `git fetch origin` to get the latest remote state
|
||||
2. `git checkout` the PR source branch
|
||||
3. `git diff origin/develop...HEAD` to generate a real diff (not just file names)
|
||||
4. Run Claude Code CLI with `cwd` set to the repo on the PR branch
|
||||
5. `git checkout develop` to restore the branch after review
|
||||
|
||||
This gives Claude full codebase context on the actual PR branch, producing much
|
||||
more thorough reviews than the AzDo iteration API (which only returns file paths).
|
||||
|
||||
**Performance**: Clone repos to WSL native filesystem (`~/git/billo/`), not
|
||||
`/mnt/c/`. Claude Code CLI with `--allowedTools Read,Glob,Grep` on `/mnt/c`
|
||||
is very slow (10+ minutes per review vs seconds on native fs).
|
||||
|
||||
## Slack App Setup
|
||||
|
||||
@@ -409,6 +440,8 @@ To use interactive buttons (optional — REST API approvals still work without i
|
||||
- Claude CLI ticket generation (tested: returns structured JSON)
|
||||
- Claude CLI code review (tested: returns structured JSON with verdict + issues)
|
||||
- PR review comments posted to Azure DevOps (inline + summary)
|
||||
- Local git checkout + real `git diff` for PR code review (with fallback to AzDo API)
|
||||
- Branch restore to develop after review completes
|
||||
- Node type annotations fixed (`RunnableConfig` instead of `dict`)
|
||||
|
||||
### Known Issues
|
||||
@@ -416,11 +449,13 @@ To use interactive buttons (optional — REST API approvals still work without i
|
||||
| Issue | Severity | Workaround |
|
||||
|-------|----------|------------|
|
||||
| Windows: Claude CLI subprocess returns empty stdout | HIGH | Run in WSL |
|
||||
| WSL: venv created from /mnt/c/ loads stale code | HIGH | Delete .venv, recreate from WSL native path |
|
||||
| WSL + /mnt/c: Claude CLI Read/Glob very slow (10+ min) | MEDIUM | Clone repos to WSL native fs |
|
||||
| Graph has no LangGraph checkpointer (interrupt not persistent) | MEDIUM | Graphs run to completion or fail; no resume |
|
||||
| `_upsert_thread` only writes final state (no intermediate updates) | LOW | Query DB only after graph completes |
|
||||
| CI poll may run indefinitely (no build to poll in dev) | LOW | Leave `PR_POLL_ENABLED=False` |
|
||||
| Config test failures (env var leakage from .env) | LOW | Run with `-k "not test_config"` |
|
||||
| Local git checkout mutates repo working tree | LOW | Review runs sequentially; branch restored after |
|
||||
|
||||
### TODO (Not Yet Implemented)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user