- AGENTS.md: 新增 §20 工具脚本复用 / §21 分析结论复用 / §22 Flaky 门禁,更新文档配置表
- .pi/: 新增 settings.json、rules/guardrails.md、prompts/{debug,review,ship}-gym-manage.md
- .agents/: 新增 Hook 配置与 4 个 Hook 脚本(session-start/pre-agent-check/check-completeness/stop-check)
及 protocols/systematic-debugging.md(check-completeness 含接口链缺口检测)
- scripts/flaky-scan.sh: vitest shuffle 稳定性扫描(gym-manage-web)
- .gitignore: 追踪 AGENTS.md 与 .pi 配置,忽略运行时缓存(todos/taskflows-runs/tokenomy/sessions)
96 lines
3.0 KiB
Bash
96 lines
3.0 KiB
Bash
#!/usr/bin/env bash
|
||
# ============================================================
|
||
# flaky-scan.sh — Vitest 全量 shuffle 稳定性扫描(AGENTS.md §22)
|
||
#
|
||
# 用 --sequence.shuffle 打乱文件与测试执行顺序,暴露顺序依赖型
|
||
# flaky(共享 store 状态 / mock 实现污染 / 全局 stub 残留等)。
|
||
# 目标项目: gym-manage-web(vitest)。通过 --project 可切换。
|
||
#
|
||
# 用法:
|
||
# bash scripts/flaky-scan.sh # gym-manage-web 全量 shuffle 1 次
|
||
# bash scripts/flaky-scan.sh --runs 3 # 全量 shuffle 3 次
|
||
# bash scripts/flaky-scan.sh --spec <file> # 单文件多次 shuffle
|
||
# bash scripts/flaky-scan.sh --project uniapp # gym-manage-uniapp(jest,无 shuffle)
|
||
# bash scripts/flaky-scan.sh --help
|
||
#
|
||
# 退出码: 0 = 全部通过;1 = 存在失败(flaky 或顺序依赖 bug)
|
||
# 失败详情保留在 /tmp/flaky-scan-*.log 供根因定位
|
||
# ============================================================
|
||
|
||
set -uo pipefail
|
||
|
||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||
RUNS=1
|
||
SPEC=""
|
||
PROJECT="web"
|
||
SHUFFLE="--sequence.shuffle"
|
||
|
||
NEXT=""
|
||
for arg in "$@"; do
|
||
case "$arg" in
|
||
--runs=*) RUNS="${arg#--runs=}" ;;
|
||
--spec=*) SPEC="${arg#--spec=}" ;;
|
||
--project=*) PROJECT="${arg#--project=}" ;;
|
||
--runs|--spec|--project) NEXT="$arg" ;;
|
||
--no-shuffle) SHUFFLE="" ;;
|
||
--help|-h)
|
||
sed -n '2,16p' "$0" | sed 's/^# \{0,1\}//'
|
||
exit 0 ;;
|
||
*)
|
||
if [ -n "$NEXT" ]; then
|
||
case "$NEXT" in
|
||
--runs) RUNS="$arg" ;;
|
||
--spec) SPEC="$arg" ;;
|
||
--project) PROJECT="$arg" ;;
|
||
esac
|
||
NEXT=""
|
||
else
|
||
echo "未知参数: ${arg}(--help 查看用法)" >&2
|
||
exit 2
|
||
fi ;;
|
||
esac
|
||
done
|
||
|
||
case "$PROJECT" in
|
||
web) SUB_PROJ="gym-manage-web" ;;
|
||
uniapp|coach) SUB_PROJ="gym-manage-${PROJECT}" ;;
|
||
*) echo "未知项目: ${PROJECT}(web | uniapp | coach)" >&2; exit 2 ;;
|
||
esac
|
||
|
||
[ -d "${PROJECT_DIR}/${SUB_PROJ}" ] || { echo "子项目不存在: ${SUB_PROJ}" >&2; exit 2; }
|
||
|
||
echo "============================================"
|
||
echo " Gym Manage Flaky 稳定性扫描"
|
||
echo " 项目: ${SUB_PROJ}"
|
||
echo " 模式: ${SHUFFLE:-无 shuffle} × $RUNS 次${SPEC:+ (${SPEC})}"
|
||
echo "============================================"
|
||
|
||
FAILED=0
|
||
for i in $(seq 1 "$RUNS"); do
|
||
LOG="/tmp/flaky-scan-$i.log"
|
||
if [ -n "$SPEC" ]; then
|
||
(cd "${PROJECT_DIR}/${SUB_PROJ}" && NODE_ENV=test npx vitest run $SHUFFLE "$SPEC" > "$LOG" 2>&1)
|
||
else
|
||
(cd "${PROJECT_DIR}/${SUB_PROJ}" && NODE_ENV=test npx vitest run $SHUFFLE > "$LOG" 2>&1)
|
||
fi
|
||
EXIT=$?
|
||
SUMMARY=$(grep -E "Tests " "$LOG" | tail -1)
|
||
if [ "$EXIT" -eq 0 ]; then
|
||
echo "run $i/$RUNS: ✅ $SUMMARY"
|
||
else
|
||
echo "run $i/$RUNS: ❌ exit=$EXIT $SUMMARY"
|
||
grep -E "^ FAIL" "$LOG" | head -10
|
||
FAILED=1
|
||
fi
|
||
done
|
||
|
||
echo "--------------------------------------------"
|
||
if [ "$FAILED" -eq 0 ]; then
|
||
echo " 扫描通过:${RUNS} 次运行 0 flaky ✅"
|
||
exit 0
|
||
else
|
||
echo " 发现 flaky/顺序依赖(详见 /tmp/flaky-scan-*.log) ❌"
|
||
exit 1
|
||
fi
|