#!/usr/bin/env bash # ============================================================================= # pre-commit — 提交前自动守卫 # ============================================================================= # 做三件事(任一失败即阻断提交): # 1. guard_arch.js — 扫描新增/修改行,禁止在 Vue 组件里内联金额计算 # 2. jest — 跑前端单测,确保不引入回归 # 3. bundle 校验 — rebuild-bundles.py --verify,拦截"改源文件忘重新打 bundle" # # 安装方式(开发者只需执行一次): # cd # cp YLErpWeb/fe-tests/hooks/pre-commit .git/hooks/pre-commit # chmod +x .git/hooks/pre-commit # # 跳过方式(紧急情况,不推荐): # git commit --no-verify # # CI 也应调用本脚本(或等价的 npm test + node guard_arch.js)。 # ============================================================================= set -euo pipefail # 定位仓库根目录 REPO_ROOT=$(git rev-parse --show-toplevel) FE_TESTS_DIR="$REPO_ROOT/YLErpWeb/fe-tests" # 自动加载 nvm(非交互 shell 中 nvm 不会自动加载) export NVM_DIR="${NVM_DIR:-$HOME/.nvm}" if [ -s "$NVM_DIR/nvm.sh" ] && ! command -v node &>/dev/null; then source "$NVM_DIR/nvm.sh" 2>/dev/null || true # 如果有 .nvmrc 就用它,否则用默认版本 if [ -f "$REPO_ROOT/.nvmrc" ]; then nvm use --silent 2>/dev/null || true else # 尝试用已安装的最新版本 nvm use --silent --lts 2>/dev/null || nvm use --silent node 2>/dev/null || true fi fi # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color echo -e "${YELLOW}[pre-commit] 开始提交前守卫检查...${NC}" # ----------------------------------------------------------------------------- # 1. guard_arch.js — 架构闸门(零依赖,纯 Node) # ----------------------------------------------------------------------------- # 只在存在 node 时运行 if command -v node &>/dev/null; then echo -e "${YELLOW}[pre-commit] ① 架构闸门 (guard_arch.js)...${NC}" if node "$FE_TESTS_DIR/guard_arch.js"; then echo -e "${GREEN}[pre-commit] ✅ 架构闸门通过${NC}" else echo -e "${RED}[pre-commit] ❌ 架构闸门未通过,提交被阻断${NC}" echo -e "${YELLOW} 请把金额/精度计算抽到 *Calc 模块(参考 swapCalc.js)${NC}" exit 1 fi else echo -e "${YELLOW}[pre-commit] ⚠️ 未找到 node,跳过架构闸门(建议安装 nvm + node 20)${NC}" fi # ----------------------------------------------------------------------------- # 2. jest — 前端单测(需要先 npm install) # ----------------------------------------------------------------------------- if [ -f "$FE_TESTS_DIR/node_modules/.bin/jest" ]; then echo -e "${YELLOW}[pre-commit] ② 前端单测 (jest)...${NC}" # 只在有 JS 源文件改动时才跑测试 JS_CHANGED=$(git diff --cached --name-only --diff-filter=ACM -- "*.js" | grep "wwwroot/Scripts/" || true) if [ -z "$JS_CHANGED" ]; then echo -e "${GREEN}[pre-commit] ⏭️ 无前端源文件改动,跳过单测${NC}" else echo -e "${YELLOW} 改动的前端文件:${NC}" echo "$JS_CHANGED" | sed 's/^/ /' if (cd "$FE_TESTS_DIR" && npx jest --no-coverage --silent 2>&1); then echo -e "${GREEN}[pre-commit] ✅ 前端单测通过${NC}" else echo -e "${RED}[pre-commit] ❌ 前端单测未通过,提交被阻断${NC}" echo -e "${YELLOW} 修复测试后重新提交,或用 git commit --no-verify 跳过(不推荐)${NC}" exit 1 fi fi else echo -e "${YELLOW}[pre-commit] ⚠️ 未安装 jest(node_modules 缺失),跳过单测${NC}" echo -e "${YELLOW} 建议:cd YLErpWeb/fe-tests && npm install${NC}" fi # ----------------------------------------------------------------------------- # 3. bundle 版本一致性 — 拦截"改了源文件却忘重新打 bundle" # ----------------------------------------------------------------------------- # EQD-6838 踩坑:8 次提交只为解决"改源文件没生效"。本检查在提交前用 # rebuild-bundles.py --verify 逐字节比对产物与源文件,不同步则阻断。 # 仅在有 bundle 相关改动时跑(Scripts 源文件 或 bundles 产物 任一改动)。 if command -v python &>/dev/null || command -v python3 &>/dev/null; then # 选可用的 python:优先 python(Windows 上 python3 可能是微软 Store 的 stub,不可用) if command -v python &>/dev/null && python -c 'print(1)' &>/dev/null; then PY=python else PY=python3 fi BUNDLE_SRC_CHANGED=$(git diff --cached --name-only --diff-filter=ACM -- "*.js" | grep "wwwroot/Scripts/" || true) BUNDLE_OUT_CHANGED=$(git diff --cached --name-only --diff-filter=ACM -- "YLErpWeb/wwwroot/Statics/bundles/" || true) if [ -n "$BUNDLE_SRC_CHANGED" ] || [ -n "$BUNDLE_OUT_CHANGED" ]; then echo -e "${YELLOW}[pre-commit] ③ bundle 版本一致性 (rebuild-bundles.py --verify)...${NC}" if ($PY "$REPO_ROOT/YLErpWeb/rebuild-bundles.py" --verify 2>&1); then echo -e "${GREEN}[pre-commit] ✅ bundle 产物与源文件同步${NC}" else echo -e "${RED}[pre-commit] ❌ bundle 产物与源文件不同步,提交被阻断${NC}" echo -e "${YELLOW} 请运行:python YLErpWeb/rebuild-bundles.py 重建并提交产物${NC}" echo -e "${YELLOW} 或用 git commit --no-verify 跳过(不推荐)${NC}" exit 1 fi else echo -e "${GREEN}[pre-commit] ⏭️ 无 bundle 相关改动,跳过 bundle 校验${NC}" fi else echo -e "${YELLOW}[pre-commit] ⚠️ 未找到 python,跳过 bundle 校验${NC}" fi echo -e "${GREEN}[pre-commit] ✅ 所有守卫检查通过,继续提交${NC}" exit 0