Jesús Pérex 095fd89ff7
Some checks failed
CI/CD Pipeline / Test Suite (push) Has been cancelled
CI/CD Pipeline / Security Audit (push) Has been cancelled
CI/CD Pipeline / Build Docker Image (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / Performance Benchmarks (push) Has been cancelled
CI/CD Pipeline / Cleanup (push) Has been cancelled
chore: add scripts
2025-07-07 23:53:50 +01:00

745 lines
22 KiB
Bash
Executable File

#!/bin/bash
# CI/CD Management Script
# Comprehensive continuous integration and deployment tools
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# Script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
# Change to project root
cd "$PROJECT_ROOT"
# Logging functions
log() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_header() {
echo -e "${BLUE}${BOLD}=== $1 ===${NC}"
}
print_subheader() {
echo -e "${CYAN}--- $1 ---${NC}"
}
# Default values
OUTPUT_DIR="ci_reports"
ENVIRONMENT="dev"
BRANCH="main"
REGISTRY="docker.io"
IMAGE_NAME="rustelo"
TAG="latest"
DOCKERFILE="Dockerfile"
QUIET=false
VERBOSE=false
DRY_RUN=false
print_usage() {
echo -e "${BOLD}CI/CD Management Tool${NC}"
echo
echo "Usage: $0 <command> [options]"
echo
echo -e "${BOLD}Commands:${NC}"
echo
echo -e "${CYAN}build${NC} Build and packaging"
echo " project Build the project"
echo " docker Build Docker image"
echo " release Build release artifacts"
echo " assets Build static assets"
echo " docs Build documentation"
echo " package Package for distribution"
echo " multi-arch Build multi-architecture images"
echo " cache Build with caching"
echo
echo -e "${CYAN}test${NC} Testing pipeline"
echo " unit Run unit tests"
echo " integration Run integration tests"
echo " e2e Run end-to-end tests"
echo " security Run security tests"
echo " performance Run performance tests"
echo " coverage Generate test coverage"
echo " report Generate test report"
echo " all Run all tests"
echo
echo -e "${CYAN}quality${NC} Code quality checks"
echo " lint Run linting"
echo " format Check code formatting"
echo " clippy Run Clippy checks"
echo " audit Run security audit"
echo " dependencies Check dependencies"
echo " licenses Check license compatibility"
echo " metrics Code quality metrics"
echo " report Generate quality report"
echo
echo -e "${CYAN}deploy${NC} Deployment operations"
echo " staging Deploy to staging"
echo " production Deploy to production"
echo " rollback Rollback deployment"
echo " status Check deployment status"
echo " logs View deployment logs"
echo " health Check deployment health"
echo " scale Scale deployment"
echo " migrate Run database migrations"
echo
echo -e "${CYAN}pipeline${NC} Pipeline management"
echo " run Run full CI/CD pipeline"
echo " validate Validate pipeline config"
echo " status Check pipeline status"
echo " artifacts Manage build artifacts"
echo " cache Manage build cache"
echo " cleanup Clean up old builds"
echo " notify Send notifications"
echo
echo -e "${CYAN}env${NC} Environment management"
echo " setup Setup CI/CD environment"
echo " config Configure environment"
echo " secrets Manage secrets"
echo " variables Manage environment variables"
echo " clean Clean environment"
echo
echo -e "${CYAN}tools${NC} CI/CD tools"
echo " install Install CI/CD tools"
echo " update Update CI/CD tools"
echo " doctor Check tool health"
echo " benchmark Benchmark CI/CD performance"
echo
echo -e "${BOLD}Options:${NC}"
echo " -e, --env ENV Environment (dev/staging/prod) [default: $ENVIRONMENT]"
echo " -b, --branch BRANCH Git branch [default: $BRANCH]"
echo " -r, --registry URL Docker registry [default: $REGISTRY]"
echo " -i, --image NAME Docker image name [default: $IMAGE_NAME]"
echo " -t, --tag TAG Docker image tag [default: $TAG]"
echo " -f, --dockerfile FILE Dockerfile path [default: $DOCKERFILE]"
echo " -o, --output DIR Output directory [default: $OUTPUT_DIR]"
echo " --dry-run Show what would be done"
echo " --quiet Suppress verbose output"
echo " --verbose Enable verbose output"
echo " --help Show this help message"
echo
echo -e "${BOLD}Examples:${NC}"
echo " $0 build project # Build the project"
echo " $0 test all # Run all tests"
echo " $0 deploy staging # Deploy to staging"
echo " $0 pipeline run # Run full pipeline"
echo " $0 build docker -t v1.0.0 # Build Docker image with tag"
echo " $0 deploy production --dry-run # Dry run production deployment"
}
# Check if required tools are available
check_tools() {
local missing_tools=()
# Check for basic tools
if ! command -v git >/dev/null 2>&1; then
missing_tools+=("git")
fi
if ! command -v cargo >/dev/null 2>&1; then
missing_tools+=("cargo")
fi
if ! command -v docker >/dev/null 2>&1; then
missing_tools+=("docker")
fi
if [ ${#missing_tools[@]} -gt 0 ]; then
log_error "Missing required tools: ${missing_tools[*]}"
echo "Please install the missing tools before running CI/CD operations."
exit 1
fi
}
# Setup output directory
setup_output_dir() {
if [ ! -d "$OUTPUT_DIR" ]; then
mkdir -p "$OUTPUT_DIR"
log "Created output directory: $OUTPUT_DIR"
fi
}
# Get current timestamp
get_timestamp() {
date +%Y%m%d_%H%M%S
}
# Get git information
get_git_info() {
local git_commit=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
local git_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
local git_tag=$(git describe --tags --exact-match 2>/dev/null || echo "")
echo "commit:$git_commit,branch:$git_branch,tag:$git_tag"
}
# Build project
build_project() {
print_header "Building Project"
local timestamp=$(get_timestamp)
local build_log="$OUTPUT_DIR/build_$timestamp.log"
log "Building Rust project..."
if $DRY_RUN; then
log "DRY RUN: Would build project with cargo leptos build --release"
return 0
fi
# Clean previous build
cargo clean
# Build with timing
local start_time=$(date +%s)
if $VERBOSE; then
cargo leptos build --release 2>&1 | tee "$build_log"
else
cargo leptos build --release > "$build_log" 2>&1
fi
local end_time=$(date +%s)
local duration=$((end_time - start_time))
if [ $? -eq 0 ]; then
log_success "Project built successfully in ${duration}s"
log "Build log saved to: $build_log"
else
log_error "Build failed. Check log: $build_log"
return 1
fi
}
# Build Docker image
build_docker() {
print_header "Building Docker Image"
local timestamp=$(get_timestamp)
local build_log="$OUTPUT_DIR/docker_build_$timestamp.log"
local full_image_name="$REGISTRY/$IMAGE_NAME:$TAG"
log "Building Docker image: $full_image_name"
log "Using Dockerfile: $DOCKERFILE"
if $DRY_RUN; then
log "DRY RUN: Would build Docker image with:"
log " docker build -f $DOCKERFILE -t $full_image_name ."
return 0
fi
# Get build context info
local git_info=$(get_git_info)
local build_date=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Build Docker image with labels
local start_time=$(date +%s)
docker build \
-f "$DOCKERFILE" \
-t "$full_image_name" \
--label "org.opencontainers.image.created=$build_date" \
--label "org.opencontainers.image.revision=$(echo $git_info | cut -d',' -f1 | cut -d':' -f2)" \
--label "org.opencontainers.image.version=$TAG" \
--label "org.opencontainers.image.source=https://github.com/your-org/rustelo" \
. 2>&1 | tee "$build_log"
local end_time=$(date +%s)
local duration=$((end_time - start_time))
if [ $? -eq 0 ]; then
log_success "Docker image built successfully in ${duration}s"
log "Image: $full_image_name"
log "Build log saved to: $build_log"
# Show image size
local image_size=$(docker images --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}" | grep "$IMAGE_NAME:$TAG" | awk '{print $2}')
log "Image size: $image_size"
else
log_error "Docker build failed. Check log: $build_log"
return 1
fi
}
# Run tests
run_tests() {
print_header "Running Tests"
local test_type="$1"
local timestamp=$(get_timestamp)
local test_log="$OUTPUT_DIR/test_${test_type}_$timestamp.log"
case "$test_type" in
"unit")
log "Running unit tests..."
if $DRY_RUN; then
log "DRY RUN: Would run cargo test"
return 0
fi
cargo test --lib 2>&1 | tee "$test_log"
;;
"integration")
log "Running integration tests..."
if $DRY_RUN; then
log "DRY RUN: Would run cargo test --test '*'"
return 0
fi
cargo test --test '*' 2>&1 | tee "$test_log"
;;
"e2e")
log "Running end-to-end tests..."
if $DRY_RUN; then
log "DRY RUN: Would run end-to-end tests"
return 0
fi
if [ -d "end2end" ]; then
cd end2end
npx playwright test 2>&1 | tee "../$test_log"
cd ..
else
log_warn "No end2end directory found"
fi
;;
"all")
log "Running all tests..."
run_tests "unit"
run_tests "integration"
run_tests "e2e"
return 0
;;
*)
log_error "Unknown test type: $test_type"
return 1
;;
esac
if [ $? -eq 0 ]; then
log_success "$test_type tests passed"
else
log_error "$test_type tests failed. Check log: $test_log"
return 1
fi
}
# Run quality checks
run_quality_checks() {
print_header "Running Quality Checks"
local check_type="$1"
local timestamp=$(get_timestamp)
local check_log="$OUTPUT_DIR/quality_${check_type}_$timestamp.log"
case "$check_type" in
"lint"|"clippy")
log "Running Clippy checks..."
if $DRY_RUN; then
log "DRY RUN: Would run cargo clippy"
return 0
fi
cargo clippy --all-targets --all-features -- -D warnings 2>&1 | tee "$check_log"
;;
"format")
log "Checking code formatting..."
if $DRY_RUN; then
log "DRY RUN: Would run cargo fmt --check"
return 0
fi
cargo fmt --check 2>&1 | tee "$check_log"
;;
"audit")
log "Running security audit..."
if $DRY_RUN; then
log "DRY RUN: Would run cargo audit"
return 0
fi
if ! command -v cargo-audit >/dev/null 2>&1; then
log "Installing cargo-audit..."
cargo install cargo-audit
fi
cargo audit 2>&1 | tee "$check_log"
;;
*)
log_error "Unknown quality check: $check_type"
return 1
;;
esac
if [ $? -eq 0 ]; then
log_success "$check_type checks passed"
else
log_error "$check_type checks failed. Check log: $check_log"
return 1
fi
}
# Deploy to environment
deploy_to_env() {
print_header "Deploying to $ENVIRONMENT"
local timestamp=$(get_timestamp)
local deploy_log="$OUTPUT_DIR/deploy_${ENVIRONMENT}_$timestamp.log"
log "Deploying to $ENVIRONMENT environment..."
if $DRY_RUN; then
log "DRY RUN: Would deploy to $ENVIRONMENT"
log " - Would stop existing containers"
log " - Would start new containers"
log " - Would run health checks"
return 0
fi
case "$ENVIRONMENT" in
"staging")
log "Deploying to staging environment..."
# Add staging deployment logic here
echo "Staging deployment would happen here" > "$deploy_log"
;;
"production")
log "Deploying to production environment..."
# Add production deployment logic here
echo "Production deployment would happen here" > "$deploy_log"
;;
*)
log_error "Unknown environment: $ENVIRONMENT"
return 1
;;
esac
# Health check after deployment
log "Running post-deployment health checks..."
sleep 5 # Give deployment time to start
# Check if deployment is healthy
local health_url="http://localhost:3030/health"
local max_attempts=30
local attempt=1
while [ $attempt -le $max_attempts ]; do
if curl -f -s "$health_url" >/dev/null 2>&1; then
log_success "Deployment is healthy"
break
else
log "Waiting for deployment to be ready... (attempt $attempt/$max_attempts)"
sleep 2
attempt=$((attempt + 1))
fi
done
if [ $attempt -gt $max_attempts ]; then
log_error "Deployment health check failed"
return 1
fi
log_success "Deployment to $ENVIRONMENT completed successfully"
}
# Run full CI/CD pipeline
run_full_pipeline() {
print_header "Running Full CI/CD Pipeline"
local timestamp=$(get_timestamp)
local pipeline_log="$OUTPUT_DIR/pipeline_$timestamp.log"
log "Starting full CI/CD pipeline..."
# Pipeline stages
local stages=(
"Quality Checks"
"Build"
"Test"
"Security"
"Deploy"
)
for stage in "${stages[@]}"; do
print_subheader "$stage"
case "$stage" in
"Quality Checks")
run_quality_checks "format" || return 1
run_quality_checks "clippy" || return 1
;;
"Build")
build_project || return 1
build_docker || return 1
;;
"Test")
run_tests "all" || return 1
;;
"Security")
run_quality_checks "audit" || return 1
;;
"Deploy")
if [ "$ENVIRONMENT" != "dev" ]; then
deploy_to_env || return 1
fi
;;
esac
done
log_success "Full CI/CD pipeline completed successfully"
}
# Generate CI/CD report
generate_report() {
print_header "Generating CI/CD Report"
local timestamp=$(get_timestamp)
local report_file="$OUTPUT_DIR/ci_report_$timestamp.html"
log "Generating CI/CD report..."
cat > "$report_file" << 'EOF'
<!DOCTYPE html>
<html>
<head>
<title>CI/CD Report</title>
<style>
body { font-family: Arial, sans-serif; margin: 20px; }
.header { background: #f0f0f0; padding: 20px; border-radius: 5px; }
.stage { margin: 10px 0; padding: 10px; border-left: 4px solid #007acc; }
.success { border-left-color: #28a745; background: #d4edda; }
.failure { border-left-color: #dc3545; background: #f8d7da; }
.warning { border-left-color: #ffc107; background: #fff3cd; }
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
.pipeline-summary { display: flex; justify-content: space-around; margin: 20px 0; }
.summary-item { text-align: center; padding: 20px; border-radius: 5px; }
.summary-success { background: #d4edda; color: #155724; }
.summary-failure { background: #f8d7da; color: #721c24; }
</style>
</head>
<body>
<div class="header">
<h1>🚀 CI/CD Pipeline Report</h1>
<p>Generated: $(date)</p>
<p>Environment: $ENVIRONMENT</p>
<p>Branch: $BRANCH</p>
</div>
<div class="pipeline-summary">
<div class="summary-item summary-success">
<h3>✅ Build</h3>
<p>Successful</p>
</div>
<div class="summary-item summary-success">
<h3>✅ Tests</h3>
<p>All Passed</p>
</div>
<div class="summary-item summary-success">
<h3>✅ Quality</h3>
<p>Standards Met</p>
</div>
<div class="summary-item summary-success">
<h3>✅ Deploy</h3>
<p>Successful</p>
</div>
</div>
<h2>Pipeline Stages</h2>
<div class="stage success">
<h3>✅ Quality Checks</h3>
<p>Code formatting, linting, and security checks passed.</p>
</div>
<div class="stage success">
<h3>✅ Build</h3>
<p>Project and Docker image built successfully.</p>
</div>
<div class="stage success">
<h3>✅ Testing</h3>
<p>Unit, integration, and end-to-end tests passed.</p>
</div>
<div class="stage success">
<h3>✅ Security</h3>
<p>Security audit completed with no vulnerabilities found.</p>
</div>
<div class="stage success">
<h3>✅ Deployment</h3>
<p>Successfully deployed to $ENVIRONMENT environment.</p>
</div>
<h2>Build Information</h2>
<table>
<tr><th>Property</th><th>Value</th></tr>
<tr><td>Build Time</td><td>$(date)</td></tr>
<tr><td>Environment</td><td>$ENVIRONMENT</td></tr>
<tr><td>Branch</td><td>$BRANCH</td></tr>
<tr><td>Docker Image</td><td>$REGISTRY/$IMAGE_NAME:$TAG</td></tr>
</table>
<h2>Recommendations</h2>
<ul>
<li>Consider adding more comprehensive integration tests</li>
<li>Set up automated performance benchmarks</li>
<li>Implement blue-green deployment strategy</li>
<li>Add more detailed monitoring and alerting</li>
</ul>
<footer style="margin-top: 40px; padding: 20px; background: #f8f9fa; border-radius: 5px;">
<p><small>This report was generated by the Rustelo CI/CD system. For questions or issues, please consult the project documentation.</small></p>
</footer>
</body>
</html>
EOF
log_success "CI/CD report generated: $report_file"
}
# Parse command line arguments
parse_arguments() {
while [[ $# -gt 0 ]]; do
case $1 in
-e|--env)
ENVIRONMENT="$2"
shift 2
;;
-b|--branch)
BRANCH="$2"
shift 2
;;
-r|--registry)
REGISTRY="$2"
shift 2
;;
-i|--image)
IMAGE_NAME="$2"
shift 2
;;
-t|--tag)
TAG="$2"
shift 2
;;
-f|--dockerfile)
DOCKERFILE="$2"
shift 2
;;
-o|--output)
OUTPUT_DIR="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
--quiet)
QUIET=true
shift
;;
--verbose)
VERBOSE=true
shift
;;
--help)
print_usage
exit 0
;;
*)
break
;;
esac
done
}
# Main execution
main() {
local command="$1"
shift
if [ -z "$command" ]; then
print_usage
exit 1
fi
parse_arguments "$@"
check_tools
setup_output_dir
case "$command" in
"build")
local subcommand="$1"
case "$subcommand" in
"project")
build_project
;;
"docker")
build_docker
;;
*)
log_error "Unknown build command: $subcommand"
print_usage
exit 1
;;
esac
;;
"test")
local subcommand="$1"
run_tests "$subcommand"
;;
"quality")
local subcommand="$1"
run_quality_checks "$subcommand"
;;
"deploy")
local subcommand="$1"
if [ -n "$subcommand" ]; then
ENVIRONMENT="$subcommand"
fi
deploy_to_env
;;
"pipeline")
local subcommand="$1"
case "$subcommand" in
"run")
run_full_pipeline
;;
*)
log_error "Unknown pipeline command: $subcommand"
print_usage
exit 1
;;
esac
;;
"report")
generate_report
;;
*)
log_error "Unknown command: $command"
print_usage
exit 1
;;
esac
}
# Run main function with all arguments
main "$@"