Files
BlackBean/pigo/internal/builtinskills/skills/review-it/scripts/review-it
T
2026-08-14 23:41:57 +08:00

248 lines
6.9 KiB
Bash

#!/usr/bin/env bash
# review-it — Code review closeout helper
# Orchestrates /review with optional parallel test execution.
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILL_DIR="$(dirname "$SCRIPT_DIR")"
MODE="auto"
BASE="origin/main"
TESTS=""
DRY_RUN=false
AGENT="auto"
usage() {
cat <<EOF
Usage: review-it [options]
Options:
--mode auto|local|branch Target selection. Default: auto.
auto: uncommitted if dirty, branch diff otherwise
local: force review on uncommitted changes
branch: force diff review against base
--agent auto|claude|antigravity|codex
Agent to target. Default: auto (detects running agent).
--base REF Base ref for branch review. Default: origin/main.
--parallel-tests CMD Run tests in parallel with review.
--dry-run Print what would be executed, don't run.
--help Show this help.
Environment:
CC_REVIEW_OUTPUT File to write review output to (default: stdout only).
For branch mode, generates a git diff against the base and instructs
Claude Code's /review to analyze it.
Examples:
review-it # auto-detect mode and agent
review-it --agent antigravity # use /code-review for Antigravity CLI
review-it --mode local # review uncommitted changes
review-it --mode branch # review branch vs origin/main
review-it --parallel-tests "go test ./..." # review + test in parallel
EOF
exit 0
}
# --- Parse args ---
while [[ $# -gt 0 ]]; do
case "$1" in
--mode) MODE="$2"; shift 2 ;;
--agent) AGENT="$2"; shift 2 ;;
--base) BASE="$2"; shift 2 ;;
--parallel-tests) TESTS="$2"; shift 2 ;;
--dry-run) DRY_RUN=true; shift ;;
--help) usage ;;
*) echo "Unknown option: $1"; usage ;;
esac
done
# --- Detect state ---
STAGED=$(git diff --cached --name-only 2>/dev/null | wc -l | tr -d ' ')
UNSTAGED=$(git diff --name-only 2>/dev/null | wc -l | tr -d ' ')
UNTRACKED=$(git ls-files --others --exclude-standard 2>/dev/null | wc -l | tr -d ' ')
CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "HEAD")
IS_MAIN=false
[[ "$CURRENT_BRANCH" == "main" || "$CURRENT_BRANCH" == "master" ]] && IS_MAIN=true
HAS_DIRTY=false
[[ "$STAGED" -gt 0 || "$UNSTAGED" -gt 0 || "$UNTRACKED" -gt 0 ]] && HAS_DIRTY=true
# --- Detect agent ---
detect_agent() {
# Check environment variables / parent process
if [[ -n "${ANTIGRAVITY_CLI:-}" ]] || [[ -n "${GEMINI_CLI:-}" ]]; then
echo "antigravity"
elif [[ -n "${CLAUDE_CODE:-}" ]] || [[ -n "${CLAUDE_CLI:-}" ]]; then
echo "claude"
elif command -v codex &>/dev/null && [[ -n "${CODEX_CLI:-}" ]]; then
echo "codex"
else
# Default to claude as most common
echo "claude"
fi
}
if [[ "$AGENT" == "auto" ]]; then
DETECTED_AGENT=$(detect_agent)
else
DETECTED_AGENT="$AGENT"
fi
# --- Resolve review command by agent ---
review_cmd_for() {
local mode="$1"
local diff_file="$2"
case "$DETECTED_AGENT" in
antigravity)
if [[ "$mode" == "local" ]]; then
echo "/code-review"
else
echo "/code-review the changes in $diff_file against $BASE"
fi
;;
codex)
if [[ "$mode" == "local" ]]; then
echo "codex review"
else
echo "codex review $diff_file"
fi
;;
claude|*)
if [[ "$mode" == "local" ]]; then
echo "/review"
else
echo "/review the changes in $diff_file against $BASE"
fi
;;
esac
}
# --- Resolve mode ---
if [[ "$MODE" == "auto" ]]; then
if $HAS_DIRTY; then
REVIEW_MODE="local"
elif $IS_MAIN; then
echo "review-it: on main with clean tree, nothing to review."
exit 0
else
REVIEW_MODE="branch"
fi
else
REVIEW_MODE="$MODE"
fi
# --- Check for PR base ---
if [[ "$REVIEW_MODE" == "branch" ]]; then
if command -v gh &>/dev/null; then
PR_BASE=$(gh pr view --json baseRefName --jq .baseRefName 2>/dev/null || echo "")
if [[ -n "$PR_BASE" ]]; then
BASE="origin/$PR_BASE"
fi
fi
# Fetch the base to ensure we have it
if ! $DRY_RUN; then
git fetch origin "$(echo "$BASE" | sed 's|origin/||')" 2>/dev/null || true
fi
fi
# --- Build review command ---
DIFF_FILE=""
case "$REVIEW_MODE" in
local)
REVIEW_DESC="uncommitted changes"
;;
branch)
DIFF_FILE="/tmp/review-it-$$.diff"
REVIEW_DESC="branch $CURRENT_BRANCH vs $BASE"
;;
*)
echo "review-it: unknown mode $REVIEW_MODE"
exit 1
;;
esac
REVIEW_CMD=$(review_cmd_for "$REVIEW_MODE" "$DIFF_FILE")
# --- Dry run ---
if $DRY_RUN; then
echo "mode: $REVIEW_MODE"
echo "agent: $DETECTED_AGENT"
echo "target: $REVIEW_DESC"
echo "review: $REVIEW_CMD"
echo "dirty: staged=$STAGED unstaged=$UNSTAGED untracked=$UNTRACKED"
if [[ "$REVIEW_MODE" == "branch" ]]; then
echo "diff: $DIFF_FILE"
echo "base: $BASE"
fi
if [[ -n "$TESTS" ]]; then
echo "tests: $TESTS"
fi
exit 0
fi
# --- Run ---
echo "review-it: mode=$REVIEW_MODE agent=$DETECTED_AGENT target=$REVIEW_DESC"
echo ""
# Generate diff for branch mode
if [[ "$REVIEW_MODE" == "branch" ]]; then
if ! git diff "$BASE"...HEAD > "$DIFF_FILE" 2>/dev/null; then
echo "review-it: failed to generate diff against $BASE"
exit 1
fi
if [[ ! -s "$DIFF_FILE" ]]; then
echo "review-it: no changes between $BASE and HEAD"
rm -f "$DIFF_FILE"
exit 0
fi
echo "review-it: generated diff ($(wc -l < "$DIFF_FILE" | tr -d ' ') lines) at $DIFF_FILE"
echo ""
fi
# Run tests in background if requested
TEST_PID=""
if [[ -n "$TESTS" ]]; then
echo "review-it: running tests in background: $TESTS"
eval "$TESTS" > /tmp/review-it-tests-$$.log 2>&1 &
TEST_PID=$!
echo "review-it: test PID=$TEST_PID"
echo ""
fi
# Run review (this is a signal to the user — the actual /review
# is executed by Claude Code when it reads this output)
cat <<CCEOF
review-it: ready for review ($REVIEW_DESC)
$REVIEW_CMD
CCEOF
# Wait for tests if running
if [[ -n "$TEST_PID" ]]; then
echo ""
echo "review-it: waiting for tests to complete (PID=$TEST_PID)..."
wait "$TEST_PID" 2>/dev/null || true
TEST_EXIT=$?
echo ""
echo "--- test output ---"
cat /tmp/review-it-tests-$$.log
echo "--- end test output ---"
rm -f /tmp/review-it-tests-$$.log
if [[ $TEST_EXIT -ne 0 ]]; then
echo ""
echo "review-it: tests FAILED (exit=$TEST_EXIT)"
exit $TEST_EXIT
else
echo ""
echo "review-it: tests passed"
fi
fi
# Cleanup
if [[ "$REVIEW_MODE" == "branch" ]]; then
rm -f "$DIFF_FILE"
fi
echo ""
echo "review-it: done"