Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

## Claude Code workflow

- Before creating a pull request, run the [Review Guidelines](../AGENTS.md#review-guidelines) checks over the branch changes.
- Before creating a pull request, run `./review.sh` (see [Review Guidelines](../AGENTS.md#review-guidelines)) over the branch changes.
- After running `/migrate-groovy-to-java`, run `/review-groovy-migration` on the migrated files before opening a PR.
- Always write new unit tests using JUnit 5 and Java. If the target test file is `.groovy`, run the `/migrate-groovy-to-java` skill on it first.
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ docs/ Developer documentation (see below)

## Review Guidelines

Run `./review.sh` before pushing. It runs your harness's code review over the branch changes against these guidelines, then `/perf-review`. It is advisory: findings are printed and nothing is enforced. Use `./review.sh --help` for options.

- **Correctness**: the review applies the [Critical constraints](#critical-constraints) below and the docs they link.
- **Technical debt**: run `/techdebt` over branch changes before marking a PR ready to catch code duplication, unnecessary complexity, and dead code (refactor-only, never changes behavior) — see [.agents/skills/techdebt/SKILL.md](.agents/skills/techdebt/SKILL.md).
- **Performance**: run `/perf-review` over branch changes before marking a PR ready (advisory, not a merge gate) — see [.agents/skills/perf-review/SKILL.md](.agents/skills/perf-review/SKILL.md).

Expand Down
1 change: 1 addition & 0 deletions review.sh
132 changes: 132 additions & 0 deletions tooling/review.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
#!/usr/bin/env bash
# Pre-push review entry point for dd-trace-java.
#
# Runs the coding harness's built-in code review over the branch changes, then the
# repo-specific review extensions (currently /perf-review). Review expectations live
# in AGENTS.md (see "Review Guidelines"). Advisory only: findings are printed and the
# script exits 0 regardless of what was found.
set -euo pipefail

usage() {
cat <<EOF
Usage: ./review.sh [options]

Review the changes on the current branch before pushing.

Options:
--base <ref> Compare against <ref> (default: merge-base with upstream master)
--harness <name> Harness to run: claude, codex (default: first one found on PATH)
--no-extensions Only run the built-in review, skip repo extensions (/perf-review)
--out <file> Also write the review output to <file>
-h, --help Show this help
EOF
}

BASE=""
HARNESS=""
RUN_EXTENSIONS=true
OUT=""

require_value() {
if [ $# -lt 2 ] || [ -z "$2" ]; then
echo "❌ Missing value for $1" >&2
usage >&2
exit 1
fi
}

while [ $# -gt 0 ]; do
case "$1" in
--base) require_value "$@"; BASE="$2"; shift 2 ;;
--harness) require_value "$@"; HARNESS="$2"; shift 2 ;;
--no-extensions) RUN_EXTENSIONS=false; shift ;;
--out) require_value "$@"; OUT="$2"; shift 2 ;;
-h|--help) usage; exit 0 ;;
*) echo "❌ Unknown option: $1" >&2; usage >&2; exit 1 ;;
esac
done

cd "$(git rev-parse --show-toplevel)"

find_base() {
local upstream
upstream=$(git remote -v | grep -E 'DataDog/[^/]+(\.git)?\s' | head -1 | awk '{print $1}')
git merge-base HEAD "${upstream:-origin}/master"
}

detect_harness() {
for candidate in claude codex; do
if command -v "$candidate" &> /dev/null; then
echo "$candidate"
return
fi
done
echo "❌ No supported harness found on PATH (claude, codex)." >&2
exit 1
}

if [ -z "$BASE" ]; then
BASE=$(find_base)
else
BASE=$(git merge-base HEAD "$BASE")
fi
case "${HARNESS:=$(detect_harness)}" in
claude|codex) ;;
*) echo "❌ Unsupported harness: $HARNESS (supported: claude, codex)" >&2; exit 1 ;;
esac

if git diff --quiet "$BASE" HEAD; then
echo "No changes since $BASE; nothing to review."
exit 0
fi

echo "🔎 Reviewing changes since $(git rev-parse --short "$BASE") with $HARNESS"
git diff --stat "$BASE" HEAD
echo

REVIEW_PROMPT="Review the changes on this branch since $BASE (git diff $BASE...HEAD) \
for correctness bugs. Apply the Review Guidelines and Critical constraints in AGENTS.md \
and the docs they link. Report only findings you are confident about, with \
file:line references. Do not edit any files."
PERF_PROMPT="/perf-review the changes on this branch since $BASE"

# Read-only tool set for headless runs, so nothing stalls on a permission prompt.
CLAUDE_ALLOWED_TOOLS="Read Grep Glob Agent Skill Bash(git diff:*) Bash(git log:*) Bash(git show:*) Bash(git merge-base:*) Bash(git remote:*) Bash(git rev-parse:*) Bash(git status:*) Bash(git blame:*) Bash(grep:*) Bash(find:*) Bash(ls:*) Bash(cat:*) Bash(head:*) Bash(sed -n:*) Bash(wc:*)"

run_harness() {
local prompt="$1"
case "$HARNESS" in
claude)
claude -p "$prompt" \
--permission-mode dontAsk \
--allowedTools "$CLAUDE_ALLOWED_TOOLS" \
--disallowedTools "Edit Write NotebookEdit"
;;
codex)
codex exec --sandbox read-only "$prompt"
;;
esac
}

run_reviews() {
echo "## Code review"
echo
run_harness "$REVIEW_PROMPT" || echo "⚠️ Code review failed"
if [ "$RUN_EXTENSIONS" = true ]; then
echo
echo "## Performance review"
echo
if [ "$HARNESS" = claude ]; then
run_harness "$PERF_PROMPT" || echo "⚠️ Performance review failed"
else
run_harness "Follow .agents/skills/perf-review/SKILL.md to review the changes on this branch since $BASE" \
|| echo "⚠️ Performance review failed"
fi
fi
}

if [ -n "$OUT" ]; then
run_reviews | tee "$OUT"
else
run_reviews
fi
Loading