Standalone bash script that extracts git diffs for af-review without PDCA orchestration. Supports --branch, --commit, and uncommitted modes. Reports stats (files/lines changed) to stderr, diff to stdout.
198 lines
5.9 KiB
Bash
Executable File
198 lines
5.9 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# archeflow-review.sh — Get a git diff for Guardian review, with stats.
|
|
#
|
|
# Standalone diff helper for af-review. No PDCA orchestration — just extracts
|
|
# the right diff and reports stats so the Claude Code agent can feed it to
|
|
# Guardian (or other reviewers).
|
|
#
|
|
# Usage:
|
|
# archeflow-review.sh # Uncommitted changes (staged + unstaged)
|
|
# archeflow-review.sh --branch feat/batch-api # Branch diff vs main
|
|
# archeflow-review.sh --commit HEAD~3..HEAD # Commit range
|
|
# archeflow-review.sh --base develop # Override base branch (default: main)
|
|
# archeflow-review.sh --stat-only # Only print stats, no diff output
|
|
#
|
|
# Output:
|
|
# Prints the diff to stdout. Stats go to stderr so they don't pollute the diff.
|
|
# Exit code 0 if diff is non-empty, 1 if empty (nothing to review).
|
|
|
|
set -euo pipefail
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Globals
|
|
# ---------------------------------------------------------------------------
|
|
|
|
BASE_BRANCH="main"
|
|
MODE="uncommitted" # uncommitted | branch | commit
|
|
TARGET=""
|
|
STAT_ONLY="false"
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
die() {
|
|
echo "[af-review] ERROR: $*" >&2
|
|
exit 1
|
|
}
|
|
|
|
info() {
|
|
echo "[af-review] $*" >&2
|
|
}
|
|
|
|
# Print diff stats (files changed, insertions, deletions) to stderr.
|
|
print_stats() {
|
|
local diff_text="$1"
|
|
|
|
local files_changed lines_added lines_removed total_lines
|
|
files_changed=$(echo "$diff_text" | grep -c '^diff --git' || true)
|
|
lines_added=$(echo "$diff_text" | grep -c '^+[^+]' || true)
|
|
lines_removed=$(echo "$diff_text" | grep -c '^-[^-]' || true)
|
|
total_lines=$(echo "$diff_text" | wc -l | tr -d ' ')
|
|
|
|
info "--- Review Stats ---"
|
|
info "Files changed: ${files_changed}"
|
|
info "Lines added: +${lines_added}"
|
|
info "Lines removed: -${lines_removed}"
|
|
info "Diff size: ${total_lines} lines"
|
|
|
|
if [[ "$total_lines" -gt 500 ]]; then
|
|
info "Warning: large diff (>500 lines). Consider reviewing per-file."
|
|
fi
|
|
}
|
|
|
|
# Detect the default base branch (main or master).
|
|
detect_base_branch() {
|
|
if git show-ref --verify --quiet "refs/heads/main" 2>/dev/null; then
|
|
echo "main"
|
|
elif git show-ref --verify --quiet "refs/heads/master" 2>/dev/null; then
|
|
echo "master"
|
|
else
|
|
echo "main"
|
|
fi
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Argument parsing
|
|
# ---------------------------------------------------------------------------
|
|
|
|
parse_args() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--branch)
|
|
MODE="branch"
|
|
TARGET="${2:?Missing branch name after --branch}"
|
|
shift 2
|
|
;;
|
|
--commit)
|
|
MODE="commit"
|
|
TARGET="${2:?Missing commit range after --commit}"
|
|
shift 2
|
|
;;
|
|
--base)
|
|
BASE_BRANCH="${2:?Missing base branch after --base}"
|
|
shift 2
|
|
;;
|
|
--stat-only)
|
|
STAT_ONLY="true"
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
echo "Usage: $0 [--branch <name>] [--commit <range>] [--base <branch>] [--stat-only]"
|
|
echo ""
|
|
echo " (no args) Review uncommitted changes (staged + unstaged)"
|
|
echo " --branch <name> Review branch diff against base (default: main)"
|
|
echo " --commit <range> Review a commit range (e.g. HEAD~3..HEAD)"
|
|
echo " --base <branch> Override base branch (default: auto-detect main/master)"
|
|
echo " --stat-only Print stats only, no diff output"
|
|
exit 0
|
|
;;
|
|
*)
|
|
die "Unknown argument: $1. Use --help for usage."
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Diff extraction
|
|
# ---------------------------------------------------------------------------
|
|
|
|
get_diff() {
|
|
local diff_text=""
|
|
|
|
case "$MODE" in
|
|
uncommitted)
|
|
# Combine staged and unstaged changes against HEAD
|
|
diff_text=$(git diff HEAD 2>/dev/null || true)
|
|
if [[ -z "$diff_text" ]]; then
|
|
# Maybe everything is staged, try just staged
|
|
diff_text=$(git diff --cached 2>/dev/null || true)
|
|
fi
|
|
;;
|
|
branch)
|
|
# Verify target branch exists
|
|
if ! git show-ref --verify --quiet "refs/heads/${TARGET}" 2>/dev/null; then
|
|
# Maybe it's a remote branch
|
|
if ! git rev-parse --verify "${TARGET}" &>/dev/null; then
|
|
die "Branch '${TARGET}' not found."
|
|
fi
|
|
fi
|
|
diff_text=$(git diff "${BASE_BRANCH}...${TARGET}" 2>/dev/null || true)
|
|
;;
|
|
commit)
|
|
# Validate commit range resolves
|
|
if ! git rev-parse "${TARGET}" &>/dev/null 2>&1; then
|
|
die "Invalid commit range: '${TARGET}'"
|
|
fi
|
|
diff_text=$(git diff "${TARGET}" 2>/dev/null || true)
|
|
;;
|
|
esac
|
|
|
|
echo "$diff_text"
|
|
}
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Main
|
|
# ---------------------------------------------------------------------------
|
|
|
|
main() {
|
|
# Verify we're in a git repo
|
|
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
|
|
die "Not inside a git repository."
|
|
fi
|
|
|
|
parse_args "$@"
|
|
|
|
# Auto-detect base branch if not overridden
|
|
if [[ "$BASE_BRANCH" == "main" ]]; then
|
|
BASE_BRANCH=$(detect_base_branch)
|
|
fi
|
|
|
|
# Describe what we're reviewing
|
|
case "$MODE" in
|
|
uncommitted) info "Reviewing: uncommitted changes vs HEAD" ;;
|
|
branch) info "Reviewing: branch '${TARGET}' vs '${BASE_BRANCH}'" ;;
|
|
commit) info "Reviewing: commit range '${TARGET}'" ;;
|
|
esac
|
|
|
|
local diff_text
|
|
diff_text=$(get_diff)
|
|
|
|
# Validate non-empty
|
|
if [[ -z "$diff_text" ]]; then
|
|
info "No changes found. Nothing to review."
|
|
exit 1
|
|
fi
|
|
|
|
# Print stats to stderr
|
|
print_stats "$diff_text"
|
|
|
|
# Output the diff to stdout (unless stat-only)
|
|
if [[ "$STAT_ONLY" != "true" ]]; then
|
|
echo "$diff_text"
|
|
fi
|
|
}
|
|
|
|
main "$@"
|