#!/bin/bash # validate-workflows.sh - Validate Gitea Actions workflows # Sprint: SPRINT_20251226_001_CICD # # Usage: # ./validate-workflows.sh # Validate all workflows # ./validate-workflows.sh --strict # Fail on any warning # ./validate-workflows.sh --verbose # Show detailed output set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" WORKFLOWS_DIR="$REPO_ROOT/.gitea/workflows" SCRIPTS_DIR="$REPO_ROOT/.gitea/scripts" # Configuration STRICT_MODE=false VERBOSE=false # Counters PASSED=0 FAILED=0 WARNINGS=0 # Colors (if terminal supports it) if [[ -t 1 ]]; then RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' # No Color else RED='' GREEN='' YELLOW='' NC='' fi # Parse arguments while [[ $# -gt 0 ]]; do case $1 in --strict) STRICT_MODE=true shift ;; --verbose) VERBOSE=true shift ;; --help) echo "Usage: $0 [OPTIONS]" echo "" echo "Options:" echo " --strict Fail on any warning" echo " --verbose Show detailed output" echo " --help Show this help message" exit 0 ;; *) echo "Unknown option: $1" exit 1 ;; esac done echo "=== Gitea Workflow Validation ===" echo "Workflows: $WORKFLOWS_DIR" echo "Scripts: $SCRIPTS_DIR" echo "" # Check if workflows directory exists if [[ ! -d "$WORKFLOWS_DIR" ]]; then echo -e "${RED}ERROR: Workflows directory not found${NC}" exit 1 fi # Function to validate YAML syntax validate_yaml_syntax() { local file=$1 local name=$(basename "$file") # Try python yaml parser first if command -v python3 &>/dev/null; then if python3 -c "import yaml; yaml.safe_load(open('$file'))" 2>/dev/null; then return 0 else return 1 fi # Fallback to ruby if available elif command -v ruby &>/dev/null; then if ruby -ryaml -e "YAML.load_file('$file')" 2>/dev/null; then return 0 else return 1 fi else # Can't validate YAML, warn and skip return 2 fi } # Function to extract script references from a workflow extract_script_refs() { local file=$1 # Look for patterns like: .gitea/scripts/*, scripts/*, ./devops/scripts/* grep -oE '(\.gitea/scripts|scripts|devops/scripts)/[a-zA-Z0-9_/-]+\.(sh|py|js|mjs)' "$file" 2>/dev/null | sort -u || true } # Function to check if a script exists check_script_exists() { local script_path=$1 local full_path="$REPO_ROOT/$script_path" if [[ -f "$full_path" ]]; then return 0 else return 1 fi } # Validate each workflow file echo "=== Validating Workflow Syntax ===" for workflow in "$WORKFLOWS_DIR"/*.yml "$WORKFLOWS_DIR"/*.yaml; do [[ -e "$workflow" ]] || continue name=$(basename "$workflow") if [[ "$VERBOSE" == "true" ]]; then echo "Checking: $name" fi result=$(validate_yaml_syntax "$workflow") exit_code=$? if [[ $exit_code -eq 0 ]]; then echo -e " ${GREEN}[PASS]${NC} $name - YAML syntax valid" ((PASSED++)) elif [[ $exit_code -eq 2 ]]; then echo -e " ${YELLOW}[SKIP]${NC} $name - No YAML parser available" ((WARNINGS++)) else echo -e " ${RED}[FAIL]${NC} $name - YAML syntax error" ((FAILED++)) fi done echo "" echo "=== Validating Script References ===" # Check all script references MISSING_SCRIPTS=() for workflow in "$WORKFLOWS_DIR"/*.yml "$WORKFLOWS_DIR"/*.yaml; do [[ -e "$workflow" ]] || continue name=$(basename "$workflow") refs=$(extract_script_refs "$workflow") if [[ -z "$refs" ]]; then if [[ "$VERBOSE" == "true" ]]; then echo " $name: No script references found" fi continue fi while IFS= read -r script_ref; do [[ -z "$script_ref" ]] && continue if check_script_exists "$script_ref"; then if [[ "$VERBOSE" == "true" ]]; then echo -e " ${GREEN}[OK]${NC} $name -> $script_ref" fi else echo -e " ${RED}[MISSING]${NC} $name -> $script_ref" MISSING_SCRIPTS+=("$name: $script_ref") ((WARNINGS++)) fi done <<< "$refs" done # Check that .gitea/scripts directories exist echo "" echo "=== Validating Script Directory Structure ===" EXPECTED_DIRS=(build test validate sign release metrics evidence util) for dir in "${EXPECTED_DIRS[@]}"; do dir_path="$SCRIPTS_DIR/$dir" if [[ -d "$dir_path" ]]; then script_count=$(find "$dir_path" -maxdepth 1 -name "*.sh" -o -name "*.py" 2>/dev/null | wc -l) echo -e " ${GREEN}[OK]${NC} $dir/ ($script_count scripts)" else echo -e " ${YELLOW}[WARN]${NC} $dir/ - Directory not found" ((WARNINGS++)) fi done # Summary echo "" echo "=== Validation Summary ===" echo -e " Passed: ${GREEN}$PASSED${NC}" echo -e " Failed: ${RED}$FAILED${NC}" echo -e " Warnings: ${YELLOW}$WARNINGS${NC}" if [[ ${#MISSING_SCRIPTS[@]} -gt 0 ]]; then echo "" echo "Missing script references:" for ref in "${MISSING_SCRIPTS[@]}"; do echo " - $ref" done fi # Exit code if [[ $FAILED -gt 0 ]]; then echo "" echo -e "${RED}FAILED: $FAILED validation(s) failed${NC}" exit 1 fi if [[ "$STRICT_MODE" == "true" && $WARNINGS -gt 0 ]]; then echo "" echo -e "${YELLOW}STRICT MODE: $WARNINGS warning(s) treated as errors${NC}" exit 1 fi echo "" echo -e "${GREEN}All validations passed!${NC}"