-
Notifications
You must be signed in to change notification settings - Fork 65
Expand file tree
/
Copy pathrun_all.sh
More file actions
executable file
·390 lines (347 loc) · 13.9 KB
/
Copy pathrun_all.sh
File metadata and controls
executable file
·390 lines (347 loc) · 13.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
#!/bin/bash
# autoresearch/run_all.sh - 批量处理所有未关闭的 Issues
#
# 根据 --issue-source 参数决定 Issue 来源,支持四种模式:
# github — 拉取项目中所有 open 状态的 GitHub Issues (默认)
# local — 扫描本地 .autoresearch/issues/ 目录下的 issue-NNN-*.md 文件
# baidu — 拉取百度 iCafe 空间中未关闭的卡片
# codeup — 拉取阿里云效 Codeup 项目中未关闭的 Issues
#
# 用法:
# ./run_all.sh # 默认 GitHub 模式,处理所有 open issue
# ./run_all.sh -p /path/to/project # 指定项目路径
# ./run_all.sh --issue-source=local # 本地模式:处理 .autoresearch/issues/ 下的所有文件
# ./run_all.sh --issue-source=local --issues-dir=/path # 本地模式:指定 issue 目录
# ./run_all.sh --issue-source=baidu --space=cloud-iCafe # 百度模式:处理 iCafe 空间中所有未关闭卡片
# ./run_all.sh --issue-source=codeup --codeup-ak-id=xxx --codeup-ak-secret=yyy --codeup-org=123 --codeup-repo=456 # Codeup 模式
# ./run_all.sh -a claude,codex # 指定 agents
# ./run_all.sh --no-archive --no-ui-verify # 跳过归档和 UI 验证
#
# 注意: 对每个 issue 默认使用 -c (continue) 模式调用 run.sh。
# 首次运行的 issue 会正常从头开始,中断后重跑会自动续跑。
#
# 环境变量:
# RUN_ALL_LABEL: 只处理带有此 label 的 issues (可选,仅 GitHub 模式)
# RUN_ALL_DRY_RUN: 设为 yes 则只列出 issues 不执行 (可选)
# ICAFE_SPACE: iCafe 空间前缀代码 (baidu 模式,也可用 --space)
# CODEUP_AK_ID: 阿里云 Access Key ID (codeup 模式,也可用 --codeup-ak-id)
# CODEUP_AK_SECRET: 阿里云 Access Key Secret (codeup 模式,也可用 --codeup-ak-secret)
# CODEUP_ORG_ID: Codeup 组织 ID (codeup 模式,也可用 --codeup-org)
# CODEUP_REPO_ID: Codeup 仓库 ID (codeup 模式,也可用 --codeup-repo)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
RUN_SH="$SCRIPT_DIR/run.sh"
if [ ! -f "$RUN_SH" ]; then
echo "ERROR: 找不到 run.sh: $RUN_SH" >&2
exit 1
fi
# ==================== 解析参数 ====================
RUN_ARGS=("$@")
ISSUE_SOURCE="github"
ICAFE_SPACE="${ICAFE_SPACE:-}"
ISSUES_DIR=""
TARGET_BRANCH=""
CODEUP_AK_ID="${CODEUP_AK_ID:-}"
CODEUP_AK_SECRET="${CODEUP_AK_SECRET:-}"
CODEUP_ORG_ID="${CODEUP_ORG_ID:-}"
CODEUP_REPO_ID="${CODEUP_REPO_ID:-}"
# 从 RUN_ARGS 中提取 --issue-source / --space / --issues-dir / --target-branch
for arg in "${RUN_ARGS[@]+"${RUN_ARGS[@]}"}"; do
case "$arg" in
--issue-source=*)
ISSUE_SOURCE="${arg#--issue-source=}"
;;
--space=*)
ICAFE_SPACE="${arg#--space=}"
;;
--issues-dir=*)
ISSUES_DIR="${arg#--issues-dir=}"
;;
--target-branch=*)
TARGET_BRANCH="${arg#--target-branch=}"
;;
--codeup-ak-id=*)
CODEUP_AK_ID="${arg#--codeup-ak-id=}"
;;
--codeup-ak-secret=*)
CODEUP_AK_SECRET="${arg#--codeup-ak-secret=}"
;;
--codeup-org=*)
CODEUP_ORG_ID="${arg#--codeup-org=}"
;;
--codeup-repo=*)
CODEUP_REPO_ID="${arg#--codeup-repo=}"
;;
esac
done
# ==================== 检测项目路径 ====================
PROJECT_ROOT="$(pwd)"
for (( i=0; i<${#RUN_ARGS[@]}; i++ )); do
if [ "${RUN_ARGS[$i]}" = "-p" ] && (( i+1 < ${#RUN_ARGS[@]} )); then
PROJECT_ROOT="${RUN_ARGS[$((i+1))]}"
break
fi
done
# ==================== 自动检测 issue source ====================
# 如果显式指定了 local 或 baidu,尊重用户选择
# 否则尝试自动检测
if [ "$ISSUE_SOURCE" = "github" ]; then
# 如果指定了 --issues-dir,切换到 local 模式
if [ -n "$ISSUES_DIR" ]; then
ISSUE_SOURCE="local"
fi
fi
if [ "$ISSUE_SOURCE" = "github" ] && [ -n "$ICAFE_SPACE" ]; then
# 检查 git remote 是否包含 icode.baidu.com
REMOTE_URL="$(git -C "$PROJECT_ROOT" remote get-url origin 2>/dev/null || true)"
if echo "$REMOTE_URL" | grep -q 'icode\.baidu\.com'; then
ISSUE_SOURCE="baidu"
fi
fi
# 自动检测: remote 是 icode.baidu.com 但没设 ICAFE_SPACE → 自动推导或使用 icode 模式
# (run.sh 会在内部做更详细的检测,这里只设置 ISSUE_SOURCE 让 run_all.sh 能正确拉取 issue 列表)
if [ "$ISSUE_SOURCE" = "github" ]; then
REMOTE_URL="$(git -C "$PROJECT_ROOT" remote get-url origin 2>/dev/null || true)"
if echo "$REMOTE_URL" | grep -q 'icode\.baidu\.com'; then
# 尝试自动推导 ICAFE_SPACE
REPO_PATH="$(echo "$REMOTE_URL" | sed -E 's|.*icode\.baidu\.com[:/][0-9]*/?||; s|\.git$||')"
AUTO_SPACE="$(echo "$REPO_PATH" | tr '/' '-')"
if command -v icafe-cli &>/dev/null && \
icafe-cli card query --space "$AUTO_SPACE" --max-records 1 &>/dev/null 2>&1; then
ICAFE_SPACE="$AUTO_SPACE"
ISSUE_SOURCE="baidu"
else
# 无 iCafe 空间,用本地文件模式获取 issue 列表(如果有的话)
if [ -d "$PROJECT_ROOT/.autoresearch/issues" ]; then
ISSUE_SOURCE="local"
ISSUES_DIR="$PROJECT_ROOT/.autoresearch/issues"
else
# 无法获取 issue 列表,交给 run.sh 的 icode 模式处理单个 issue
ISSUE_SOURCE="icode"
fi
fi
fi
fi
# ==================== Issue 列表获取 ====================
ISSUES_JSON="" # JSON 数组: [{"number": N, "title": "..."}, ...]
fetch_github_issues() {
# 检查 gh CLI
if ! command -v gh &>/dev/null; then
echo "ERROR: 需要安装 GitHub CLI (gh)。请运行: brew install gh" >&2
exit 1
fi
if ! gh auth status &>/dev/null; then
echo "ERROR: gh 未登录。请运行: gh auth login" >&2
exit 1
fi
# 获取 repo slug
local repo_slug=""
if [ -d "$PROJECT_ROOT/.git" ]; then
repo_slug="$(cd "$PROJECT_ROOT" && git remote get-url origin 2>/dev/null | sed -E 's#.*github.com[/:]##;s/\.git$//' || true)"
fi
if [ -z "$repo_slug" ]; then
echo "ERROR: 无法从 $PROJECT_ROOT 检测到 GitHub remote (origin)。确保项目目录是 git 仓库且关联了 GitHub。" >&2
exit 1
fi
local gh_args=(issue list --repo "$repo_slug" --state open --limit 1000 --json number,title,labels)
local json
json="$(gh "${gh_args[@]}" 2>/dev/null)" || {
echo "ERROR: 拉取 issues 失败。请检查仓库权限和网络。" >&2
exit 1
}
# 可选:按 label 过滤
if [ -n "${RUN_ALL_LABEL:-}" ]; then
json="$(echo "$json" | jq -c "[.[] | select(.labels[].name == \"$RUN_ALL_LABEL\")]")"
fi
# 标准化为 {number, title} 数组
ISSUES_JSON="$(echo "$json" | jq -c '[.[] | {number: .number, title: .title}]')"
}
fetch_local_issues() {
local dir="$ISSUES_DIR"
if [ -z "$dir" ]; then
dir="$PROJECT_ROOT/.autoresearch/issues"
fi
# 相对路径转绝对路径
if [[ "$dir" != /* ]]; then
dir="$PROJECT_ROOT/$dir"
fi
if [ ! -d "$dir" ]; then
echo "ERROR: 本地 issue 目录不存在: $dir" >&2
echo "提示: 创建目录并放入 issue-NNN-*.md 文件,或使用 --issues-dir 指定路径" >&2
exit 1
fi
# 扫描 issue-NNN-*.md 文件
local entries=()
for f in "$dir"/issue-*-*.md; do
[ -f "$f" ] || continue
local basename
basename="$(basename "$f")"
# 从 issue-008-feature-request.md 提取编号和标题
local number title
number="$(echo "$basename" | sed -E 's/^issue-0*([0-9]+)-.*/\1/')"
title="$(echo "$basename" | sed -E 's/^issue-[0-9]+-(.*)\.md$/\1/' | tr '-' ' ')"
entries+=("{\"number\": $number, \"title\": $(printf '%s' "$title" | jq -Rs 'rtrimstr("\n")')}")
done
if [ ${#entries[@]} -eq 0 ]; then
ISSUES_JSON="[]"
return
fi
# 组装 JSON 数组
ISSUES_JSON="$(printf '%s\n' "${entries[@]}" | jq -s '.')"
}
fetch_baidu_issues() {
if ! command -v icafe-cli &>/dev/null; then
echo "ERROR: icafe-cli 未安装。请参考 https://icode.baidu.com/articles/help/icafe-cli" >&2
exit 1
fi
if ! icafe-cli login status &>/dev/null 2>&1; then
echo "ERROR: icafe-cli 未登录,请先运行 icafe-cli login" >&2
exit 1
fi
if [ -z "$ICAFE_SPACE" ]; then
echo "ERROR: baidu 模式需要指定 --space=<prefixCode> 或设置 ICAFE_SPACE 环境变量" >&2
exit 1
fi
# 使用 icafe-cli card query 获取未关闭的卡片
local json
json="$(icafe-cli card query --space "$ICAFE_SPACE" --max-records 100 --brief 2>&1)" || {
echo "ERROR: 拉取 iCafe 卡片失败: $json" >&2
echo "提示: 请检查空间名称 ($ICAFE_SPACE) 和网络连接" >&2
exit 1
}
# 解析返回的 JSON,过滤掉已关闭/已完成的卡片
ISSUES_JSON="$(echo "$json" | jq -c '
[(.cards // . // [])[]
| select(
(.status // "" | test("已完成|已关闭|closed"; "i")) | not
)
| {number: .sequence, title: .title}
]
')"
}
fetch_codeup_issues() {
if [ -z "$CODEUP_AK_ID" ]; then
echo "ERROR: codeup 模式需要指定 --codeup-ak-id=<ak_id> 或设置 CODEUP_AK_ID 环境变量" >&2
exit 1
fi
if [ -z "$CODEUP_AK_SECRET" ]; then
echo "ERROR: codeup 模式需要指定 --codeup-ak-secret=<ak_secret> 或设置 CODEUP_AK_SECRET 环境变量" >&2
exit 1
fi
if [ -z "$CODEUP_ORG_ID" ]; then
echo "ERROR: codeup 模式需要指定 --codeup-org=<org_id> 或设置 CODEUP_ORG_ID 环境变量" >&2
exit 1
fi
if [ -z "$CODEUP_REPO_ID" ]; then
echo "ERROR: codeup 模式需要指定 --codeup-repo=<repo_id> 或设置 CODEUP_REPO_ID 环境变量" >&2
exit 1
fi
# 通过 codeup_cli.py (Alibaba Cloud SDK) 获取工作项列表
local cli="$SCRIPT_DIR/codeup_cli.py"
if [ ! -f "$cli" ]; then
echo "ERROR: 找不到 codeup_cli.py: $cli" >&2
exit 1
fi
local json
export CODEUP_AK_ID CODEUP_AK_SECRET CODEUP_ORG_ID
json="$(python3 "$cli" list_issues --state=opened 2>&1)" || {
echo "ERROR: 拉取 Codeup Issues 失败: $json" >&2
exit 1
}
# 标准化为 {number, title} 数组 (serial_number 作为 number)
ISSUES_JSON="$(echo "$json" | jq -c '[.[] | {number: .iid, title: .title}]')"
}
# ==================== 执行获取 ====================
echo "========================================"
echo " autoresearch run_all"
echo " 来源: $ISSUE_SOURCE"
echo " 项目: $PROJECT_ROOT"
if [ "$ISSUE_SOURCE" = "baidu" ]; then
echo " iCafe 空间: $ICAFE_SPACE"
elif [ "$ISSUE_SOURCE" = "codeup" ]; then
echo " Codeup 组织: $CODEUP_ORG_ID"
echo " Codeup 仓库: $CODEUP_REPO_ID"
fi
echo "========================================"
case "$ISSUE_SOURCE" in
github) fetch_github_issues ;;
local) fetch_local_issues ;;
baidu) fetch_baidu_issues ;;
codeup) fetch_codeup_issues ;;
icode)
echo "ERROR: iCode 模式无法自动获取 issue 列表。" >&2
echo "提示: 请在 .autoresearch/issues/ 目录下放置 issue 文件,或使用以下方式之一:" >&2
echo " 1. --issue-source=baidu --space=<space> (如果有对应的 iCafe 空间)" >&2
echo " 2. --issue-source=local --issues-dir=<dir> (使用本地 issue 文件)" >&2
echo " 3. 单独运行: ./run.sh <issue_number> (处理单个 issue)" >&2
exit 1
;;
*)
echo "ERROR: 未知 issue-source: $ISSUE_SOURCE (支持: github, local, baidu, codeup, icode)" >&2
exit 1
;;
esac
ISSUE_COUNT="$(echo "$ISSUES_JSON" | jq 'length')"
if [ "$ISSUE_COUNT" -eq 0 ]; then
echo "没有找到待处理的 issues ($ISSUE_SOURCE 模式)。"
exit 0
fi
echo ""
echo "找到 $ISSUE_COUNT 个待处理 issues ($ISSUE_SOURCE 模式):"
echo "$ISSUES_JSON" | jq -r '.[] | " #\(.number) - \(.title)"'
echo ""
# ==================== DRY RUN 模式 ====================
if [ "${RUN_ALL_DRY_RUN:-}" = "yes" ]; then
echo "[DRY RUN] 以上 issues 将被处理。设置 RUN_ALL_DRY_RUN 不为 yes 以实际执行。"
exit 0
fi
# ==================== 逐个处理 ====================
SUCCESS=0
FAILED=0
SKIPPED=0
FAILED_ISSUES=()
echo "----------------------------------------"
echo "开始逐个处理 issues..."
echo "----------------------------------------"
ISSUE_NUMBERS=($(echo "$ISSUES_JSON" | jq -r '.[].number' | sort -n))
for ISSUE_NUM in "${ISSUE_NUMBERS[@]}"; do
ISSUE_TITLE="$(echo "$ISSUES_JSON" | jq -r ".[] | select(.number == $ISSUE_NUM) | .title")"
echo ""
echo "========================================"
echo " 处理 Issue #$ISSUE_NUM: $ISSUE_TITLE"
echo "========================================"
if bash "$RUN_SH" -c "${RUN_ARGS[@]}" "$ISSUE_NUM"; then
echo "✓ Issue #$ISSUE_NUM 处理完成"
((SUCCESS++)) || true
else
EXIT_CODE=$?
echo "✗ Issue #$ISSUE_NUM 处理失败 (exit code: $EXIT_CODE)"
((FAILED++)) || true
FAILED_ISSUES+=("$ISSUE_NUM")
# 继续处理下一个 issue,不终止
fi
done
# ==================== 汇总报告 ====================
echo ""
echo "========================================"
echo " 批量处理完成"
echo "========================================"
echo " 来源: $ISSUE_SOURCE"
echo " 成功: $SUCCESS"
echo " 失败: $FAILED"
echo " 总计: $ISSUE_COUNT"
if [ ${#FAILED_ISSUES[@]} -gt 0 ]; then
echo ""
echo "失败的 issues:"
for NUM in "${FAILED_ISSUES[@]}"; do
echo " #$NUM"
done
echo ""
echo "可以手动重试失败的 issues:"
echo " ./run.sh ${RUN_ARGS[*]} <issue_number>"
fi
echo ""
if [ "$FAILED" -gt 0 ]; then
exit 1
fi
exit 0