diff --git a/ci-runner.sh b/ci-runner.sh index 6a10925..98af173 100755 --- a/ci-runner.sh +++ b/ci-runner.sh @@ -140,6 +140,50 @@ if [ "$ERROR_COUNT" != "0" ] && [ "$ERROR_COUNT" != "" ]; then echo "TEST COLLECTION ERRORS" fi +# ─── Auto-Escalation ─── +# If a tag-targeted run fails, escalate to full light suite. +# If light fails too, escalate to heavy. Captures results at each level. +ESCALATION_LOG="" +if [ "$OVERALL" = "fail" ] && [[ "$RUN_MODE" == tag:* ]]; then + ESCALATION_LOG="Escalated from ${RUN_MODE} (${PASS_COUNT} passed, ${FAIL_COUNT} failed)" + echo "" + echo "--- ESCALATING: ${RUN_MODE} failed → running full light suite ---" + LIGHT_OUTPUT=$($PYTHON -m pytest "$WORKTREE/backend/tests/" --tb=line -q $TIMEOUT_FLAG 2>&1) + LIGHT_PASS=$(echo "$LIGHT_OUTPUT" | grep -oP '\d+ passed' | grep -oP '\d+' || echo 0) + LIGHT_FAIL=$(echo "$LIGHT_OUTPUT" | grep -oP '\d+ failed' | grep -oP '\d+' || echo 0) + LIGHT_SKIP=$(echo "$LIGHT_OUTPUT" | grep -oP '\d+ skipped' | grep -oP '\d+' || echo 0) + LIGHT_DESELECTED=$(echo "$LIGHT_OUTPUT" | grep -oP '\d+ deselected' | grep -oP '\d+' || echo 0) + echo "Light suite: $LIGHT_PASS passed, $LIGHT_FAIL failed, $LIGHT_SKIP skipped" + + if [ "$LIGHT_FAIL" = "0" ] || [ -z "$LIGHT_FAIL" ]; then + ESCALATION_LOG="$ESCALATION_LOG → light PASSED ($LIGHT_PASS passed)" + RUN_MODE="tag:${TAG}→light" + PASS_COUNT="$LIGHT_PASS"; FAIL_COUNT="0"; SKIP_COUNT="$LIGHT_SKIP" + DESELECTED_COUNT="$LIGHT_DESELECTED"; OVERALL="pass" + else + ESCALATION_LOG="$ESCALATION_LOG → light FAILED ($LIGHT_PASS passed, $LIGHT_FAIL failed)" + echo "" + echo "--- ESCALATING: light failed → running heavy suite ---" + export RUN_HEAVY_TESTS=1 + HEAVY_OUTPUT=$($PYTHON -m pytest "$WORKTREE/backend/tests/" --tb=line -q $TIMEOUT_FLAG 2>&1) + HEAVY_PASS=$(echo "$HEAVY_OUTPUT" | grep -oP '\d+ passed' | grep -oP '\d+' || echo 0) + HEAVY_FAIL=$(echo "$HEAVY_OUTPUT" | grep -oP '\d+ failed' | grep -oP '\d+' || echo 0) + echo "Heavy suite: $HEAVY_PASS passed, $HEAVY_FAIL failed" + + if [ "$HEAVY_FAIL" = "0" ] || [ -z "$HEAVY_FAIL" ]; then + ESCALATION_LOG="$ESCALATION_LOG → heavy PASSED ($HEAVY_PASS passed)" + RUN_MODE="tag:${TAG}→light→heavy" + PASS_COUNT="$HEAVY_PASS"; FAIL_COUNT="0"; OVERALL="pass" + else + ESCALATION_LOG="$ESCALATION_LOG → heavy FAILED ($HEAVY_PASS passed, $HEAVY_FAIL failed)" + RUN_MODE="tag:${TAG}→light→heavy" + PASS_COUNT="$HEAVY_PASS"; FAIL_COUNT="$HEAVY_FAIL" + TEST_OUTPUT="$HEAVY_OUTPUT" + fi + fi + echo "Escalation: $ESCALATION_LOG" +fi + # ─── Test Count Baseline Check ─── # Baseline check only applies to full suite runs (light), not tag-targeted runs BASELINE=$(python3 -c "import json; print(json.load(open('$CONFIG')).get('test_count_baseline', 0))") @@ -186,6 +230,12 @@ else SUITE_INFO="Mode: ${RUN_MODE} | ${DESELECTED_COUNT} not in scope" fi +# Append escalation info if escalation occurred +if [ -n "$ESCALATION_LOG" ]; then + SUITE_INFO="${SUITE_INFO} +Escalation: ${ESCALATION_LOG}" +fi + echo "" echo "=========================" echo "Result: $OVERALL"