已合并
新增 pre-push 本地编译门禁脚本,将 CI 质量门禁左移到开发者本地,在 git push 时自动触发构建与 UT 检查。 #8563
chenqi317创建于 23 天前
新增 pre-push 本地编译门禁脚本,将 CI 质量门禁左移到开发者本地,在 git push 时自动触发构建与 UT 检查。 #8563
已合并
共 3 个文件变更+494-3
| @@ -76,3 +76,19 @@ repos: | |||
| 76 | types: [file] | 76 | types: [file] |
| 77 | stages: [pre-commit] | 77 | stages: [pre-commit] |
| 78 | verbose: true | 78 | verbose: true |
| 79 | + | ||
| 80 | + # pre-push 本地编译门禁(构建 + UT) | ||
| 81 | + # 安装:pre-commit install --hook-type pre-push | ||
| 82 | + # 旁路:git push --no-verify / SKIP=pre-push-build git push / PRE_PUSH_BUILD=0 git push | ||
| 83 | + # 默认即快速增量模式(有漏检风险,合入前需跑完整模式) | ||
| 84 | + # 完整对齐模式:PRE_PUSH_FULL=1 git push(100% 复刻 CI 门禁语义) | ||
| 85 | + - repo: local | ||
| 86 | + hooks: | ||
| 87 | + - id: pre-push-build | ||
| 88 | + name: Pre-Push Build & UT Gate | ||
| 89 | + entry: bash scripts/ci/pre_push_build.sh | ||
| 90 | + language: system | ||
| 91 | + pass_filenames: false | ||
| 92 | + require_serial: true | ||
| 93 | + stages: [pre-push] | ||
| 94 | + verbose: true | ||
| @@ -244,12 +244,14 @@ done | |||
| 244 | echo "related op: ${builtin_ops_name[*]}" | 244 | echo "related op: ${builtin_ops_name[*]}" |
| 245 | echo "related experimental op: ${experimental_ops_name[*]}" | 245 | echo "related experimental op: ${experimental_ops_name[*]}" |
| 246 | echo "need build all: ${build_all}" | 246 | echo "need build all: ${build_all}" |
| 247 | - | 247 | +echo "force_jit: ${force_jit}" |
| 248 | a5_soc="ascend950" | 248 | a5_soc="ascend950" |
| 249 | 249 | ||
| 250 | -if [[ ${#builtin_ops_name[@]} -gt 0 && "$force_jit" = "false" ]]; then | 250 | +if [[ ${#builtin_ops_name[@]} -gt 0 ]]; then |
| 251 | builtin_ops_str=$(IFS=,; echo "${builtin_ops_name[*]}") | 251 | builtin_ops_str=$(IFS=,; echo "${builtin_ops_name[*]}") |
| 252 | - build_cmd="bash build.sh --pkg --ops=$builtin_ops_str --soc=$a5_soc ${THREAD_NUM} --cann_3rd_lib_path=${ASCEND_3RD_LIB_PATH} ${force}" | 252 | + jit_flag="" |
| 253 | + [[ "$force_jit" == "true" ]] && jit_flag="--jit" | ||
| 254 | + build_cmd="bash build.sh --pkg ${jit_flag} --ops=$builtin_ops_str --soc=$a5_soc ${THREAD_NUM} --cann_3rd_lib_path=${ASCEND_3RD_LIB_PATH} ${force}" | ||
| 253 | run_build_command "$build_cmd" | 255 | run_build_command "$build_cmd" |
| 254 | execute_run_file "custom" | 256 | execute_run_file "custom" |
| 255 | fi | 257 | fi |
| @@ -0,0 +1,473 @@ | |||
| 1 | +#!/bin/bash | ||
[MAJOR] 473行 Shell 脚本建议在开头顶部添加 文件: ![]() ![]() | |||
| 2 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 3 | +# Copyright (c) 2026 Huawei Technologies Co., Ltd. | ||
| 4 | +# This program is free software, you can redistribute it and/or modify it under the terms and conditions of | ||
| 5 | +# CANN Open Software License Agreement Version 2.0 (the "License"). | ||
| 6 | +# Please refer to the License for details. You may not use this file except in compliance with the License. | ||
| 7 | +# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, | ||
| 8 | +# INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | ||
| 9 | +# See LICENSE in the root of the software repository for the full text of the License. | ||
| 10 | +# ----------------------------------------------------------------------------------------------------------- | ||
| 11 | +# ============================================================================ | ||
| 12 | +# pre-push 本地编译门禁脚本 | ||
| 13 | +# 用途:在 git push 前触发本地构建与 UT,将门禁质量左移到本地,保障远程门禁成功率。 | ||
| 14 | +# | ||
| 15 | +# 运行模式: | ||
| 16 | +# 默认(快速增量模式):按变更模块精简编译范围,耗时短但有漏检风险。 | ||
| 17 | +# PRE_PUSH_FULL=1(完整对齐模式):直接调用 scripts/ci/local_build.sh,100% 复刻 CI 门禁语义。 | ||
| 18 | +# | ||
| 19 | +# 旁路方式: | ||
| 20 | +# git push --no-verify | ||
| 21 | +# SKIP=pre-push-build git push | ||
| 22 | +# PRE_PUSH_BUILD=0 git push | ||
| 23 | +# ============================================================================ | ||
| 24 | + | ||
| 25 | +set -eo pipefail | ||
| 26 | + | ||
| 27 | +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| 28 | +WORKSPACE="$(dirname "$(dirname "$SCRIPT_DIR")")" | ||
| 29 | +cd "$WORKSPACE" | ||
| 30 | + | ||
| 31 | +# --------------------------------------------------------------------------- | ||
| 32 | +# 0. 旁路控制 | ||
| 33 | +# --------------------------------------------------------------------------- | ||
| 34 | +if [[ "${PRE_PUSH_BUILD:-1}" == "0" ]]; then | ||
| 35 | + echo "[pre-push] PRE_PUSH_BUILD=0, skipping pre-push build gate." | ||
| 36 | + exit 0 | ||
| 37 | +fi | ||
| 38 | + | ||
| 39 | +if [[ -n "${SKIP:-}" && "$SKIP" == *"pre-push-build"* ]]; then | ||
| 40 | + echo "[pre-push] SKIP=pre-push-build, skipping pre-push build gate." | ||
| 41 | + exit 0 | ||
| 42 | +fi | ||
| 43 | + | ||
| 44 | +# --------------------------------------------------------------------------- | ||
| 45 | +# 1. 环境自检 | ||
| 46 | +# --------------------------------------------------------------------------- | ||
| 47 | +THREAD_NUM=${THREAD_NUM:-$(grep -c ^processor /proc/cpuinfo)} | ||
| 48 | +BASE_BRANCH_NAME=${BASE_BRANCH_NAME:-master} | ||
| 49 | +PR_FILELIST="pr_filelist.txt" | ||
| 50 | + | ||
| 51 | +# 检查 CANN Toolkit 环境是否安装 | ||
| 52 | +cann_installed=false | ||
| 53 | +for _cann_dir in "${ASCEND_HOME_PATH:-}" "${ASCEND_TOOLKIT_HOME:-}" "/usr/local/Ascend/ascend-toolkit/latest"; do | ||
| 54 | + [[ -z "$_cann_dir" ]] && continue | ||
| 55 | + if [[ -f "$_cann_dir/set_env.sh" ]]; then | ||
| 56 | + cann_installed=true | ||
| 57 | + break | ||
| 58 | + fi | ||
| 59 | +done | ||
| 60 | +if [[ "$cann_installed" == "false" ]]; then | ||
| 61 | + echo -e "\033[31m[pre-push][WARN] 环境未检测到 CANN 包,跳过 pre-push 检查,带风险提交。\033[0m" | ||
| 62 | + exit 0 | ||
| 63 | +fi | ||
| 64 | + | ||
| 65 | +# 检查关键脚本是否存在 | ||
| 66 | +if [[ ! -f "$WORKSPACE/scripts/ci/local_build.sh" ]]; then | ||
| 67 | + echo "[pre-push][ERROR] scripts/ci/local_build.sh not found." | ||
| 68 | + exit 1 | ||
| 69 | +fi | ||
| 70 | + | ||
| 71 | +# 日志辅助:同时输出到终端和 pre_push_build.log | ||
| 72 | +log_echo() { | ||
| 73 | + echo "$@" | tee -a pre_push_build.log | ||
| 74 | +} | ||
| 75 | + | ||
| 76 | +# --------------------------------------------------------------------------- | ||
| 77 | +# 2. 计算变更文件清单(复用 local_build.sh 的 git diff 逻辑) | ||
| 78 | +# --------------------------------------------------------------------------- | ||
| 79 | +calc_changed_files() { | ||
| 80 | + local target_url="https://gitcode.com/cann/ops-nn.git" | ||
| 81 | + local remote_name="" | ||
| 82 | + for remote in $(git remote); do | ||
| 83 | + local url | ||
| 84 | + url=$(git remote get-url "$remote" 2>/dev/null || true) | ||
| 85 | + if [[ "$url" == *"$target_url"* || "$url" == *"${target_url%.git}"* ]]; then | ||
| 86 | + remote_name="$remote" | ||
| 87 | + break | ||
| 88 | + fi | ||
| 89 | + done | ||
| 90 | + if [[ -z "$remote_name" ]]; then | ||
| 91 | + if git remote | grep -q "^origin$"; then | ||
| 92 | + remote_name="origin" | ||
| 93 | + else | ||
| 94 | + log_echo "[pre-push][ERROR] No remote found for git diff calculation." | ||
| 95 | + exit 1 | ||
| 96 | + fi | ||
| 97 | + fi | ||
| 98 | + | ||
| 99 | + log_echo "[pre-push] Remote: $remote_name ($(git remote get-url $remote_name))" | ||
| 100 | + log_echo "[pre-push] Fetching latest from $remote_name..." | ||
| 101 | + git fetch "$remote_name" --quiet --prune 2>/dev/null || true | ||
| 102 | + | ||
| 103 | + local remote_ref="${remote_name}/${BASE_BRANCH_NAME}" | ||
| 104 | + if ! git rev-parse --verify "$remote_ref" >/dev/null 2>&1; then | ||
| 105 | + log_echo "[pre-push][ERROR] Remote branch '$remote_ref' does not exist." | ||
| 106 | + git branch -r --list "${remote_name}/*" | ||
| 107 | + exit 1 | ||
| 108 | + fi | ||
| 109 | + | ||
| 110 | + local merge_base target_commit | ||
| 111 | + merge_base=$(git merge-base "$remote_ref" HEAD 2>/dev/null || true) | ||
| 112 | + if [[ -z "$merge_base" ]]; then | ||
| 113 | + log_echo "[pre-push][ERROR] Could not find merge-base with $remote_ref." | ||
| 114 | + exit 1 | ||
| 115 | + fi | ||
| 116 | + target_commit=$(git rev-parse HEAD) | ||
| 117 | + | ||
| 118 | + local changed_files | ||
| 119 | + changed_files=$(git diff --name-only "$merge_base" "$target_commit" | sort -u) | ||
| 120 | + if [[ -z "$changed_files" ]]; then | ||
| 121 | + log_echo "[pre-push][WARN] No changed files found. Please check whether the code has been committed." | ||
| 122 | + exit 0 | ||
| 123 | + fi | ||
| 124 | + | ||
| 125 | + echo "$changed_files" > "$PR_FILELIST" | ||
| 126 | + local total | ||
| 127 | + total=$(wc -l < "$PR_FILELIST") | ||
| 128 | + log_echo "[pre-push] Changed files: $total" | ||
| 129 | + log_echo "[pre-push] --- Changed File List ---" | ||
| 130 | + while IFS= read -r f; do | ||
| 131 | + [[ -z "$f" ]] && continue | ||
| 132 | + log_echo " $f" | ||
| 133 | + done < "$PR_FILELIST" | ||
| 134 | + log_echo "[pre-push] ---------------------------" | ||
| 135 | +} | ||
| 136 | + | ||
| 137 | +# --------------------------------------------------------------------------- | ||
| 138 | +# 3. 四步识别(用于快速模式与日志展示) | ||
| 139 | +# --------------------------------------------------------------------------- | ||
| 140 | +identify_changes() { | ||
| 141 | + has_kernel=false | ||
| 142 | + has_host=false | ||
| 143 | + has_api=false | ||
| 144 | + has_graph=false | ||
| 145 | + has_experimental=false | ||
| 146 | + has_arch35=false | ||
| 147 | + need_jit_build=false | ||
| 148 | + md_only=true | ||
| 149 | + kernel_ops="" | ||
| 150 | + arch_list=() | ||
| 151 | + | ||
| 152 | + while IFS= read -r f; do | ||
| 153 | + [[ -z "$f" ]] && continue | ||
| 154 | + case "$f" in | ||
| 155 | + */op_kernel/*) has_kernel=true; md_only=false ;; | ||
| 156 | + */op_host/*) has_host=true; md_only=false ;; | ||
| 157 | + */op_api/*) has_api=true; md_only=false ;; | ||
| 158 | + */op_graph/*) has_graph=true; md_only=false ;; | ||
| 159 | + */examples/*) md_only=false ;; | ||
| 160 | + experimental/*) has_experimental=true; md_only=false ;; | ||
| 161 | + *.md|*.json|*.ini|*.txt|*.yaml|*.yml|cmake/*|scripts/*) ;; | ||
| 162 | + *) md_only=false ;; | ||
| 163 | + esac | ||
| 164 | + # 目录包含 arch35 或 op_kernel 不触发 JIT,配置/脚本也不触发 | ||
| 165 | + case "$f" in | ||
| 166 | + */arch35/*) ;; | ||
| 167 | + */op_kernel/*) ;; | ||
| 168 | + *.md|*.json|*.ini|*.txt|*.yaml|*.yml|cmake/*|scripts/*) ;; | ||
| 169 | + *) need_jit_build=true ;; | ||
| 170 | + esac | ||
| 171 | + # arch 识别 | ||
| 172 | + case "$f" in | ||
| 173 | + */arch35/*) arch_list+=("ascend950"); has_arch35=true ;; | ||
| 174 | + */arch22/*) arch_list+=("ascend910b") ;; | ||
| 175 | + */arch20/*) arch_list+=("ascend310p") ;; | ||
| 176 | + esac | ||
| 177 | + done < "$PR_FILELIST" | ||
| 178 | + | ||
| 179 | + # 去重 arch_list | ||
| 180 | + if [[ ${#arch_list[@]} -gt 0 ]]; then | ||
| 181 | + mapfile -t arch_list < <(printf '%s\n' "${arch_list[@]}" | sort -u) | ||
| 182 | + fi | ||
| 183 | + | ||
| 184 | + log_echo "[pre-push] --- Change Identification ---" | ||
| 185 | + log_echo "[pre-push] op_kernel : $has_kernel" | ||
| 186 | + log_echo "[pre-push] op_host : $has_host" | ||
| 187 | + log_echo "[pre-push] op_api : $has_api" | ||
| 188 | + log_echo "[pre-push] op_graph : $has_graph" | ||
| 189 | + log_echo "[pre-push] experimental: $has_experimental" | ||
| 190 | + log_echo "[pre-push] md_only : $md_only" | ||
| 191 | + log_echo "[pre-push] need_jit_build: $need_jit_build" | ||
| 192 | + if [[ ${#arch_list[@]} -gt 0 ]]; then | ||
| 193 | + log_echo "[pre-push] arch : ${arch_list[*]}" | ||
| 194 | + else | ||
| 195 | + log_echo "[pre-push] arch : default (affects all SOC)" | ||
| 196 | + fi | ||
| 197 | + log_echo "[pre-push] -----------------------------" | ||
| 198 | +} | ||
| 199 | + | ||
| 200 | +# --------------------------------------------------------------------------- | ||
| 201 | +# 3b. 打印本次将执行的环节与命令概览 | ||
| 202 | +# --------------------------------------------------------------------------- | ||
| 203 | +print_pipeline() { | ||
| 204 | + local mode | ||
| 205 | + if [[ "${PRE_PUSH_FULL:-0}" == "1" ]]; then | ||
| 206 | + mode="FULL" | ||
| 207 | + else | ||
| 208 | + mode="FAST" | ||
| 209 | + fi | ||
| 210 | + | ||
| 211 | + log_echo "" | ||
| 212 | + log_echo "====================================================================" | ||
| 213 | + log_echo " Pipeline Preview (mode: $mode)" | ||
| 214 | + log_echo "====================================================================" | ||
| 215 | + | ||
| 216 | + if [[ "$mode" == "FULL" ]]; then | ||
| 217 | + log_echo " [1] JIT build : bash build.sh --pkg --jit -j${THREAD_NUM}" | ||
| 218 | + log_echo " [2] ophost UT : bash build.sh -u --ophost -f $PR_FILELIST -j${THREAD_NUM}" | ||
| 219 | + log_echo " [3] opapi UT : bash build.sh -u --opapi -f $PR_FILELIST -j${THREAD_NUM}" | ||
| 220 | + if [[ "$BASE_BRANCH_NAME" == "master" ]]; then | ||
| 221 | + log_echo " [4] opgraph UT : bash build.sh -u --opgraph -f $PR_FILELIST -j${THREAD_NUM}" | ||
| 222 | + log_echo " [5] opkernel UT : bash scripts/ci/check_kernel_ut.sh $PR_FILELIST --no_cov" | ||
| 223 | + fi | ||
| 224 | + log_echo " [6] single-op pkg : bash scripts/ci/check_pkg.sh $PR_FILELIST -j${THREAD_NUM} --no_force" | ||
| 225 | + log_echo " [7] ascend950 pkg : bash scripts/ci/compile_ascend950_pkg.sh $PR_FILELIST --no_force -j${THREAD_NUM}" | ||
| 226 | + log_echo " [8] A2 smoke : bash scripts/ci/check_example.sh $PR_FILELIST (needs 910B)" | ||
| 227 | + log_echo " [9] experimental pkg : bash scripts/ci/check_experimental_pkg.sh $PR_FILELIST" | ||
| 228 | + else | ||
| 229 | + local idx=1 | ||
| 230 | + if [[ "$need_jit_build" == "true" ]]; then | ||
| 231 | + log_echo " [$idx] JIT build : bash build.sh --pkg --jit -j${THREAD_NUM}" | ||
| 232 | + idx=$((idx+1)) | ||
| 233 | + else | ||
| 234 | + log_echo " [--] JIT build : SKIP (arch35/op_kernel only)" | ||
| 235 | + fi | ||
| 236 | + if [[ "$has_host" == "true" ]]; then | ||
| 237 | + log_echo " [$idx] ophost UT : bash build.sh -u --ophost -f $PR_FILELIST -j${THREAD_NUM}" | ||
| 238 | + idx=$((idx+1)) | ||
| 239 | + else | ||
| 240 | + log_echo " [--] ophost UT : SKIP (op_host not changed)" | ||
| 241 | + fi | ||
| 242 | + if [[ "$has_api" == "true" ]]; then | ||
| 243 | + log_echo " [$idx] opapi UT : bash build.sh -u --opapi -f $PR_FILELIST -j${THREAD_NUM}" | ||
| 244 | + idx=$((idx+1)) | ||
| 245 | + else | ||
| 246 | + log_echo " [--] opapi UT : SKIP (op_api not changed)" | ||
| 247 | + fi | ||
| 248 | + if [[ "$BASE_BRANCH_NAME" == "master" ]]; then | ||
| 249 | + if [[ "$has_graph" == "true" ]]; then | ||
| 250 | + log_echo " [$idx] opgraph UT : bash build.sh -u --opgraph -f $PR_FILELIST -j${THREAD_NUM}" | ||
| 251 | + idx=$((idx+1)) | ||
| 252 | + else | ||
| 253 | + log_echo " [--] opgraph UT : SKIP (op_graph not changed)" | ||
| 254 | + fi | ||
| 255 | + if [[ "$has_kernel" == "true" ]]; then | ||
| 256 | + log_echo " [$idx] opkernel UT : bash scripts/ci/check_kernel_ut.sh $PR_FILELIST --no_cov" | ||
| 257 | + idx=$((idx+1)) | ||
| 258 | + else | ||
| 259 | + log_echo " [--] opkernel UT : SKIP (op_kernel not changed)" | ||
| 260 | + fi | ||
| 261 | + else | ||
| 262 | + log_echo " [--] opgraph/opkernel UT: SKIP (non-master branch)" | ||
| 263 | + fi | ||
| 264 | + if [[ "$has_arch35" == "true" ]]; then | ||
| 265 | + local arch_flag="--no_force" | ||
| 266 | + [[ "$has_kernel" == "false" ]] && arch_flag="-force_jit" | ||
| 267 | + log_echo " [$idx] ascend950 pkg : bash scripts/ci/compile_ascend950_pkg.sh $PR_FILELIST ${arch_flag} -j${THREAD_NUM}" | ||
| 268 | + idx=$((idx+1)) | ||
| 269 | + else | ||
| 270 | + log_echo " [--] ascend950 pkg : SKIP (arch35 not changed)" | ||
| 271 | + fi | ||
| 272 | + log_echo " [--] single-op pkg : SKIP (fast mode)" | ||
| 273 | + log_echo " [--] A2 smoke : SKIP (fast mode)" | ||
| 274 | + if [[ "$has_experimental" == "true" ]]; then | ||
| 275 | + log_echo " [$idx] experimental pkg : bash scripts/ci/check_experimental_pkg.sh $PR_FILELIST" | ||
| 276 | + idx=$((idx+1)) | ||
| 277 | + else | ||
| 278 | + log_echo " [--] experimental pkg : SKIP (experimental not changed)" | ||
| 279 | + fi | ||
| 280 | + fi | ||
| 281 | + log_echo "====================================================================" | ||
| 282 | + log_echo "" | ||
| 283 | +} | ||
| 284 | + | ||
| 285 | +# --------------------------------------------------------------------------- | ||
| 286 | +# 4. 静默执行:构建/UT 输出仅写入日志文件,终端只打印阶段名与 PASS/FAIL | ||
| 287 | +# 用法: run_cmd_silent <stage_name> <log_file> <extra_grep> <cmd...> | ||
| 288 | +# extra_grep 非空时,即使退出码为 0 也会在日志中搜索该关键字,命中即判失败 | ||
| 289 | +# --------------------------------------------------------------------------- | ||
| 290 | +run_cmd_silent() { | ||
| 291 | + local stage_name=$1 log_file=$2 extra_grep=$3 | ||
| 292 | + shift 3 | ||
| 293 | + log_echo "[pre-push] >>> $stage_name (log: $log_file)" | ||
| 294 | + [[ "$log_file" != "pre_push_build.log" ]] && : > "$log_file" | ||
| 295 | + local rc=0 | ||
| 296 | + set +e | ||
| 297 | + "$@" >> "$log_file" 2>&1 | ||
| 298 | + rc=$? | ||
| 299 | + set -e | ||
| 300 | + [[ "$log_file" != "pre_push_build.log" ]] && cat "$log_file" >> pre_push_build.log | ||
| 301 | + if [[ $rc -ne 0 ]]; then | ||
| 302 | + log_echo "[pre-push][FAILED] $stage_name (exit $rc), check log: $log_file" | ||
| 303 | + local failed_lines | ||
| 304 | + failed_lines=$(grep -E '\[ FAILED \]|FAILED TESTS|error happened|Error:|error:' "$log_file" 2>/dev/null | tail -5) | ||
| 305 | + [[ -n "$failed_lines" ]] && log_echo "$failed_lines" | ||
| 306 | + exit $rc | ||
| 307 | + fi | ||
| 308 | + if [[ -n "$extra_grep" ]] && grep -q "$extra_grep" "$log_file" 2>/dev/null; then | ||
| 309 | + log_echo "[pre-push][FAILED] $stage_name: found '$extra_grep' in log: $log_file" | ||
| 310 | + exit 1 | ||
| 311 | + fi | ||
| 312 | + log_echo "[pre-push][PASSED] $stage_name" | ||
| 313 | +} | ||
| 314 | + | ||
| 315 | +# --------------------------------------------------------------------------- | ||
| 316 | +# 5. 阶段间清理 | ||
| 317 | +# --------------------------------------------------------------------------- | ||
| 318 | +clean_build() { | ||
| 319 | + local dir | ||
| 320 | + for dir in build build_out; do | ||
| 321 | + local abs="$WORKSPACE/$dir" | ||
| 322 | + if [[ -z "$WORKSPACE" || "$abs" == "/" || ! "$abs" =~ ^/[^/] ]]; then | ||
| 323 | + log_echo "[pre-push][ERROR] clean_build refused: unsafe path '$abs' (WORKSPACE='$WORKSPACE')." | ||
| 324 | + exit 1 | ||
| 325 | + fi | ||
| 326 | + if [[ -d "$abs" ]]; then | ||
| 327 | + rm -rf "$abs" | ||
| 328 | + fi | ||
| 329 | + done | ||
| 330 | +} | ||
| 331 | + | ||
| 332 | +# --------------------------------------------------------------------------- | ||
| 333 | +# 6a. 完整对齐模式:直接调用 local_build.sh | ||
| 334 | +# --------------------------------------------------------------------------- | ||
| 335 | +run_full_mode() { | ||
| 336 | + log_echo "[pre-push] >>> FULL MODE: delegating to local_build.sh (100% CI-aligned)" | ||
| 337 | + log_echo "[pre-push] Branch: $(git rev-parse --abbrev-ref HEAD) Base: $BASE_BRANCH_NAME" | ||
| 338 | + run_cmd_silent "FULL MODE (local_build.sh)" pre_push_build.log "" \ | ||
| 339 | + bash "$WORKSPACE/scripts/ci/local_build.sh" | ||
| 340 | + log_echo "[pre-push] <<< FULL MODE: ALL PASSED" | ||
| 341 | +} | ||
| 342 | + | ||
| 343 | +# --------------------------------------------------------------------------- | ||
| 344 | +# 6b. 快速增量模式:按模块精简 | ||
| 345 | +# --------------------------------------------------------------------------- | ||
| 346 | +run_fast_mode() { | ||
| 347 | + log_echo "[pre-push] >>> FAST MODE: incremental build (default)" | ||
| 348 | + log_echo "[pre-push] NOTE: Fast mode has known coverage gaps vs CI. Run full mode before merge." | ||
| 349 | + log_echo "" | ||
| 350 | + | ||
| 351 | + local branch | ||
| 352 | + branch=$(git rev-parse --abbrev-ref HEAD) | ||
| 353 | + export WORKSPACE="$WORKSPACE" | ||
| 354 | + export ASCEND_3RD_LIB_PATH="$WORKSPACE/third_party" | ||
| 355 | + export BASE_PATH="$WORKSPACE" | ||
| 356 | + export BUILD_PATH="$WORKSPACE/build" | ||
| 357 | + | ||
| 358 | + clean_build | ||
| 359 | + | ||
| 360 | + if [[ "$need_jit_build" == "true" ]]; then | ||
| 361 | + run_cmd_silent "JIT build" pre_push_build.log "" \ | ||
| 362 | + bash build.sh --pkg --jit -j${THREAD_NUM} --cann_3rd_lib_path=${ASCEND_3RD_LIB_PATH} | ||
| 363 | + clean_build | ||
| 364 | + fi | ||
| 365 | + | ||
| 366 | + if [[ "$has_host" == "true" ]]; then | ||
| 367 | + run_cmd_silent "ophost UT" ut_test.log "" \ | ||
| 368 | + bash build.sh -u --ophost -f "$PR_FILELIST" --cann_3rd_lib_path=${ASCEND_3RD_LIB_PATH} -j${THREAD_NUM} | ||
| 369 | + else | ||
| 370 | + log_echo "[pre-push] op_host not changed, skipping ophost UT (fast mode)." | ||
| 371 | + fi | ||
| 372 | + | ||
| 373 | + if [[ "$has_api" == "true" ]]; then | ||
| 374 | + if [[ "$has_host" == "false" && "$need_jit_build" == "false" ]]; then | ||
| 375 | + run_cmd_silent "JIT build (opapi dep)" pre_push_build.log "" \ | ||
| 376 | + bash build.sh --pkg --jit -j${THREAD_NUM} --cann_3rd_lib_path=${ASCEND_3RD_LIB_PATH} | ||
| 377 | + fi | ||
| 378 | + run_cmd_silent "opapi UT" ut_test.log "" \ | ||
| 379 | + bash build.sh -u --opapi -f "$PR_FILELIST" --cann_3rd_lib_path=${ASCEND_3RD_LIB_PATH} -j${THREAD_NUM} | ||
| 380 | + else | ||
| 381 | + log_echo "[pre-push] op_api not changed, skipping opapi UT (fast mode)." | ||
| 382 | + fi | ||
| 383 | + | ||
| 384 | + if [[ "$branch" == "master" || "$BASE_BRANCH_NAME" == "master" ]]; then | ||
| 385 | + if [[ "$has_graph" == "true" ]]; then | ||
| 386 | + run_cmd_silent "opgraph UT" ut_test.log "" \ | ||
| 387 | + bash build.sh -u --opgraph -f "$PR_FILELIST" --cann_3rd_lib_path=${ASCEND_3RD_LIB_PATH} -j${THREAD_NUM} | ||
| 388 | + fi | ||
| 389 | + if [[ "$has_kernel" == "true" ]]; then | ||
| 390 | + run_cmd_silent "opkernel UT" ut_kernel.log "error happened" \ | ||
| 391 | + bash scripts/ci/check_kernel_ut.sh "$PR_FILELIST" --no_cov | ||
| 392 | + fi | ||
| 393 | + else | ||
| 394 | + log_echo "[pre-push] Non-master branch, skipping opgraph/opkernel UT (aligned with CI)." | ||
| 395 | + fi | ||
| 396 | + clean_build | ||
| 397 | + | ||
| 398 | + if [[ "$has_arch35" == "true" ]]; then | ||
| 399 | + if [[ "$has_kernel" == "false" ]]; then | ||
| 400 | + run_cmd_silent "ascend950 pkg" pre_push_build.log "" \ | ||
| 401 | + bash scripts/ci/compile_ascend950_pkg.sh "$PR_FILELIST" -force_jit -j${THREAD_NUM} | ||
| 402 | + else | ||
| 403 | + run_cmd_silent "ascend950 pkg" pre_push_build.log "" \ | ||
| 404 | + bash scripts/ci/compile_ascend950_pkg.sh "$PR_FILELIST" -j${THREAD_NUM} --no_force | ||
| 405 | + fi | ||
| 406 | + clean_build | ||
| 407 | + fi | ||
| 408 | + | ||
| 409 | + log_echo "[pre-push][SKIP] Single-op pkg / A2 smoke skipped in fast mode." | ||
| 410 | + log_echo "[pre-push][SKIP] Run full mode (PRE_PUSH_FULL=1) to cover remaining CI stages." | ||
| 411 | + | ||
| 412 | + if [[ "$has_experimental" == "true" ]]; then | ||
| 413 | + run_cmd_silent "experimental pkg" pre_push_build.log "" \ | ||
| 414 | + bash scripts/ci/check_experimental_pkg.sh "$PR_FILELIST" | ||
| 415 | + clean_build | ||
| 416 | + log_echo "[pre-push][SKIP] experimental example skipped in fast mode." | ||
| 417 | + fi | ||
| 418 | + | ||
| 419 | + log_echo "[pre-push] <<< FAST MODE: DONE (with coverage gaps, see SKIP above)" | ||
| 420 | +} | ||
| 421 | + | ||
| 422 | +# --------------------------------------------------------------------------- | ||
| 423 | +# 7. 主流程 | ||
| 424 | +# --------------------------------------------------------------------------- | ||
| 425 | +main() { | ||
| 426 | + : > pre_push_build.log | ||
| 427 | + log_echo "====================================================================" | ||
| 428 | + log_echo " Pre-Push Build & UT Gate" | ||
| 429 | + log_echo " Mode: $([[ "${PRE_PUSH_FULL:-0}" == "1" ]] && echo "FULL (CI-aligned)" || echo "FAST (incremental)")" | ||
| 430 | + log_echo " Workspace: $WORKSPACE" | ||
| 431 | + log_echo " Time: $(date '+%Y-%m-%d %H:%M:%S')" | ||
| 432 | + log_echo "====================================================================" | ||
| 433 | + calc_changed_files | ||
| 434 | + identify_changes | ||
| 435 | + print_pipeline | ||
| 436 | + | ||
| 437 | + # 仅文档/配置/cmake/scripts 变更时,所有流程直接跳过 | ||
| 438 | + if [[ "$md_only" == "true" ]]; then | ||
| 439 | + log_echo "[pre-push] Only docs/config/cmake/scripts changed, skipping all build & UT." | ||
| 440 | + log_echo "[pre-push][HINT] If scripts/ci or CMakeLists were modified, CI script changes are NOT verified locally. Review manually." | ||
| 441 | + exit 0 | ||
| 442 | + fi | ||
| 443 | + | ||
| 444 | + # 仅 experimental 变更时,只触发 check_experimental_pkg.sh | ||
| 445 | + if [[ "$has_experimental" == "true" && "$has_host" == "false" && "$has_kernel" == "false" \ | ||
| 446 | + && "$has_api" == "false" && "$has_graph" == "false" ]]; then | ||
| 447 | + log_echo "[pre-push] Only experimental changed, running check_experimental_pkg.sh only." | ||
| 448 | + clean_build | ||
| 449 | + export ASCEND_3RD_LIB_PATH="$WORKSPACE/third_party" | ||
| 450 | + run_cmd_silent "experimental pkg" pre_push_build.log "" \ | ||
| 451 | + bash scripts/ci/check_experimental_pkg.sh "$PR_FILELIST" | ||
| 452 | + exit 0 | ||
| 453 | + fi | ||
| 454 | + | ||
| 455 | + local start_ts end_ts elapsed | ||
| 456 | + start_ts=$(date +%s) | ||
| 457 | + | ||
| 458 | + if [[ "${PRE_PUSH_FULL:-0}" == "1" ]]; then | ||
| 459 | + run_full_mode | ||
| 460 | + else | ||
| 461 | + run_fast_mode | ||
| 462 | + fi | ||
| 463 | + | ||
| 464 | + end_ts=$(date +%s) | ||
| 465 | + elapsed=$((end_ts - start_ts)) | ||
| 466 | + log_echo "" | ||
| 467 | + log_echo "====================================================================" | ||
| 468 | + log_echo " Pre-Push Gate: PASSED (elapsed ${elapsed}s)" | ||
| 469 | + log_echo "====================================================================" | ||
| 470 | + exit 0 | ||
| 471 | +} | ||
| 472 | + | ||
| 473 | +main "$@" | ||


🔴 Critical
变更行
.pre-commit-config.yaml第 92 行:stages: [pre-push]pre-commit 框架中,
pre-pushhook type 对应的 stage 名称为push,而非pre-push。有效的 stage 名称仅有commit、merge-commit、push、manual。配置stages: [pre-push]是一个无效值,框架会忽略此项,导致该 hook 在git push时永远不会被触发。失效模式:开发者执行
git push时,pre-push 构建门禁完全静默跳过,无论是否安装了 hook。这将导致 CI 质量左移完全失效,开发者可能在本地未发现构建/UT 错误直接推送,失去本 PR 的全部价值。建议:将
stages: [pre-push]改为 pre-commit 框架规定的正确 stage 名称push。re-push]