Files
bootstrap/rails/qa/qa-hook-handler.sh

197 lines
6.6 KiB
Bash
Executable File

#!/bin/bash
# Universal QA hook handler with robust error handling
# Location: ~/.mosaic/rails/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 <tool> <file_path>" >&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"