已合并
fix pre-commit file change hook #92
chenyx_2012创建于 6月24日
fix pre-commit file change hook #92
已合并
共 1 个文件变更+214-39
| @@ -48,15 +48,49 @@ if [ -z "$_PYTHON" ]; then | |||
| 48 | fi | 48 | fi |
| 49 | 49 | ||
| 50 | # --------------------------------------------------------------------------- | 50 | # --------------------------------------------------------------------------- |
| 51 | -# 1. Ensure oat-py is installed | 51 | +# 1. Ensure oat-py>=1.0.2 is installed (serialized via flock to prevent parallel pip conflicts) |
| 52 | # --------------------------------------------------------------------------- | 52 | # --------------------------------------------------------------------------- |
| 53 | -_OAT_OK=$("$_PYTHON" -c "import importlib.util; print('ok' if importlib.util.find_spec('oat') else 'missing')" 2>/dev/null || echo "missing") | 53 | +_OAT_MIN="1.0.2" |
| 54 | +_check_oat_version() { | ||
| 55 | + "$_PYTHON" -c " | ||
| 56 | +import importlib.util, sys | ||
| 57 | +if not importlib.util.find_spec('oat'): | ||
| 58 | + print('missing'); sys.exit() | ||
| 59 | +try: | ||
| 60 | + from importlib.metadata import version | ||
| 61 | + v = version('oat-py') | ||
| 62 | + parts_have = [int(x) for x in v.split('.')[:3]] | ||
| 63 | + parts_need = [int(x) for x in '${_OAT_MIN}'.split('.')[:3]] | ||
| 64 | + print('ok' if parts_have >= parts_need else 'old') | ||
| 65 | +except Exception: | ||
| 66 | + print('ok') # cannot determine version, assume ok | ||
| 67 | +" 2>/dev/null || echo "missing" | ||
| 68 | +} | ||
| 69 | + | ||
| 70 | +_OAT_OK=$(_check_oat_version) | ||
| 54 | if [ "$_OAT_OK" != "ok" ]; then | 71 | if [ "$_OAT_OK" != "ok" ]; then |
| 55 | - echo "[OAT] oat-py not found. Installing oat-py>=1.0.1 ..." | 72 | + if [ "$_OAT_OK" = "old" ]; then |
| 56 | - "$_PYTHON" -m pip install --quiet "oat-py>=1.0.1" | 73 | + echo "[OAT] oat-py is outdated. Upgrading to oat-py>=${_OAT_MIN} ..." |
| 57 | - _OAT_OK=$("$_PYTHON" -c "import importlib.util; print('ok' if importlib.util.find_spec('oat') else 'missing')" 2>/dev/null || echo "missing") | 74 | + else |
| 75 | + echo "[OAT] oat-py not found. Installing oat-py>=${_OAT_MIN} ..." | ||
| 76 | + fi | ||
| 77 | + _LOCK_FILE="/tmp/oat_pip_install.lock" | ||
| 78 | + # flock ensures only one concurrent invocation runs pip install at a time; | ||
| 79 | + # re-check inside the lock so processes that waited skip redundant installs | ||
| 80 | + if command -v flock >/dev/null 2>&1; then | ||
| 81 | + ( | ||
| 82 | + flock -w 120 9 | ||
| 83 | + _RECHECK=$(_check_oat_version) | ||
| 84 | + if [ "$_RECHECK" != "ok" ]; then | ||
| 85 | + "$_PYTHON" -m pip install --quiet "oat-py>=${_OAT_MIN}" | ||
| 86 | + fi | ||
| 87 | + ) 9>"$_LOCK_FILE" | ||
| 88 | + else | ||
| 89 | + "$_PYTHON" -m pip install --quiet "oat-py>=${_OAT_MIN}" | ||
| 90 | + fi | ||
| 91 | + _OAT_OK=$(_check_oat_version) | ||
| 58 | if [ "$_OAT_OK" != "ok" ]; then | 92 | if [ "$_OAT_OK" != "ok" ]; then |
| 59 | - echo "[OAT] [WARNING] Failed to install oat-py. Please run: pip install oat-py>=1.0.1" | 93 | + echo "[OAT] [WARNING] Failed to install oat-py. Please run: pip install oat-py>=${_OAT_MIN}" |
| 60 | echo "[OAT] Skipping OAT check, continuing commit..." | 94 | echo "[OAT] Skipping OAT check, continuing commit..." |
| 61 | exit 0 | 95 | exit 0 |
| 62 | fi | 96 | fi |
| @@ -68,10 +102,99 @@ fi | |||
| 68 | # --------------------------------------------------------------------------- | 102 | # --------------------------------------------------------------------------- |
| 69 | REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) | 103 | REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) |
| 70 | REPO_NAME=$(basename "$REPO_ROOT") | 104 | REPO_NAME=$(basename "$REPO_ROOT") |
| 71 | -OAT_REPORT_DIR="$REPO_ROOT/oat_reports" | 105 | +OAT_REPORT_DIR="${TMPDIR:-/tmp}/oat_reports_$$" |
| 106 | +OAT_RESULT_DIR="$REPO_ROOT/oat_reports" | ||
| 72 | 107 | ||
| 73 | -echo "[OAT] Running OAT scan (Python Edition) — INCREMENTAL MODE" | 108 | +# --------------------------------------------------------------------------- |
| 109 | +# 2a. PR-range deduplication (pure git, no CI env vars required) | ||
| 110 | +# | ||
| 111 | +# Strategy: | ||
| 112 | +# 1. Find the merge-base between HEAD and the upstream branch (origin/master | ||
| 113 | +# or similar). If found, this is a feature-branch context ??collect ALL | ||
| 114 | +# files changed since the branch diverged (full PR diff). | ||
| 115 | +# 2. Key a done-marker on the HEAD SHA. The first invocation runs the scan; | ||
| 116 | +# every subsequent invocation for the same HEAD exits 0 immediately. | ||
| 117 | +# This eliminates redundant scans when CI calls the hook once per commit. | ||
| 118 | +# 3. If no merge-base is found (e.g. committing directly on master) fall back | ||
| 119 | +# to scanning only the currently staged files, with no done-marker. | ||
| 120 | +# --------------------------------------------------------------------------- | ||
| 121 | +_PR_MERGE_BASE="" | ||
| 122 | +_DONE_MARKER="" | ||
| 123 | +_HEAD_SHA=$(git rev-parse HEAD 2>/dev/null | cut -c1-12 || true) | ||
| 124 | + | ||
| 125 | +if [ -n "$_HEAD_SHA" ]; then | ||
| 126 | + # Try to find merge-base with a known upstream branch | ||
| 127 | + if [ -n "${PRE_COMMIT_FROM_REF:-}" ]; then | ||
| 128 | + # pre-commit --from-ref/--to-ref: use the provided base directly | ||
| 129 | + _PR_MERGE_BASE=$(git merge-base "$PRE_COMMIT_FROM_REF" HEAD 2>/dev/null || true) | ||
| 130 | + fi | ||
| 131 | + if [ -z "$_PR_MERGE_BASE" ]; then | ||
| 132 | + # Search all remotes (origin, upstream, etc.) for common trunk branch names. | ||
| 133 | + # This handles fork setups where origin=fork and upstream=main-repo. | ||
| 134 | + _CANDIDATE_BASE="" | ||
| 135 | + _CANDIDATE_DIST=0 | ||
| 136 | + for _b in $(git for-each-ref --format='%(refname:short)' \ | ||
| 137 | + 'refs/remotes/*/master' 'refs/remotes/*/main' \ | ||
| 138 | + 'refs/remotes/*/develop' 'refs/remotes/*/dev' 2>/dev/null); do | ||
| 139 | + _mb=$(git merge-base HEAD "$_b" 2>/dev/null || true) | ||
| 140 | + [ -z "$_mb" ] && continue | ||
| 141 | + # Skip if merge-base is HEAD itself (branch is ahead of or equal to HEAD) | ||
| 142 | + [ "$_mb" = "$(git rev-parse HEAD 2>/dev/null)" ] && continue | ||
| 143 | + # Pick the candidate whose merge-base is furthest from HEAD | ||
| 144 | + # (most commits since divergence = most likely true PR base) | ||
| 145 | + _dist=$(git rev-list --count "$_mb"..HEAD 2>/dev/null || echo 0) | ||
| 146 | + if [ -z "$_CANDIDATE_BASE" ] || [ "$_dist" -gt "$_CANDIDATE_DIST" ]; then | ||
| 147 | + _CANDIDATE_BASE="$_mb" | ||
| 148 | + _CANDIDATE_DIST="$_dist" | ||
| 149 | + fi | ||
| 150 | + done | ||
| 151 | + _PR_MERGE_BASE="$_CANDIDATE_BASE" | ||
| 152 | + fi | ||
| 153 | + | ||
| 154 | + # Only use PR-range mode when HEAD has diverged from the upstream base | ||
| 155 | + if [ -n "$_PR_MERGE_BASE" ] && [ "$_PR_MERGE_BASE" != "$(git rev-parse HEAD 2>/dev/null)" ]; then | ||
| 156 | + mkdir -p "$OAT_RESULT_DIR" | ||
| 157 | + _DONE_MARKER="$OAT_RESULT_DIR/.done_${_HEAD_SHA}" | ||
| 158 | + if [ -f "$_DONE_MARKER" ]; then | ||
| 159 | + echo "[OAT] [SKIP] Already scanned HEAD=${_HEAD_SHA}. Skipping duplicate invocation." | ||
| 160 | + exit 0 | ||
| 161 | + fi | ||
| 162 | + else | ||
| 163 | + # HEAD == merge-base: on the upstream branch itself, no PR range | ||
| 164 | + _PR_MERGE_BASE="" | ||
| 165 | + fi | ||
| 166 | +fi | ||
| 167 | + | ||
| 168 | +# --------------------------------------------------------------------------- | ||
| 169 | +# 2b. Deduplicate parallel invocations within the same pre-commit run. | ||
| 170 | +# Only the first instance that acquires the lock actually runs the scan; | ||
| 171 | +# all others wait then exit 0. | ||
| 172 | +# --------------------------------------------------------------------------- | ||
| 173 | +if command -v flock >/dev/null 2>&1; then | ||
| 174 | + _OAT_SCAN_LOCK="${TMPDIR:-/tmp}/oat_scan_$(echo "$REPO_ROOT" | tr '/\\: ' '____').lock" | ||
| 175 | + exec 9>"$_OAT_SCAN_LOCK" | ||
| 176 | + if ! flock -n 9; then | ||
| 177 | + echo "[OAT] Another OAT scan instance is running. Waiting..." | ||
| 178 | + flock -w 120 9 | ||
| 179 | + # Re-check done marker: if the scanning instance completed normally, skip. | ||
| 180 | + # If it exited abnormally (no marker), fall through and run the scan ourselves. | ||
| 181 | + if [ -n "$_DONE_MARKER" ] && [ -f "$_DONE_MARKER" ]; then | ||
| 182 | + echo "[OAT] Scan already completed by another instance. Skipping." | ||
| 183 | + exit 0 | ||
| 184 | + fi | ||
| 185 | + echo "[OAT] Previous instance did not complete. Proceeding with scan..." | ||
| 186 | + # Fall through to run the scan below | ||
| 187 | + fi | ||
| 188 | + # This instance now owns the lock and will run the scan. | ||
| 189 | +fi | ||
| 190 | + | ||
| 191 | +echo "[OAT] Running OAT scan (Python Edition) ??INCREMENTAL MODE" | ||
| 74 | echo "[OAT] Project: $REPO_NAME" | 192 | echo "[OAT] Project: $REPO_NAME" |
| 193 | +if [ -n "$_PR_MERGE_BASE" ]; then | ||
| 194 | + echo "[OAT] Mode: PR range ??scanning all files changed since merge-base" | ||
| 195 | +else | ||
| 196 | + echo "[OAT] Mode: staged files ??scanning only currently staged files" | ||
| 197 | +fi | ||
| 75 | 198 | ||
| 76 | # --------------------------------------------------------------------------- | 199 | # --------------------------------------------------------------------------- |
| 77 | # 3. Collect staged files | 200 | # 3. Collect staged files |
| @@ -93,15 +216,19 @@ if [ $# -gt 0 ]; then | |||
| 93 | FILE_LIST="$FILE_LIST,$_abs" | 216 | FILE_LIST="$FILE_LIST,$_abs" |
| 94 | fi | 217 | fi |
| 95 | done | 218 | done |
| 96 | -else | 219 | +elif [ -n "$_PR_MERGE_BASE" ]; then |
| 97 | - _STAGED=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || true) | 220 | + # PR range mode: collect ALL files changed since the branch diverged |
| 221 | + _STAGED=$(git diff --name-only --diff-filter=ACM "$_PR_MERGE_BASE" HEAD \ | ||
| 222 | + 2>/dev/null || true) | ||
| 98 | if [ -z "$_STAGED" ]; then | 223 | if [ -z "$_STAGED" ]; then |
| 99 | - echo "[OAT] No staged files to check. Skipping." | 224 | + echo "[OAT] No files changed in PR range. Skipping." |
| 225 | + [ -n "$_DONE_MARKER" ] && touch "$_DONE_MARKER" 2>/dev/null || true | ||
| 100 | exit 0 | 226 | exit 0 |
| 101 | fi | 227 | fi |
| 102 | FILE_COUNT=$(echo "$_STAGED" | wc -l | tr -d ' ') | 228 | FILE_COUNT=$(echo "$_STAGED" | wc -l | tr -d ' ') |
| 103 | FILE_LIST="" | 229 | FILE_LIST="" |
| 104 | - for _f in $_STAGED; do | 230 | + while IFS= read -r _f; do |
| 231 | + [ -z "$_f" ] && continue | ||
| 105 | case "$_f" in | 232 | case "$_f" in |
| 106 | /*) _abs="$_f" ;; | 233 | /*) _abs="$_f" ;; |
| 107 | *) _abs="$REPO_ROOT/$_f" ;; | 234 | *) _abs="$REPO_ROOT/$_f" ;; |
| @@ -112,7 +239,33 @@ else | |||
| 112 | else | 239 | else |
| 113 | FILE_LIST="$FILE_LIST,$_abs" | 240 | FILE_LIST="$FILE_LIST,$_abs" |
| 114 | fi | 241 | fi |
| 115 | - done | 242 | + done <<EOF |
| 243 | +$_STAGED | ||
| 244 | +EOF | ||
| 245 | +else | ||
| 246 | + # Staged files mode: on upstream branch directly, scan only staged files | ||
| 247 | + _STAGED=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null || true) | ||
| 248 | + if [ -z "$_STAGED" ]; then | ||
| 249 | + echo "[OAT] No staged files to check. Skipping." | ||
| 250 | + exit 0 | ||
| 251 | + fi | ||
| 252 | + FILE_COUNT=$(echo "$_STAGED" | wc -l | tr -d ' ') | ||
| 253 | + FILE_LIST="" | ||
| 254 | + while IFS= read -r _f; do | ||
| 255 | + [ -z "$_f" ] && continue | ||
| 256 | + case "$_f" in | ||
| 257 | + /*) _abs="$_f" ;; | ||
| 258 | + *) _abs="$REPO_ROOT/$_f" ;; | ||
| 259 | + esac | ||
| 260 | + [ -f "$_abs" ] || continue | ||
| 261 | + if [ -z "$FILE_LIST" ]; then | ||
| 262 | + FILE_LIST="$_abs" | ||
| 263 | + else | ||
| 264 | + FILE_LIST="$FILE_LIST,$_abs" | ||
| 265 | + fi | ||
| 266 | + done <<EOF | ||
| 267 | +$_STAGED | ||
| 268 | +EOF | ||
| 116 | fi | 269 | fi |
| 117 | 270 | ||
| 118 | if [ -z "$FILE_LIST" ]; then | 271 | if [ -z "$FILE_LIST" ]; then |
| @@ -123,36 +276,40 @@ fi | |||
| 123 | echo "[OAT] Checking $FILE_COUNT staged file(s)..." | 276 | echo "[OAT] Checking $FILE_COUNT staged file(s)..." |
| 124 | 277 | ||
| 125 | # --------------------------------------------------------------------------- | 278 | # --------------------------------------------------------------------------- |
| 126 | -# 4. Ensure oat_reports/ exists and is in .gitignore | 279 | +# 4. Ensure report directories exist |
| 127 | # --------------------------------------------------------------------------- | 280 | # --------------------------------------------------------------------------- |
| 128 | mkdir -p "$OAT_REPORT_DIR" | 281 | mkdir -p "$OAT_REPORT_DIR" |
| 129 | - | 282 | +mkdir -p "$OAT_RESULT_DIR" |
| 130 | -_GITIGNORE="$REPO_ROOT/.gitignore" | ||
| 131 | -for _entry in "oat_reports" "log"; do | ||
| 132 | - if ! grep -qE "^${_entry}/?$" "$_GITIGNORE" 2>/dev/null; then | ||
| 133 | - printf "\n%s/\n" "$_entry" >> "$_GITIGNORE" 2>/dev/null || true | ||
| 134 | - echo "[OAT] Added ${_entry}/ to .gitignore" | ||
| 135 | - fi | ||
| 136 | -done | ||
| 137 | 283 | ||
| 138 | # --------------------------------------------------------------------------- | 284 | # --------------------------------------------------------------------------- |
| 139 | -# 5. Build oat command — use OAT.xml if present in repo root | 285 | +# 5. Resolve OAT.xml path |
| 140 | # --------------------------------------------------------------------------- | 286 | # --------------------------------------------------------------------------- |
| 141 | -_OAT_CMD="$_PYTHON -m oat -mode s -s $REPO_ROOT -r $OAT_REPORT_DIR -n $REPO_NAME -w 1 -f $FILE_LIST" | ||
| 142 | - | ||
| 143 | _OAT_XML="$REPO_ROOT/OAT.xml" | 287 | _OAT_XML="$REPO_ROOT/OAT.xml" |
| 288 | +if [ ! -f "$_OAT_XML" ] && [ -f "$REPO_ROOT/scripts/OAT.xml" ]; then | ||
| 289 | + _OAT_XML="$REPO_ROOT/scripts/OAT.xml" | ||
| 290 | +fi | ||
| 291 | + | ||
| 292 | +# _OAT_CMD is kept for display purposes only (shown in error messages). | ||
| 293 | +# Actual execution uses direct argument passing below to avoid eval word-splitting | ||
| 294 | +# and command-injection risks when paths or filenames contain special characters. | ||
| 144 | if [ -f "$_OAT_XML" ]; then | 295 | if [ -f "$_OAT_XML" ]; then |
| 145 | - _OAT_CMD="$_OAT_CMD -oatconfig $_OAT_XML" | 296 | + _OAT_CMD="\"$_PYTHON\" -m oat -mode s -s \"$REPO_ROOT\" -r \"$OAT_REPORT_DIR\" -n \"$REPO_NAME\" -w 1 -f \"$FILE_LIST\" -oatconfig \"$_OAT_XML\"" |
| 297 | +else | ||
| 298 | + _OAT_CMD="\"$_PYTHON\" -m oat -mode s -s \"$REPO_ROOT\" -r \"$OAT_REPORT_DIR\" -n \"$REPO_NAME\" -w 1 -f \"$FILE_LIST\"" | ||
| 146 | fi | 299 | fi |
| 147 | 300 | ||
| 148 | # --------------------------------------------------------------------------- | 301 | # --------------------------------------------------------------------------- |
| 149 | -# 6. Run oat scan | 302 | +# 6. Run oat scan (direct argument passing � no eval) |
| 150 | # --------------------------------------------------------------------------- | 303 | # --------------------------------------------------------------------------- |
| 151 | echo "" | 304 | echo "" |
| 152 | echo "[OAT] Running compliance scan..." | 305 | echo "[OAT] Running compliance scan..." |
| 153 | 306 | ||
| 154 | set +e | 307 | set +e |
| 155 | -eval "$_OAT_CMD" >/dev/null 2>&1 | 308 | +if [ -f "$_OAT_XML" ]; then |
| 309 | + "$_PYTHON" -m oat -mode s -s "$REPO_ROOT" -r "$OAT_REPORT_DIR" -n "$REPO_NAME" -w 1 -f "$FILE_LIST" -oatconfig "$_OAT_XML" >/dev/null 2>&1 | ||
| 310 | +else | ||
| 311 | + "$_PYTHON" -m oat -mode s -s "$REPO_ROOT" -r "$OAT_REPORT_DIR" -n "$REPO_NAME" -w 1 -f "$FILE_LIST" >/dev/null 2>&1 | ||
| 312 | +fi | ||
| 156 | _OAT_RC=$? | 313 | _OAT_RC=$? |
| 157 | set -e | 314 | set -e |
| 158 | 315 | ||
| @@ -170,7 +327,7 @@ fi | |||
| 170 | # Only: Invalid File Type + License Header Invalid (no copyright) | 327 | # Only: Invalid File Type + License Header Invalid (no copyright) |
| 171 | # --------------------------------------------------------------------------- | 328 | # --------------------------------------------------------------------------- |
| 172 | REPORT_FILE="$OAT_REPORT_DIR/PlainReport_${REPO_NAME}.txt" | 329 | REPORT_FILE="$OAT_REPORT_DIR/PlainReport_${REPO_NAME}.txt" |
| 173 | -RESULT_FILE="$OAT_REPORT_DIR/result.txt" | 330 | +RESULT_FILE="$OAT_RESULT_DIR/result.txt" |
| 174 | 331 | ||
| 175 | # Section headers used as stop-boundaries when extracting sections | 332 | # Section headers used as stop-boundaries when extracting sections |
| 176 | _ALL_HEADERS="Invalid File Type Total Count:|License Not Compatible Total Count:|License Header Invalid Total Count:|Copyright Header Invalid Total Count:|No License File Total Count:|No Readme.OpenSource Total Count:|No Readme Total Count:|Import Invalid Total Count:|Redundant License File Total Count:|Third Party Software Info Total Count:" | 333 | _ALL_HEADERS="Invalid File Type Total Count:|License Not Compatible Total Count:|License Header Invalid Total Count:|Copyright Header Invalid Total Count:|No License File Total Count:|No Readme.OpenSource Total Count:|No Readme Total Count:|Import Invalid Total Count:|Redundant License File Total Count:|Third Party Software Info Total Count:" |
| @@ -201,17 +358,29 @@ _extract_section() { | |||
| 201 | 358 | ||
| 202 | if [ ! -f "$REPORT_FILE" ]; then | 359 | if [ ! -f "$REPORT_FILE" ]; then |
| 203 | if [ "$_OAT_RC" -eq 0 ]; then | 360 | if [ "$_OAT_RC" -eq 0 ]; then |
| 361 | + # oat exited cleanly with no report: all staged files were filtered out | ||
| 204 | echo "[OAT] [OK] All checks passed ($FILE_COUNT file(s) checked)." | 362 | echo "[OAT] [OK] All checks passed ($FILE_COUNT file(s) checked)." |
| 363 | + [ -n "$_DONE_MARKER" ] && touch "$_DONE_MARKER" 2>/dev/null || true | ||
| 364 | + rm -rf "$OAT_REPORT_DIR" | ||
| 205 | exit 0 | 365 | exit 0 |
| 206 | else | 366 | else |
| 207 | - echo "[OAT] [WARNING] Report not found: $REPORT_FILE" | 367 | + # oat returned exit code 1 but produced no report �?possible disk issue |
| 368 | + # or oat internal error. Do not silently pass; block the commit. | ||
| 369 | + echo "" | ||
| 370 | + echo "[OAT] [ERROR] oat exited with code $_OAT_RC but no report was generated." | ||
| 371 | + echo "[OAT] This may indicate a disk error or an oat internal bug." | ||
| 372 | + echo "[OAT] To investigate, run manually:" | ||
| 373 | + echo " $_OAT_CMD" | ||
| 374 | + echo "[OAT] Blocking commit to prevent silent compliance bypass." | ||
| 375 | + echo "" | ||
| 376 | + rm -rf "$OAT_REPORT_DIR" | ||
| 208 | exit 1 | 377 | exit 1 |
| 209 | fi | 378 | fi |
| 210 | fi | 379 | fi |
| 211 | 380 | ||
| 212 | -# Parse counts | 381 | +# Parse counts ??use || true to prevent set -e from triggering if grep finds no match |
| 213 | -_INVALID_TYPE=$(grep "^Invalid File Type Total Count:" "$REPORT_FILE" | grep -oE '[0-9]+' | head -1) | 382 | +_INVALID_TYPE=$(grep "^Invalid File Type Total Count:" "$REPORT_FILE" | grep -oE '[0-9]+' | head -1 || true) |
| 214 | -_LICENSE_INVALID=$(grep "^License Header Invalid Total Count:" "$REPORT_FILE" | grep -oE '[0-9]+' | head -1) | 383 | +_LICENSE_INVALID=$(grep "^License Header Invalid Total Count:" "$REPORT_FILE" | grep -oE '[0-9]+' | head -1 || true) |
| 215 | _INVALID_TYPE=${_INVALID_TYPE:-0} | 384 | _INVALID_TYPE=${_INVALID_TYPE:-0} |
| 216 | _LICENSE_INVALID=${_LICENSE_INVALID:-0} | 385 | _LICENSE_INVALID=${_LICENSE_INVALID:-0} |
| 217 | 386 | ||
| @@ -240,11 +409,8 @@ _SECTION_LIC=$(_extract_section "$REPORT_FILE" "License Header Invalid Total Cou | |||
| 240 | echo "===================================" | 409 | echo "===================================" |
| 241 | } > "$RESULT_FILE" | 410 | } > "$RESULT_FILE" |
| 242 | 411 | ||
| 243 | -# Clean up full plain report (keep only result.txt) | ||
| 244 | -rm -f "$REPORT_FILE" | ||
| 245 | - | ||
| 246 | # --------------------------------------------------------------------------- | 412 | # --------------------------------------------------------------------------- |
| 247 | -# 8. Block commit if issues found | 413 | +# 8. Block commit if issues found; always clean up temp dir |
| 248 | # --------------------------------------------------------------------------- | 414 | # --------------------------------------------------------------------------- |
| 249 | TOTAL_ISSUES=$(( _INVALID_TYPE + _LICENSE_INVALID )) | 415 | TOTAL_ISSUES=$(( _INVALID_TYPE + _LICENSE_INVALID )) |
| 250 | 416 | ||
| @@ -258,12 +424,15 @@ if [ "$TOTAL_ISSUES" -gt 0 ]; then | |||
| 258 | echo " - Invalid File Type: $_INVALID_TYPE" | 424 | echo " - Invalid File Type: $_INVALID_TYPE" |
| 259 | echo " - License Header Invalid: $_LICENSE_INVALID" | 425 | echo " - License Header Invalid: $_LICENSE_INVALID" |
| 260 | echo "" | 426 | echo "" |
| 261 | - echo "[OAT] Details:" | 427 | + echo "[OAT] Details (also saved to: $RESULT_FILE):" |
| 262 | - echo " cat $RESULT_FILE" | 428 | + echo "---" |
| 429 | + cat "$RESULT_FILE" | ||
| 430 | + echo "---" | ||
| 263 | echo "" | 431 | echo "" |
| 264 | echo "Fix the issues and recommit, or skip with:" | 432 | echo "Fix the issues and recommit, or skip with:" |
| 265 | echo " git commit --no-verify" | 433 | echo " git commit --no-verify" |
| 266 | echo "" | 434 | echo "" |
| 435 | + rm -rf "$OAT_REPORT_DIR" | ||
| 267 | exit 1 | 436 | exit 1 |
| 268 | fi | 437 | fi |
| 269 | 438 | ||
| @@ -271,4 +440,10 @@ echo "" | |||
| 271 | echo "[OAT] [OK] All checks passed ($FILE_COUNT file(s) checked)." | 440 | echo "[OAT] [OK] All checks passed ($FILE_COUNT file(s) checked)." |
| 272 | echo "[OAT] Summary: cat $RESULT_FILE" | 441 | echo "[OAT] Summary: cat $RESULT_FILE" |
| 273 | echo "" | 442 | echo "" |
| 443 | +# Mark scan as done for CI range mode (prevents redundant re-runs on same PR head) | ||
| 444 | +if [ -n "$_DONE_MARKER" ]; then | ||
| 445 | + touch "$_DONE_MARKER" 2>/dev/null || true | ||
| 446 | + echo "[OAT] Done-marker created: $_DONE_MARKER" | ||
| 447 | +fi | ||
| 448 | +rm -rf "$OAT_REPORT_DIR" | ||
| 274 | exit 0 | 449 | exit 0 |