#!/usr/bin/env bash # # githooks/pre-push — 本地编译闸门(OPS-CI-GATE 方案 A) # # 作用:git push 前,对"推送到受保护长期分支 且 涉及 cfc-backend 改动"的 ref # 执行 `mvn -q -DskipTests compile`;编译失败(红构建)则禁止 push。 # 启用:仓库内执行 `git config core.hooksPath githooks`(每位开发者配置一次)。 # 约束:编译闸门仅在 local(开发者本机)与 iwintrue(远端 CI)执行 —— 本 hook 即 local 侧。 # 临时关闭(紧急 bypass):XAF_CI_GATE=0 git push # # 读取 stdin:每行 " " # set -euo pipefail # 允许通过环境变量临时关闭 if [ "${XAF_CI_GATE:-1}" = "0" ]; then echo "[pre-push 编译闸门] XAF_CI_GATE=0,已跳过编译检查。" >&2 exit 0 fi BACKEND_DIR="cfc-backend" ZERO="0000000000000000000000000000000000000000" # 判断本次推送的提交范围是否触及 backend 源码 backend_touched() { local local_sha="$1" remote_sha="$2" if [ "$remote_sha" = "$ZERO" ]; then # 新建分支:与本地 HEAD 的 merge-base 比较 git diff --name-only "$(git merge-base HEAD "$local_sha")" "$local_sha" 2>/dev/null else git diff --name-only "$remote_sha" "$local_sha" 2>/dev/null fi | grep -q "^${BACKEND_DIR}/" } need_compile=0 while read -r local_ref local_sha remote_ref remote_sha; do # 仅对受保护长期分支设闸门;其余分支(个人 feature 等)不拦截,交给远端 CI case "$remote_ref" in refs/heads/cfclub|refs/heads/main|refs/heads/master|refs/heads/release/*) ;; *) continue ;; esac if backend_touched "$local_sha" "$remote_sha"; then need_compile=1 fi done if [ "$need_compile" -ne 1 ]; then exit 0 fi echo "[pre-push 编译闸门] 检测到 cfc-backend 改动,开始编译校验(mvn -q -DskipTests compile)..." >&2 if ! command -v mvn >/dev/null 2>&1; then echo "[pre-push 编译闸门] ❌ 未找到 mvn,无法校验编译。请安装 Maven 并加入 PATH;或确认用 XAF_CI_GATE=0 临时跳过(不推荐,红构建将不被拦截)。" >&2 exit 1 fi if [ ! -d "$BACKEND_DIR" ]; then echo "[pre-push 编译闸门] ⚠️ 未找到 $BACKEND_DIR 目录,跳过(可能非后端仓库)。" >&2 exit 0 fi set +e ( cd "$BACKEND_DIR" && mvn -q -DskipTests compile ) rc=$? set -e if [ "$rc" -ne 0 ]; then echo "[pre-push 编译闸门] ❌ 编译失败(exit=$rc),已阻止 push。请修复后再推送;确认需跳过可用 XAF_CI_GATE=0。" >&2 exit 1 fi echo "[pre-push 编译闸门] ✅ 编译通过,允许 push。" >&2 exit 0