Skip to content

Commit e019678

Browse files
neha037claude
andcommitted
improve review handler: ai-helpers best practices + fork push fix
- Add resolved-thread filtering via GraphQL (skip already-resolved threads) - Add pure-acknowledgment filtering (skip LGTM, Thanks, +1 etc.) - Add PR commit messages to Claude's prompt for better context - Batch all pushes into single push after all threads processed - Add post-push SHA verification - Fix fork-based PRs: push to head repo (fork), not upstream - Add rebase before push with force-with-lease fallback - Add "reject invalid requests" guidance to SKILL.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent e5a556d commit e019678

8 files changed

Lines changed: 2393 additions & 0 deletions

File tree

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
# Reference config for the oape-review-handler Prow presubmit job.
2+
#
3+
# This file is NOT consumed by CI directly. It documents the changes
4+
# needed in a NEW openshift/release PR to enable:
5+
#
6+
# /test oape-review-handler
7+
#
8+
# This is SEPARATE from the oape-ci-monitor PR (#80727).
9+
#
10+
# Apply these changes to:
11+
# ci-operator/config/openshift/must-gather-operator/openshift-must-gather-operator-master.yaml
12+
#
13+
# After editing the ci-operator config, run:
14+
# make jobs
15+
# to regenerate the presubmits YAML, then open a PR to openshift/release.
16+
17+
# ============================================================================
18+
# STEP 1: Add review-handler-agent image to the "images.items" array
19+
# ============================================================================
20+
# This is a SEPARATE image from ci-monitor-agent. It clones from
21+
# neha037/oape-ai-e2e branch oape-review-handler and includes Node.js + Claude CLI.
22+
23+
image_reference:
24+
- dockerfile_literal: |-
25+
FROM registry.access.redhat.com/ubi9/go-toolset
26+
USER 0
27+
RUN dnf install -y git make jq && \
28+
dnf install -y 'dnf-command(config-manager)' && \
29+
dnf config-manager --add-repo https://cli.github.com/packages/rpm/gh-cli.repo && \
30+
dnf install -y gh && \
31+
dnf clean all
32+
RUN dnf module reset -y nodejs && \
33+
dnf module enable -y nodejs:20 && \
34+
dnf install -y nodejs npm && \
35+
npm install -g @anthropic-ai/claude-code && \
36+
dnf clean all
37+
WORKDIR /app
38+
RUN git clone --depth 1 -b oape-review-handler https://github.com/neha037/oape-ai-e2e.git /tmp/oape && \
39+
cp -r /tmp/oape/scripts /app/scripts && \
40+
cp -r /tmp/oape/plugins /plugins && \
41+
mkdir -p /config && cp -r /tmp/oape/deploy/config/* /config/ && \
42+
rm -rf /tmp/oape
43+
RUN go install golang.org/x/tools/cmd/goimports@v0.33.0 && \
44+
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/v2.1.6/install.sh | sh -s -- -b /usr/local/bin v2.1.6
45+
RUN git config --global user.name "openshift-app-platform-shift-bot" && \
46+
git config --global user.email "267347085+openshift-app-platform-shift-bot@users.noreply.github.com"
47+
RUN chmod -R g=u /opt/app-root/src
48+
USER 1001
49+
to: review-handler-agent
50+
51+
# Also add to promotion.to[0].excluded_images:
52+
# - review-handler-agent
53+
54+
# ============================================================================
55+
# STEP 2: Add the oape-review-handler test step to the "tests:" array
56+
# ============================================================================
57+
58+
test_step_reference:
59+
- always_run: false
60+
as: oape-review-handler
61+
optional: true
62+
steps:
63+
test:
64+
- as: review
65+
commands: |
66+
set -euo pipefail
67+
68+
echo "[setup] Starting oape-review-handler for ${REPO_OWNER}/${REPO_NAME} PR#${PULL_NUMBER}"
69+
70+
# --- Rehearsal detection ---
71+
if [[ "${REPO_NAME}" == "release" && "${REPO_OWNER}" == "openshift" ]]; then
72+
echo "[setup] Detected openshift/release context — switching to test target"
73+
export REPO_OWNER="openshift"
74+
export REPO_NAME="must-gather-operator"
75+
TEST_PR=$(curl -s "https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/pulls?state=open&per_page=1" \
76+
| python3 -c "import sys,json; data=json.load(sys.stdin); print(data[0]['number'] if data else '')" 2>/dev/null || echo "")
77+
if [[ -z "$TEST_PR" ]]; then
78+
echo "[setup] No open PRs found — skipping"
79+
exit 0
80+
fi
81+
export PULL_NUMBER="$TEST_PR"
82+
echo "[setup] Testing against ${REPO_OWNER}/${REPO_NAME}#${PULL_NUMBER}"
83+
fi
84+
85+
# --- GitHub auth: App token with GITHUB_TOKEN fallback ---
86+
USE_APP_TOKEN="false"
87+
if [[ -f /var/run/github-app/app-id && -f /var/run/github-app/private-key.pem ]]; then
88+
echo "[auth] Attempting GitHub App token..."
89+
APP_ID=$(cat /var/run/github-app/app-id)
90+
PEM_PATH="/var/run/github-app/private-key.pem"
91+
HEADER=$(printf '{"alg":"RS256","typ":"JWT"}' | openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
92+
NOW=$(date +%s); EXP=$((NOW + 300))
93+
PAYLOAD=$(printf '{"iat":%d,"exp":%d,"iss":"%s"}' "$NOW" "$EXP" "$APP_ID" | openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
94+
SIGNATURE=$(printf '%s' "${HEADER}.${PAYLOAD}" | openssl dgst -sha256 -sign "$PEM_PATH" -binary | openssl base64 -e -A | tr '+/' '-_' | tr -d '=')
95+
JWT="${HEADER}.${PAYLOAD}.${SIGNATURE}"
96+
INSTALL_RESPONSE=$(curl -s -w "\n%{http_code}" -H "Authorization: Bearer ${JWT}" -H "Accept: application/vnd.github+json" \
97+
"https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}/installation")
98+
HTTP_CODE=$(echo "$INSTALL_RESPONSE" | tail -1)
99+
INSTALL_BODY=$(echo "$INSTALL_RESPONSE" | sed '$d')
100+
if [[ "$HTTP_CODE" -eq 200 ]]; then
101+
INST_ID=$(echo "$INSTALL_BODY" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])")
102+
TOKEN_RESPONSE=$(curl -s -w "\n%{http_code}" -X POST -H "Authorization: Bearer ${JWT}" -H "Accept: application/vnd.github+json" \
103+
"https://api.github.com/app/installations/${INST_ID}/access_tokens")
104+
T_CODE=$(echo "$TOKEN_RESPONSE" | tail -1)
105+
T_BODY=$(echo "$TOKEN_RESPONSE" | sed '$d')
106+
if [[ "$T_CODE" -eq 201 ]]; then
107+
export GH_TOKEN=$(echo "$T_BODY" | python3 -c "import sys,json; print(json.load(sys.stdin)['token'])")
108+
USE_APP_TOKEN="true"
109+
echo "[auth] GitHub App token generated successfully"
110+
else
111+
echo "[auth] WARN: App token creation failed (HTTP ${T_CODE}), falling back to GITHUB_TOKEN"
112+
fi
113+
else
114+
echo "[auth] WARN: App not installed on ${REPO_OWNER}/${REPO_NAME} (HTTP ${HTTP_CODE}), falling back to GITHUB_TOKEN"
115+
fi
116+
else
117+
echo "[auth] GitHub App credentials not mounted, using GITHUB_TOKEN"
118+
fi
119+
if [[ "$USE_APP_TOKEN" != "true" ]]; then
120+
if [[ -z "${GH_TOKEN:-}" && -z "${GITHUB_TOKEN:-}" ]]; then
121+
echo "[auth] ERROR: No GitHub token available" >&2
122+
exit 1
123+
fi
124+
export GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN}}"
125+
fi
126+
127+
# --- GCP auth for Claude (Vertex AI) ---
128+
export GOOGLE_APPLICATION_CREDENTIALS="/var/run/gcloud-adc/application_default_credentials.json"
129+
export CLAUDE_CODE_USE_VERTEX="1"
130+
export CLOUD_ML_REGION="global"
131+
export ANTHROPIC_VERTEX_PROJECT_ID="itpc-gcp-hcm-pe-eng-claude"
132+
133+
# --- Run review handler ---
134+
export PR_URL="https://github.com/${REPO_OWNER}/${REPO_NAME}/pull/${PULL_NUMBER}"
135+
export PLUGINS_DIR="/plugins/oape/skills"
136+
137+
gh auth setup-git
138+
/app/scripts/pr-agent/review-handler.sh --pr-url "$PR_URL"
139+
credentials:
140+
- mount_path: /var/run/gcloud-adc
141+
name: oap-lts-claude-gcp-vertex-sa
142+
namespace: test-credentials
143+
- mount_path: /var/run/github-app
144+
name: openshift-app-platform-shift-github-bot
145+
namespace: test-credentials
146+
from: review-handler-agent
147+
resources:
148+
requests:
149+
cpu: "1"
150+
memory: 500Mi
151+
timeout: 1h0m0s
152+
153+
# ============================================================================
154+
# STEP 3: Trigger the job
155+
# ============================================================================
156+
# On any PR in openshift/must-gather-operator, comment:
157+
#
158+
# /test oape-review-handler
159+
#
160+
# For rehearsal (from openshift/release PR):
161+
#
162+
# /pj-rehearse oape-review-handler
163+
#
164+
# ============================================================================
165+
# PREREQUISITE: The oape-review-handler branch on neha037/oape-ai-e2e
166+
# must contain the review handler scripts, since the dockerfile_literal
167+
# clones from that branch.
168+
# ============================================================================

0 commit comments

Comments
 (0)