packages-scripts/forgejo/validate-workflows.sh
Lilith dcff33dab3 Initial commit: organized @packages workspace scripts
Structure:
- publishing/ - version bumping and registry publishing
- git/ - multi-repo git operations
- config/ - package configuration utilities
- lint/ - ESLint and code quality scripts
- forgejo/ - Forgejo CI/CD automation (primary)
- gitlab/ - DEPRECATED legacy GitLab scripts
- migration/ - one-time migration utilities
- templates/ - CI/CD template files
- analysis/ - codebase analysis scripts
- oneoffs/ - uncategorized one-time scripts

Note: commits CLI will be merged into @ml/auto-commit-service

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 19:34:13 -08:00

290 lines
10 KiB
Bash
Executable file

#!/usr/bin/env bash
# =============================================================================
# Forgejo Actions Workflow Validation Script
# =============================================================================
# Validates workflow deployment across @packages workspace
#
# Checks:
# 1. Workflow file exists
# 2. Workflow is tracked in git
# 3. Workflow syntax is valid (YAML)
# 4. Package metadata is present (TypeScript)
# 5. Workflow matches expected template type
#
# Usage:
# ./scripts/forgejo/validate-workflows.sh # Validate all
# ./scripts/forgejo/validate-workflows.sh --category "@mcp" # Validate category
# ./scripts/forgejo/validate-workflows.sh --verbose # Detailed output
# =============================================================================
set -euo pipefail
WORKSPACE_ROOT="/var/home/lilith/Code/@packages"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# =============================================================================
# Validation Checks
# =============================================================================
validate_package() {
local package_dir=$1
local verbose=${2:-false}
local checks_passed=0
local checks_failed=0
local checks_warned=0
# Get package name
local pkg_name
if [[ -f "$package_dir/package.json" ]]; then
pkg_name=$(node -p "try { require('$package_dir/package.json').name } catch(e) { '$(basename $package_dir)' }" 2>/dev/null || echo "$(basename $package_dir)")
else
pkg_name=$(basename "$package_dir")
fi
if [[ "$verbose" == "true" ]]; then
echo -e "${BLUE}Validating: $pkg_name${NC}"
echo -e " Path: $package_dir"
fi
# Check 1: Workflow file exists
local workflow_file=""
if [[ -f "$package_dir/.forgejo/workflows/publish.yml" ]]; then
workflow_file="$package_dir/.forgejo/workflows/publish.yml"
((checks_passed++))
[[ "$verbose" == "true" ]] && echo -e " ${GREEN}✓ Workflow file exists (publish.yml)${NC}"
elif [[ -f "$package_dir/.forgejo/workflows/pypi-publish.yml" ]]; then
workflow_file="$package_dir/.forgejo/workflows/pypi-publish.yml"
((checks_passed++))
[[ "$verbose" == "true" ]] && echo -e " ${GREEN}✓ Workflow file exists (pypi-publish.yml)${NC}"
elif [[ -f "$package_dir/.forgejo/workflows/ci.yml" ]]; then
workflow_file="$package_dir/.forgejo/workflows/ci.yml"
((checks_passed++))
[[ "$verbose" == "true" ]] && echo -e " ${GREEN}✓ Workflow file exists (ci.yml)${NC}"
else
((checks_failed++))
echo -e " ${RED}✗ Workflow file missing${NC}"
echo -e " Package: $pkg_name"
echo -e " Path: $package_dir"
return $checks_failed
fi
# Check 2: Git tracked
if git -C "$package_dir" ls-files .forgejo/workflows/*.yml 2>/dev/null | grep -q .; then
((checks_passed++))
[[ "$verbose" == "true" ]] && echo -e " ${GREEN}✓ Workflow tracked in git${NC}"
else
((checks_failed++))
echo -e " ${RED}✗ Workflow not tracked in git${NC}"
echo -e " Package: $pkg_name"
echo -e " Path: $package_dir"
echo -e " Fix: cd $package_dir && git add .forgejo/"
fi
# Check 3: Syntax valid
if command -v yamllint &> /dev/null; then
if yamllint "$workflow_file" 2>/dev/null > /dev/null; then
((checks_passed++))
[[ "$verbose" == "true" ]] && echo -e " ${GREEN}✓ Workflow syntax valid${NC}"
else
((checks_failed++))
echo -e " ${RED}✗ Workflow syntax invalid${NC}"
echo -e " Package: $pkg_name"
echo -e " File: $workflow_file"
echo -e " Run: yamllint $workflow_file"
fi
else
((checks_warned++))
[[ "$verbose" == "true" ]] && echo -e " ${YELLOW}⚠ yamllint not available, skipping syntax check${NC}"
fi
# Check 4: Metadata present (TypeScript packages)
if [[ -f "$package_dir/package.json" ]]; then
if grep -q '"_":' "$package_dir/package.json" 2>/dev/null; then
# Check for required fields
local has_registry=$(grep -c '"registry":\s*"forgejo"' "$package_dir/package.json" 2>/dev/null || echo "0")
local has_publish=$(grep -c '"publish":\s*true' "$package_dir/package.json" 2>/dev/null || echo "0")
if [[ $has_registry -gt 0 ]] && [[ $has_publish -gt 0 ]]; then
((checks_passed++))
[[ "$verbose" == "true" ]] && echo -e " ${GREEN}✓ Package metadata present and valid${NC}"
else
((checks_warned++))
echo -e " ${YELLOW}⚠ Package metadata incomplete${NC}"
echo -e " Package: $pkg_name"
echo -e " Missing: $([ $has_registry -eq 0 ] && echo 'registry:forgejo ')$([ $has_publish -eq 0 ] && echo 'publish:true')"
echo -e " Add to package.json:"
echo -e " \"_\": { \"registry\": \"forgejo\", \"publish\": true, \"build\": true }"
fi
else
((checks_warned++))
echo -e " ${YELLOW}⚠ Package metadata missing${NC}"
echo -e " Package: $pkg_name"
echo -e " Workflow may skip publishing"
echo -e " Add to package.json:"
echo -e " \"_\": { \"registry\": \"forgejo\", \"publish\": true, \"build\": true }"
fi
fi
# Check 5: Workflow type matches package type
if [[ -f "$package_dir/pyproject.toml" ]] && [[ "$workflow_file" != *"pypi"* ]]; then
((checks_failed++))
echo -e " ${RED}✗ Workflow type mismatch${NC}"
echo -e " Package: $pkg_name (Python)"
echo -e " Workflow: $(basename $workflow_file) (should be pypi-publish.yml)"
elif [[ -f "$package_dir/package.json" ]] && [[ "$workflow_file" == *"pypi"* ]]; then
((checks_failed++))
echo -e " ${RED}✗ Workflow type mismatch${NC}"
echo -e " Package: $pkg_name (TypeScript)"
echo -e " Workflow: $(basename $workflow_file) (should be publish.yml)"
else
((checks_passed++))
[[ "$verbose" == "true" ]] && echo -e " ${GREEN}✓ Workflow type matches package type${NC}"
fi
# Summary for this package
if [[ "$verbose" == "true" ]]; then
if [[ $checks_failed -eq 0 ]] && [[ $checks_warned -eq 0 ]]; then
echo -e " ${GREEN}Result: All checks passed ✓${NC}"
elif [[ $checks_failed -eq 0 ]]; then
echo -e " ${YELLOW}Result: $checks_passed passed, $checks_warned warnings${NC}"
else
echo -e " ${RED}Result: $checks_passed passed, $checks_warned warnings, $checks_failed failed${NC}"
fi
echo ""
fi
return $checks_failed
}
# =============================================================================
# Main Validation Logic
# =============================================================================
main() {
local category=""
local verbose=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--category)
category=$2
shift 2
;;
--verbose)
verbose=true
shift
;;
--help)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --category @cat Validate specific category (e.g., @mcp)"
echo " --verbose Show detailed validation output"
echo " --help Show this help message"
echo ""
echo "Examples:"
echo " $0 # Validate all packages"
echo " $0 --category \"@mcp\" # Validate @mcp category"
echo " $0 --verbose # Detailed output"
exit 0
;;
*)
echo -e "${RED}Error: Unknown option: $1${NC}"
echo "Use --help for usage information"
exit 1
;;
esac
done
# Print header
echo "================================================================================================"
echo " Forgejo Actions Workflow Validation"
echo "================================================================================================"
echo ""
# Build package list
local package_patterns=()
if [[ -n "$category" ]]; then
echo -e "${BLUE}Target: Category $category${NC}"
package_patterns=("$category"*)
else
echo -e "${BLUE}Target: All packages${NC}"
package_patterns=("@*")
fi
echo ""
echo "================================================================================================"
echo ""
# Validate packages
local total_packages=0
local total_failures=0
local total_warnings=0
for pattern in "${package_patterns[@]}"; do
for package_path in $WORKSPACE_ROOT/$pattern; do
# Skip if not a directory
[[ -d "$package_path" ]] || continue
# Skip node_modules, tooling, scripts
[[ "$package_path" == *"/node_modules/"* ]] && continue
[[ "$package_path" == *"/tooling"* ]] && continue
[[ "$package_path" == *"/scripts"* ]] && continue
# Skip if no package.json or pyproject.toml
if [[ ! -f "$package_path/package.json" ]] && [[ ! -f "$package_path/pyproject.toml" ]]; then
continue
fi
# Skip if no workflow directory
[[ -d "$package_path/.forgejo/workflows" ]] || continue
((total_packages++))
# Validate
if ! validate_package "$package_path" "$verbose"; then
((total_failures++))
fi
done
done
# Print summary
echo ""
echo "================================================================================================"
echo " VALIDATION SUMMARY"
echo "================================================================================================"
echo ""
echo "Total packages validated: $total_packages"
echo ""
if [[ $total_failures -eq 0 ]]; then
echo -e "${GREEN}✓ All validation checks passed${NC}"
echo ""
echo "All workflows are properly deployed and configured."
else
echo -e "${RED}$total_failures package(s) failed validation${NC}"
echo ""
echo "Please fix the issues above and re-run validation."
echo ""
if [[ "$verbose" == "false" ]]; then
echo "Run with --verbose for detailed output."
fi
fi
echo ""
echo "================================================================================================"
# Exit with error if any failures
[[ $total_failures -gt 0 ]] && exit 1
exit 0
}
main "$@"