From 7662bfddc3a618b737866cbedef97db55bb5e53d Mon Sep 17 00:00:00 2001 From: liuxiaotong Date: Fri, 6 Mar 2026 13:52:09 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=8D=87=E7=BA=A7=20auto-review=20workflow?= =?UTF-8?q?=EF=BC=9A=E5=BC=82=E6=AD=A5API=20+=20=E5=AE=A1=E6=9F=A5?= =?UTF-8?q?=E9=97=AD=E7=8E=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/auto-review.yml | 58 +++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/.github/workflows/auto-review.yml b/.github/workflows/auto-review.yml index ba86535..fec83cf 100644 --- a/.github/workflows/auto-review.yml +++ b/.github/workflows/auto-review.yml @@ -119,8 +119,8 @@ jobs: - summary: 审查总结 - comments: 具体意见数组(每条包含 file, line, comment)" - # 调用林锐审查 - RESPONSE=$(curl -s -X POST "https://crew.knowlyr.com/api/run/employee/code-reviewer" \ + # 调用林锐审查(异步 API:POST 返回 task_id,轮询等结果) + SUBMIT=$(curl -s -X POST "https://crew.knowlyr.com/run/employee/code-reviewer" \ -H "Authorization: Bearer ${CREW_API_TOKEN}" \ -H "Content-Type: application/json" \ -d "$(python3 -c " @@ -129,13 +129,47 @@ jobs: print(json.dumps({'task': task, 'format': 'json'})) " <<< "$TASK")") - echo "Review response received" - - # 解析返回结果,提取 JSON - RESULT=$(echo "$RESPONSE" | python3 -c " + TASK_ID=$(echo "$SUBMIT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('task_id',''))" 2>/dev/null) + if [ -z "$TASK_ID" ]; then + echo "Failed to submit review task: $SUBMIT" + RESULT='{"approved": false, "summary": "Failed to submit review task", "comments": []}' + else + echo "Review task submitted: $TASK_ID — polling for result..." + + # 轮询等待完成(最多 5 分钟) + POLL_TIMEOUT=300 + POLL_INTERVAL=10 + POLL_ELAPSED=0 + RESPONSE="" + + while [ $POLL_ELAPSED -lt $POLL_TIMEOUT ]; do + sleep $POLL_INTERVAL + POLL_ELAPSED=$((POLL_ELAPSED + POLL_INTERVAL)) + POLL_RESP=$(curl -s "https://crew.knowlyr.com/tasks/${TASK_ID}" \ + -H "Authorization: Bearer ${CREW_API_TOKEN}") + STATUS=$(echo "$POLL_RESP" | python3 -c "import json,sys; print(json.load(sys.stdin).get('status','unknown'))" 2>/dev/null) + + if [ "$STATUS" = "completed" ]; then + RESPONSE="$POLL_RESP" + echo "Review completed (${POLL_ELAPSED}s)" + break + elif [ "$STATUS" = "failed" ]; then + echo "Review task failed" + break + fi + echo " Still running... (${POLL_ELAPSED}s / ${POLL_TIMEOUT}s)" + done + + if [ -z "$RESPONSE" ]; then + echo "Review task timed out or failed" + RESULT='{"approved": false, "summary": "Review task timed out", "comments": []}' + else + # 解析返回结果:result.output 是林锐的文本输出,从中提取 JSON + RESULT=$(echo "$RESPONSE" | python3 -c " import json, sys, re data = json.load(sys.stdin) - text = data.get('result', data.get('output', '')) + result = data.get('result', {}) + text = result.get('output', '') if isinstance(result, dict) else str(result) # 尝试从文本中提取 JSON match = re.search(r'\{.*\}', text, re.DOTALL) if match: @@ -143,10 +177,12 @@ jobs: parsed = json.loads(match.group()) print(json.dumps(parsed)) except: - print(json.dumps({'approved': False, 'summary': text, 'comments': []})) + print(json.dumps({'approved': False, 'summary': text[:2000], 'comments': []})) else: - print(json.dumps({'approved': False, 'summary': text, 'comments': []})) + print(json.dumps({'approved': False, 'summary': text[:2000], 'comments': []})) " 2>/dev/null || echo '{"approved": false, "summary": "Failed to parse review response", "comments": []}') + fi + fi APPROVED=$(echo "$RESULT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('approved', False))") SUMMARY=$(echo "$RESULT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('summary', 'No summary'))") @@ -198,7 +234,7 @@ jobs: )" else echo "PR not approved — leaving review comments" - gh pr comment "$PR_NUMBER" --body "$(cat < Date: Fri, 6 Mar 2026 20:35:07 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20auto-review=20JSON=20=E8=A7=A3?= =?UTF-8?q?=E6=9E=90=E6=94=B9=E7=94=A8=E9=80=90=E4=BD=8D=E7=BD=AE=E5=B0=9D?= =?UTF-8?q?=E8=AF=95=EF=BC=8C=E4=BF=AE=E5=A4=8D=20approved=20=E8=AF=AF?= =?UTF-8?q?=E5=88=A4=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/auto-review.yml | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/.github/workflows/auto-review.yml b/.github/workflows/auto-review.yml index 6c4fc6a..bc1d2c9 100644 --- a/.github/workflows/auto-review.yml +++ b/.github/workflows/auto-review.yml @@ -176,19 +176,32 @@ jobs: RESULT='{"approved": false, "summary": "Review task timed out", "comments": []}' else # 解析返回结果:result.output 是林锐的文本输出,从中提取 JSON + # 逐位置尝试解析,找包含 approved key 的 JSON 对象(避免贪婪正则被文本中花括号干扰) RESULT=$(echo "$RESPONSE" | python3 -c " - import json, sys, re + import json, sys + data = json.load(sys.stdin) result = data.get('result', {}) text = result.get('output', '') if isinstance(result, dict) else str(result) - # 尝试从文本中提取 JSON - match = re.search(r'\{.*\}', text, re.DOTALL) - if match: - try: - parsed = json.loads(match.group()) - print(json.dumps(parsed)) - except: - print(json.dumps({'approved': False, 'summary': text[:2000], 'comments': []})) + + # 逐位置尝试解析 JSON,找包含 approved 的对象 + parsed = None + for i, ch in enumerate(text): + if ch == '{': + for j in range(len(text), i, -1): + if text[j-1] == '}': + try: + candidate = json.loads(text[i:j]) + if isinstance(candidate, dict) and 'approved' in candidate: + parsed = candidate + break + except (json.JSONDecodeError, ValueError): + continue + if parsed: + break + + if parsed: + print(json.dumps(parsed)) else: print(json.dumps({'approved': False, 'summary': text[:2000], 'comments': []})) " 2>/dev/null || echo '{"approved": false, "summary": "Failed to parse review response", "comments": []}')