Files
git.stella-ops.org/.gitea/scripts/validate/validate-workflows.sh

225 lines
5.2 KiB
Bash

#!/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}"