#!/bin/bash # Universal QA hook handler with robust error handling # Location: ~/.config/mosaic/tools/qa/qa-hook-handler.sh # Don't exit on unset variables initially to handle missing params gracefully set -eo pipefail PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) TOOL_NAME="${1:-}" FILE_PATH="${2:-}" # Debug logging echo "[DEBUG] Script called with args: \$1='$1' \$2='$2'" >> "$PROJECT_ROOT/logs/qa-automation.log" 2>/dev/null || true # Validate inputs if [ -z "$FILE_PATH" ] || [ -z "$TOOL_NAME" ]; then echo "[ERROR] Missing required parameters: tool='$TOOL_NAME' file='$FILE_PATH'" >&2 echo "[ERROR] Usage: $0 " >&2 # Log to file if possible echo "[$(date '+%Y-%m-%d %H:%M:%S')] [ERROR] Missing parameters - tool='$TOOL_NAME' file='$FILE_PATH'" >> "$PROJECT_ROOT/logs/qa-automation.log" 2>/dev/null || true exit 1 fi # Now enable strict mode after parameter handling set -u # Skip non-JS/TS files if ! [[ "$FILE_PATH" =~ \.(ts|tsx|js|jsx|mjs|cjs)$ ]]; then echo "[INFO] Skipping non-JS/TS file: $FILE_PATH" exit 0 fi # Generate naming components TIMESTAMP=$(date '+%Y%m%d-%H%M') SANITIZED_NAME=$(echo "$FILE_PATH" | sed 's/\//-/g' | sed 's/^-//' | sed 's/\.\./\./g') ITERATION=1 # Log file for debugging LOG_FILE="$PROJECT_ROOT/logs/qa-automation.log" mkdir -p "$(dirname "$LOG_FILE")" # Function to detect Epic with fallback detect_epic() { local file_path="$1" local epic="" # Try to detect Epic from path patterns case "$file_path" in */apps/frontend/src/components/*adapter*|*/apps/frontend/src/views/*adapter*) epic="E.3001-ADAPTER-CONFIG-SYSTEM" ;; */services/backend/src/adapters/*) epic="E.3001-ADAPTER-CONFIG-SYSTEM" ;; */services/backend/src/*) epic="E.2004-enterprise-data-synchronization-engine" ;; */services/syncagent-debezium/*|*/services/syncagent-n8n/*) epic="E.2004-enterprise-data-synchronization-engine" ;; *) epic="" # General QA ;; esac echo "$epic" } # Detect Epic association EPIC_FOLDER=$(detect_epic "$FILE_PATH") # Function to setup report directory with creation if needed setup_report_dir() { local epic="$1" local project_root="$2" local report_dir="" if [ -n "$epic" ]; then # Check if Epic directory exists local epic_dir="$project_root/docs/task-management/epics/active/$epic" if [ -d "$epic_dir" ]; then # Epic exists, use it report_dir="$epic_dir/reports/qa-automation/pending" echo "[INFO] Using existing Epic: $epic" | tee -a "$LOG_FILE" else # Epic doesn't exist, check if we should create it local epic_parent="$project_root/docs/task-management/epics/active" if [ -d "$epic_parent" ]; then # Parent exists, create Epic structure echo "[WARN] Epic $epic not found, creating structure..." | tee -a "$LOG_FILE" mkdir -p "$epic_dir/reports/qa-automation/pending" mkdir -p "$epic_dir/reports/qa-automation/in-progress" mkdir -p "$epic_dir/reports/qa-automation/done" mkdir -p "$epic_dir/reports/qa-automation/escalated" # Create Epic README cat > "$epic_dir/README.md" << EOF # Epic: $epic **Status**: Active **Created**: $(date '+%Y-%m-%d') **Purpose**: Auto-created by QA automation system ## Description This Epic was automatically created to organize QA remediation reports. ## QA Automation - Reports are stored in \`reports/qa-automation/\` - Pending issues: \`reports/qa-automation/pending/\` - Escalated issues: \`reports/qa-automation/escalated/\` EOF report_dir="$epic_dir/reports/qa-automation/pending" echo "[INFO] Created Epic structure: $epic" | tee -a "$LOG_FILE" else # Epic structure doesn't exist, fall back to general echo "[WARN] Epic structure not found, using general QA" | tee -a "$LOG_FILE" report_dir="$project_root/docs/reports/qa-automation/pending" fi fi else # No Epic association, use general report_dir="$project_root/docs/reports/qa-automation/pending" echo "[INFO] No Epic association, using general QA" | tee -a "$LOG_FILE" fi # Ensure directory exists mkdir -p "$report_dir" echo "$report_dir" } # Setup report directory (capture only the last line which is the path) REPORT_DIR=$(setup_report_dir "$EPIC_FOLDER" "$PROJECT_ROOT" | tail -1) # Check for existing reports from same timestamp check_existing_iteration() { local dir="$1" local name="$2" local timestamp="$3" local max_iter=0 for file in "$dir"/${name}_${timestamp}_*_remediation_needed.md; do if [ -f "$file" ]; then # Extract iteration number local iter=$(echo "$file" | sed 's/.*_\([0-9]\+\)_remediation_needed\.md$/\1/') if [ "$iter" -gt "$max_iter" ]; then max_iter=$iter fi fi done echo $((max_iter + 1)) } ITERATION=$(check_existing_iteration "$REPORT_DIR" "$SANITIZED_NAME" "$TIMESTAMP") # Check if we're at max iterations if [ "$ITERATION" -gt 5 ]; then echo "[ERROR] Max iterations (5) reached for $FILE_PATH" | tee -a "$LOG_FILE" # Move to escalated immediately REPORT_DIR="${REPORT_DIR/pending/escalated}" mkdir -p "$REPORT_DIR" ITERATION=5 # Cap at 5 fi # Create report filename REPORT_FILE="${SANITIZED_NAME}_${TIMESTAMP}_${ITERATION}_remediation_needed.md" REPORT_PATH="$REPORT_DIR/$REPORT_FILE" # Log the action echo "[$(date '+%Y-%m-%d %H:%M:%S')] QA Hook: $TOOL_NAME on $FILE_PATH" | tee -a "$LOG_FILE" echo "[$(date '+%Y-%m-%d %H:%M:%S')] Creating report: $REPORT_PATH" | tee -a "$LOG_FILE" echo "[$(date '+%Y-%m-%d %H:%M:%S')] Epic: ${EPIC_FOLDER:-general}, Iteration: $ITERATION" | tee -a "$LOG_FILE" # Create a task file for the QA agent instead of calling Claude directly cat > "$REPORT_PATH" << EOF # QA Remediation Report **File:** $FILE_PATH **Tool Used:** $TOOL_NAME **Epic:** ${EPIC_FOLDER:-general} **Iteration:** $ITERATION **Generated:** $(date '+%Y-%m-%d %H:%M:%S') ## Status Pending QA validation ## Next Steps This report was created by the QA automation hook. To process this report, run: \`\`\`bash claude -p "Use Task tool to launch universal-qa-agent for report: $REPORT_PATH" \`\`\` EOF echo "[$(date '+%Y-%m-%d %H:%M:%S')] Created report template at: $REPORT_PATH" | tee -a "$LOG_FILE"