forked from Gitlink/gitlink-cli
166 lines
7.6 KiB
Bash
166 lines
7.6 KiB
Bash
#!/usr/bin/env bash
|
||
# =============================================================================
|
||
# GitLink-CLI 子任务一 全量验证脚本(对齐 doc/DEMO-SCRIPT-SUBTASK1.md)
|
||
#
|
||
# 七段验证(每段独立,可单独跑:./verify.sh <段号>,如 ./verify.sh 5):
|
||
# 1 编译 + 静态检查
|
||
# 2 单元测试 + 覆盖率(≥80%)
|
||
# 3 命令注册冒烟(show / demo / 8 个新 shortcut 模块)
|
||
# 4 能力探测(需 GITLINK_TOKEN;无则跳过)
|
||
# 5 终端↔网页联动(Demo Mock:show + html_url + demo +run --list)
|
||
# 6 五大类功能 E2E(Demo Mock + 真机可选)
|
||
# 7 format 统一 + --debug 增强(Demo Mock)
|
||
#
|
||
# 退出码:0 全绿;非 0 表示有失败段。
|
||
# =============================================================================
|
||
set -uo pipefail
|
||
|
||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||
cd "$ROOT"
|
||
|
||
# Windows 默认二进制是 .exe;Linux/macOS 无后缀。
|
||
if [ -x "$ROOT/gitlink-cli.exe" ]; then BIN="$ROOT/gitlink-cli.exe"
|
||
elif [ -x "$ROOT/gitlink-cli" ]; then BIN="$ROOT/gitlink-cli"
|
||
else BIN="" # 将在段3前构建
|
||
fi
|
||
|
||
PASS=0; FAIL=0; SKIP=0
|
||
GREEN='\033[32m'; RED='\033[31m'; YEL='\033[1;33m'; BOLD='\033[1m'; RST='\033[0m'
|
||
|
||
section(){ printf "\n${BOLD}━━━ 段 %s : %s ━━━${RST}\n" "$1" "$2"; }
|
||
ok() { printf " ${GREEN}✓${RST} %s\n" "$1"; PASS=$((PASS+1)); }
|
||
ng() { printf " ${RED}✗${RST} %s\n" "$1"; FAIL=$((FAIL+1)); }
|
||
skip() { printf " ${YEL}⊘${RST} %s\n" "$1"; SKIP=$((SKIP+1)); }
|
||
contain() { grep -q "$1" <<<"$2"; }
|
||
|
||
# 选段:若传了段号,只跑该段。
|
||
SELECTED="${1:-all}"
|
||
run_section(){ [ "$SELECTED" = "all" ] || [ "$SELECTED" = "$1" ]; }
|
||
|
||
# ----------------------------------------------------------------------------
|
||
section 1 "编译 + 静态检查"
|
||
if run_section 1; then
|
||
if go build -o "$ROOT/.gitlink-cli.verify" . 2>err.log; then
|
||
BIN="$ROOT/.gitlink-cli.verify"; ok "go build"
|
||
else ng "go build: $(cat err.log)"; fi
|
||
if go vet ./... >err.log 2>&1; then ok "go vet"; else ng "go vet: $(cat err.log)"; fi
|
||
if [ -z "$(gofmt -s -l . 2>/dev/null | grep -v '^vendor/')" ]; then ok "gofmt -s"
|
||
else ng "gofmt -s: $(gofmt -s -l . | head -3)"; fi
|
||
if go run ./internal/i18n/cmd/check >err.log 2>&1; then ok "i18n check"
|
||
else skip "i18n check (容许 P2 前未全覆盖)"; fi
|
||
fi
|
||
|
||
# ----------------------------------------------------------------------------
|
||
section 2 "单元测试 + 覆盖率(≥80%)"
|
||
if run_section 2; then
|
||
# -race 留给 CI 的 Linux runner;Windows 本地 race runtime 的 DLL 依赖不稳。
|
||
RACE_FLAG=""
|
||
[ "$(go env GOOS)" != "windows" ] && RACE_FLAG="-race"
|
||
if go test $RACE_FLAG -coverprofile=coverage.verify.out ./... >test.log 2>&1; then
|
||
ok "go test ${RACE_FLAG:-(no-race)} 全绿"
|
||
else ng "go test 失败(见 test.log)"; tail -5 test.log; fi
|
||
COV=$(go tool cover -func=coverage.verify.out 2>/dev/null | grep '^total:' | awk '{print $3}' | tr -d '%')
|
||
COVI=${COV%.*}
|
||
if [ -n "$COVI" ] && [ "$COVI" -ge 80 ]; then ok "覆盖率 ${COV}% ≥ 80%"
|
||
else ng "覆盖率 ${COV:-?}% < 80%"; fi
|
||
fi
|
||
|
||
# ----------------------------------------------------------------------------
|
||
section 3 "命令注册冒烟"
|
||
if run_section 3; then
|
||
[ -z "$BIN" ] && { ng "无二进制可执行(先 go build)"; }
|
||
if [ -n "$BIN" ]; then
|
||
HELP=$("$BIN" --help 2>&1 || true)
|
||
for c in show demo browse status alias auth config api version; do
|
||
contain "$c" "$HELP" && ok "$c 注册" || ng "$c 未注册"
|
||
done
|
||
# 8 个新 shortcut 模块(第一类)
|
||
for grp in webhook wiki pm pipeline label member milestone notification; do
|
||
"$BIN" "$grp" --help >/dev/null 2>&1 && ok "$grp +help" || ng "$grp +help"
|
||
done
|
||
fi
|
||
fi
|
||
|
||
# ----------------------------------------------------------------------------
|
||
section 4 "能力探测(需 GITLINK_TOKEN)"
|
||
if run_section 4; then
|
||
if [ -z "${GITLINK_TOKEN:-}" ]; then
|
||
skip "段4 跳过(未设置 GITLINK_TOKEN)"
|
||
elif [ -z "$BIN" ]; then ng "无二进制"
|
||
else
|
||
OUT=$("$BIN" capability +check 2>&1 || true)
|
||
contain "label" "$OUT" && ok "capability +check 探测到模块" || ng "capability +check 无输出"
|
||
fi
|
||
fi
|
||
|
||
# ----------------------------------------------------------------------------
|
||
section 5 "终端↔网页联动(Demo Mock)"
|
||
if run_section 5 && [ -n "$BIN" ]; then
|
||
# show repo
|
||
OUT=$("$BIN" show repo --owner jiangtx --repo gitlink-cli-demo 2>&1)
|
||
contain "gitlink.org.cn/jiangtx/gitlink-cli-demo" "$OUT" && ok "show repo URL" || ng "show repo URL"
|
||
# show issue JSON html_url
|
||
OUT=$("$BIN" show issue --owner jiangtx --repo demo --number 42 --format json 2>&1)
|
||
contain '"html_url"' "$OUT" && ok "show issue JSON html_url" || ng "show issue html_url"
|
||
# show 各实体
|
||
for ent in webhook wiki label milestone member ci; do
|
||
"$BIN" show "$ent" --owner o --repo r >/dev/null 2>&1 && ok "show $ent" || ng "show $ent"
|
||
done
|
||
# demo +run --list
|
||
OUT=$("$BIN" demo +run --list 2>&1)
|
||
contain "showcase" "$OUT" && ok "demo +run --list" || ng "demo +run --list"
|
||
# browse --list / --no-open
|
||
OUT=$("$BIN" browse --owner o --repo r --list 2>&1)
|
||
contain "issues" "$OUT" && ok "browse --list" || ng "browse --list"
|
||
OUT=$("$BIN" browse --owner o --repo r --no-open issues/42 2>&1)
|
||
contain "/issues/42" "$OUT" && ok "browse --no-open issues/42" || ng "browse --no-open"
|
||
fi
|
||
|
||
# ----------------------------------------------------------------------------
|
||
section 6 "五大类功能 E2E(Demo Mock)"
|
||
if run_section 6 && [ -n "$BIN" ]; then
|
||
export GITLINK_DEMO=1
|
||
# 第一类:新增模块的 list
|
||
for cmd in "webhook +list --owner o --repo r" "label +list --owner o --repo r" \
|
||
"milestone +list --owner o --repo r" "member +list --owner o --repo r" \
|
||
"notification +list"; do
|
||
OUT=$("$BIN" $cmd 2>&1 || true)
|
||
(contain '"ok": true' "$OUT" || contain '"status":0' "$OUT") \
|
||
&& ok "第一类: $cmd" || ng "第一类: $cmd → $OUT"
|
||
done
|
||
# 第二类:三种输出格式
|
||
for fmt in json table yaml; do
|
||
OUT=$("$BIN" repo +list --format "$fmt" 2>&1 || true)
|
||
[ -n "$OUT" ] && ok "第二类: repo +list --format $fmt" || ng "第二类: --format $fmt"
|
||
done
|
||
# 第三类:批量 dry-run
|
||
OUT=$("$BIN" issue +batch-close --owner o --repo r --numbers 1,2,3 --dry-run 2>&1 || true)
|
||
(contain "DRY RUN" "$OUT" || contain '"ok": true' "$OUT") \
|
||
&& ok "第三类: issue +batch-close --dry-run" || ng "第三类: batch-close → $OUT"
|
||
# 第五类:Raw API 补全
|
||
OUT=$("$BIN" repo +languages --owner o --repo r 2>&1 || true)
|
||
(contain '"ok": true' "$OUT" || contain "Go" "$OUT") \
|
||
&& ok "第五类: repo +languages" || ng "第五类: repo +languages → $OUT"
|
||
unset GITLINK_DEMO
|
||
fi
|
||
|
||
# ----------------------------------------------------------------------------
|
||
section 7 "format 统一 + --debug 增强"
|
||
if run_section 7 && [ -n "$BIN" ]; then
|
||
export GITLINK_DEMO=1
|
||
OUT=$("$BIN" alias +list --format json 2>&1 || true)
|
||
contain '"ok": true' "$OUT" && ok "alias --format json 走 output" || skip "alias format(P1-2 前可能未统一)"
|
||
OUT=$("$BIN" issue +list --owner o --repo r --debug 2>&1 || true)
|
||
(contain "→ GET" "$OUT" || contain "→ POST" "$OUT") \
|
||
&& ok "--debug 打印请求行" || ng "--debug 请求行"
|
||
contain "Bearer \*\*\*" "$OUT" && ok "--debug Authorization redact" \
|
||
|| skip "--debug Header redact(P2-2 前未实现)"
|
||
unset GITLINK_DEMO
|
||
fi
|
||
|
||
# ----------------------------------------------------------------------------
|
||
printf "\n${BOLD}━━━ 汇总 ━━━${RST}\n"
|
||
printf " ${GREEN}通过: %d${RST} ${RED}失败: %d${RST} ${YEL}跳过: %d${RST}\n" "$PASS" "$FAIL" "$SKIP"
|
||
rm -f "$ROOT/.gitlink-cli.verify" err.log test.log 2>/dev/null
|
||
[ "$FAIL" -eq 0 ]
|