#!/usr/bin/env bash # ============================================================================ # Issue Prioritization Script # ============================================================================ # Purpose: Categorize and prioritize validation issues into P0/P1/P2 tiers # Version: 1.0.0 # Usage: ./issue-prioritizer.sh [criteria] # Returns: 0=success, 1=error # Dependencies: jq, bash 4.0+ # ============================================================================ set -euo pipefail # Configuration readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" readonly RED='\033[0;31m' readonly YELLOW='\033[1;33m' readonly BLUE='\033[0;34m' readonly NC='\033[0m' # No Color # Priority definitions declare -A PRIORITY_NAMES=( [0]="Critical - Must Fix" [1]="Important - Should Fix" [2]="Recommended - Nice to Have" ) declare -A PRIORITY_ICONS=( [0]="❌" [1]="⚠️ " [2]="💡" ) # Effort labels declare -A EFFORT_LABELS=( [low]="Low" [medium]="Medium" [high]="High" ) # Effort time estimates declare -A EFFORT_TIMES=( [low]="5-15 minutes" [medium]="30-60 minutes" [high]="2+ hours" ) # ============================================================================ # Functions # ============================================================================ usage() { cat < [criteria] Arguments: issues-json-file Path to JSON file with validation issues criteria Prioritization criteria: severity|impact|effort (default: severity) Examples: $0 validation-results.json $0 results.json impact $0 results.json severity JSON Structure: { "errors": [{"type": "...", "severity": "critical", ...}], "warnings": [{"type": "...", "severity": "important", ...}], "recommendations": [{"type": "...", "severity": "recommended", ...}] } EOF exit 1 } check_dependencies() { local missing_deps=() if ! command -v jq &> /dev/null; then missing_deps+=("jq") fi if [ ${#missing_deps[@]} -gt 0 ]; then echo "Error: Missing dependencies: ${missing_deps[*]}" >&2 echo "Install with: sudo apt-get install ${missing_deps[*]}" >&2 return 1 fi return 0 } determine_priority() { local severity="$1" local type="$2" # P0 (Critical) - Blocking issues if [[ "$severity" == "critical" ]] || \ [[ "$type" =~ ^(missing_required|invalid_json|security_vulnerability|format_violation)$ ]]; then echo "0" return fi # P1 (Important) - Should fix if [[ "$severity" == "important" ]] || \ [[ "$type" =~ ^(missing_recommended|documentation_gap|convention_violation|performance)$ ]]; then echo "1" return fi # P2 (Recommended) - Nice to have echo "2" } get_effort_estimate() { local type="$1" # High effort if [[ "$type" =~ ^(security_vulnerability|performance|architecture)$ ]]; then echo "high" return fi # Medium effort if [[ "$type" =~ ^(documentation_gap|convention_violation|missing_recommended)$ ]]; then echo "medium" return fi # Low effort (default) echo "low" } format_issue() { local priority="$1" local message="$2" local impact="${3:-Unknown impact}" local effort="${4:-low}" local fix="${5:-No fix suggestion available}" local icon="${PRIORITY_ICONS[$priority]}" local effort_label="${EFFORT_LABELS[$effort]}" local effort_time="${EFFORT_TIMES[$effort]}" cat <&2 return 1 fi # Validate JSON syntax if ! jq empty "$json_file" 2>/dev/null; then echo "Error: Invalid JSON in $json_file" >&2 return 1 fi # Count total issues local total_errors=$(jq '.errors // [] | length' "$json_file") local total_warnings=$(jq '.warnings // [] | length' "$json_file") local total_recommendations=$(jq '.recommendations // [] | length' "$json_file") local total_issues=$((total_errors + total_warnings + total_recommendations)) if [[ $total_issues -eq 0 ]]; then echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "ISSUE PRIORITIZATION" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "No issues found! Quality score is perfect." return 0 fi # Initialize priority counters declare -A priority_counts=([0]=0 [1]=0 [2]=0) declare -A priority_issues=([0]="" [1]="" [2]="") # Process errors while IFS= read -r issue; do local type=$(echo "$issue" | jq -r '.type // "unknown"') local severity=$(echo "$issue" | jq -r '.severity // "critical"') local message=$(echo "$issue" | jq -r '.message // "Unknown error"') local impact=$(echo "$issue" | jq -r '.impact // "Unknown impact"') local fix=$(echo "$issue" | jq -r '.fix // "No fix available"') local score_impact=$(echo "$issue" | jq -r '.score_impact // 0') local priority=$(determine_priority "$severity" "$type") local effort=$(get_effort_estimate "$type") priority_counts[$priority]=$((priority_counts[$priority] + 1)) local formatted_issue=$(format_issue "$priority" "$message" "$impact" "$effort" "$fix") priority_issues[$priority]+="$formatted_issue" done < <(jq -c '.errors // [] | .[]' "$json_file") # Process warnings while IFS= read -r issue; do local type=$(echo "$issue" | jq -r '.type // "unknown"') local severity=$(echo "$issue" | jq -r '.severity // "important"') local message=$(echo "$issue" | jq -r '.message // "Unknown warning"') local impact=$(echo "$issue" | jq -r '.impact // "Unknown impact"') local fix=$(echo "$issue" | jq -r '.fix // "No fix available"') local priority=$(determine_priority "$severity" "$type") local effort=$(get_effort_estimate "$type") priority_counts[$priority]=$((priority_counts[$priority] + 1)) local formatted_issue=$(format_issue "$priority" "$message" "$impact" "$effort" "$fix") priority_issues[$priority]+="$formatted_issue" done < <(jq -c '.warnings // [] | .[]' "$json_file") # Process recommendations while IFS= read -r issue; do local type=$(echo "$issue" | jq -r '.type // "unknown"') local severity=$(echo "$issue" | jq -r '.severity // "recommended"') local message=$(echo "$issue" | jq -r '.message // "Recommendation"') local impact=$(echo "$issue" | jq -r '.impact // "Minor quality improvement"') local fix=$(echo "$issue" | jq -r '.fix // "No fix available"') local priority=$(determine_priority "$severity" "$type") local effort=$(get_effort_estimate "$type") priority_counts[$priority]=$((priority_counts[$priority] + 1)) local formatted_issue=$(format_issue "$priority" "$message" "$impact" "$effort" "$fix") priority_issues[$priority]+="$formatted_issue" done < <(jq -c '.recommendations // [] | .[]' "$json_file") # Display results echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "ISSUE PRIORITIZATION" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" echo "Total Issues: $total_issues" echo "" # Display each priority tier for priority in 0 1 2; do local count=${priority_counts[$priority]} local name="${PRIORITY_NAMES[$priority]}" if [[ $count -gt 0 ]]; then echo "Priority $priority ($name): $count" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo -e "${priority_issues[$priority]}" fi done # Summary echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "Summary:" echo "- Fix P0 issues first (blocking publication)" echo "- Address P1 issues for quality improvement" echo "- Consider P2 improvements for excellence" if [[ ${priority_counts[0]} -gt 0 ]]; then echo "" echo "⚠️ WARNING: ${priority_counts[0]} blocking issue(s) must be fixed before publication" fi return 0 } # ============================================================================ # Main # ============================================================================ main() { # Check arguments if [[ $# -lt 1 ]]; then usage fi local json_file="$1" local criteria="${2:-severity}" # Check dependencies if ! check_dependencies; then return 1 fi # Validate criteria if [[ ! "$criteria" =~ ^(severity|impact|effort)$ ]]; then echo "Error: Invalid criteria '$criteria'. Use: severity|impact|effort" >&2 return 1 fi # Process issues process_issues "$json_file" "$criteria" return 0 } main "$@"