feat: Add comprehensive Gitea CI/CD workflows for multi-arch container builds
- Add build-container.yml: Main build pipeline with multi-arch support - Add pr-check.yml: Pull request validation with comprehensive testing - Add release.yml: Automated release pipeline with security scanning - Add nightly.yml: Daily builds with performance testing - Add health_check.sh: Container health validation script - Add setup-ci.sh: Local CI/CD environment setup script - Add comprehensive CI/CD documentation Features: - Multi-architecture builds (linux/amd64, linux/arm64) - Security scanning with Trivy - Automated PyPI publishing for releases - Container registry integration - Performance testing and validation - Artifact management and cleanup - Build caching and optimization Supports full development workflow from PR to production deployment.
This commit is contained in:
306
scripts/health_check.sh
Executable file
306
scripts/health_check.sh
Executable file
@@ -0,0 +1,306 @@
|
||||
#!/bin/bash
|
||||
# Health check script for UnitForge CI/CD workflows
|
||||
# Tests basic functionality of the running application
|
||||
|
||||
set -e
|
||||
|
||||
# Configuration
|
||||
HOST=${HOST:-localhost}
|
||||
PORT=${PORT:-8000}
|
||||
TIMEOUT=${TIMEOUT:-30}
|
||||
MAX_RETRIES=${MAX_RETRIES:-5}
|
||||
RETRY_DELAY=${RETRY_DELAY:-2}
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Helper functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if application is responding
|
||||
check_health() {
|
||||
local url="http://${HOST}:${PORT}/health"
|
||||
local retry_count=0
|
||||
|
||||
log_info "Checking health endpoint: $url"
|
||||
|
||||
while [ $retry_count -lt "$MAX_RETRIES" ]; do
|
||||
if curl -s -f --max-time "$TIMEOUT" "$url" > /dev/null 2>&1; then
|
||||
log_info "Health check passed"
|
||||
return 0
|
||||
fi
|
||||
|
||||
retry_count=$((retry_count + 1))
|
||||
log_warn "Health check failed (attempt $retry_count/$MAX_RETRIES)"
|
||||
|
||||
if [ $retry_count -lt "$MAX_RETRIES" ]; then
|
||||
log_info "Retrying in ${RETRY_DELAY} seconds..."
|
||||
sleep "$RETRY_DELAY"
|
||||
fi
|
||||
done
|
||||
|
||||
log_error "Health check failed after $MAX_RETRIES attempts"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Check if main page loads
|
||||
check_main_page() {
|
||||
local url="http://${HOST}:${PORT}/"
|
||||
log_info "Checking main page: $url"
|
||||
|
||||
local response
|
||||
response=$(curl -s -w "%{http_code}" --max-time "$TIMEOUT" "$url")
|
||||
local http_code="${response: -3}"
|
||||
|
||||
if [ "$http_code" = "200" ]; then
|
||||
log_info "Main page check passed (HTTP $http_code)"
|
||||
return 0
|
||||
else
|
||||
log_error "Main page check failed (HTTP $http_code)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check API endpoints
|
||||
check_api() {
|
||||
local base_url="http://${HOST}:${PORT}/api"
|
||||
log_info "Checking API endpoints"
|
||||
|
||||
# Check API health
|
||||
local api_health_url="${base_url}/health"
|
||||
if curl -s -f --max-time "$TIMEOUT" "$api_health_url" > /dev/null 2>&1; then
|
||||
log_info "API health endpoint passed"
|
||||
else
|
||||
log_warn "API health endpoint failed or not available"
|
||||
fi
|
||||
|
||||
# Check API version
|
||||
local api_version_url="${base_url}/version"
|
||||
if curl -s -f --max-time "$TIMEOUT" "$api_version_url" > /dev/null 2>&1; then
|
||||
log_info "API version endpoint passed"
|
||||
else
|
||||
log_warn "API version endpoint failed or not available"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Check static assets
|
||||
check_static_assets() {
|
||||
log_info "Checking static assets"
|
||||
|
||||
local assets=(
|
||||
"/static/css/style.css"
|
||||
"/static/js/app.js"
|
||||
"/static/vendor/bootstrap/css/bootstrap.min.css"
|
||||
"/static/vendor/fontawesome/css/all.min.css"
|
||||
)
|
||||
|
||||
local failed_assets=0
|
||||
|
||||
for asset in "${assets[@]}"; do
|
||||
local url="http://${HOST}:${PORT}${asset}"
|
||||
if curl -s -f --max-time "$TIMEOUT" "$url" > /dev/null 2>&1; then
|
||||
log_info "Asset check passed: $asset"
|
||||
else
|
||||
log_warn "Asset check failed: $asset"
|
||||
failed_assets=$((failed_assets + 1))
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $failed_assets -eq 0 ]; then
|
||||
log_info "All static assets available"
|
||||
return 0
|
||||
else
|
||||
log_warn "$failed_assets static assets failed to load"
|
||||
return 0 # Don't fail health check for missing assets
|
||||
fi
|
||||
}
|
||||
|
||||
# Performance test
|
||||
check_performance() {
|
||||
log_info "Running basic performance test"
|
||||
|
||||
local url="http://${HOST}:${PORT}/"
|
||||
local response_time
|
||||
|
||||
# Test response time
|
||||
local response_time
|
||||
response_time=$(curl -s -w "%{time_total}" --max-time "$TIMEOUT" -o /dev/null "$url")
|
||||
|
||||
if curl -s -w "%{time_total}" --max-time "$TIMEOUT" -o /dev/null "$url" > /dev/null 2>&1; then
|
||||
log_info "Response time: ${response_time}s"
|
||||
|
||||
# Check if response time is reasonable (< 5 seconds)
|
||||
if (( $(echo "$response_time < 5.0" | bc -l) )); then
|
||||
log_info "Performance check passed"
|
||||
return 0
|
||||
else
|
||||
log_warn "Performance check warning: slow response time (${response_time}s)"
|
||||
return 0 # Don't fail health check for slow response
|
||||
fi
|
||||
else
|
||||
log_error "Performance check failed: no response"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Memory usage check (if running in container)
|
||||
check_memory() {
|
||||
if command -v docker > /dev/null 2>&1 && [ -n "$CONTAINER_NAME" ]; then
|
||||
log_info "Checking container memory usage"
|
||||
|
||||
local memory_usage
|
||||
memory_usage=$(docker stats "$CONTAINER_NAME" --no-stream --format "{{.MemUsage}}" | cut -d'/' -f1)
|
||||
|
||||
if [ -n "$memory_usage" ]; then
|
||||
log_info "Memory usage: $memory_usage"
|
||||
else
|
||||
log_warn "Could not determine memory usage"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Wait for application to start
|
||||
wait_for_startup() {
|
||||
log_info "Waiting for application to start..."
|
||||
local startup_timeout=60
|
||||
local elapsed=0
|
||||
|
||||
while [ $elapsed -lt $startup_timeout ]; do
|
||||
if curl -s --max-time 5 "http://${HOST}:${PORT}/" > /dev/null 2>&1; then
|
||||
log_info "Application is responding"
|
||||
return 0
|
||||
fi
|
||||
|
||||
sleep 5
|
||||
elapsed=$((elapsed + 5))
|
||||
log_info "Waiting... (${elapsed}s/${startup_timeout}s)"
|
||||
done
|
||||
|
||||
log_error "Application failed to start within ${startup_timeout} seconds"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Main health check function
|
||||
run_health_check() {
|
||||
log_info "Starting UnitForge health check"
|
||||
log_info "Target: http://${HOST}:${PORT}"
|
||||
|
||||
local failed_checks=0
|
||||
|
||||
# Wait for startup if needed
|
||||
if ! curl -s --max-time 5 "http://${HOST}:${PORT}/" > /dev/null 2>&1; then
|
||||
wait_for_startup || return 1
|
||||
fi
|
||||
|
||||
# Run all checks
|
||||
check_health || failed_checks=$((failed_checks + 1))
|
||||
check_main_page || failed_checks=$((failed_checks + 1))
|
||||
check_api || failed_checks=$((failed_checks + 1))
|
||||
check_static_assets || true # Don't count static asset failures
|
||||
check_performance || true # Don't count performance warnings
|
||||
check_memory || true # Don't count memory check failures
|
||||
|
||||
# Summary
|
||||
if [ $failed_checks -eq 0 ]; then
|
||||
log_info "✅ All health checks passed"
|
||||
return 0
|
||||
else
|
||||
log_error "❌ $failed_checks health checks failed"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Usage information
|
||||
usage() {
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -h, --host HOST Target host (default: localhost)"
|
||||
echo " -p, --port PORT Target port (default: 8000)"
|
||||
echo " -t, --timeout TIMEOUT Request timeout in seconds (default: 30)"
|
||||
echo " -r, --retries RETRIES Maximum retry attempts (default: 5)"
|
||||
echo " -d, --delay DELAY Retry delay in seconds (default: 2)"
|
||||
echo " -c, --container NAME Container name for memory checks"
|
||||
echo " --help Show this help message"
|
||||
echo ""
|
||||
echo "Environment variables:"
|
||||
echo " HOST Same as --host"
|
||||
echo " PORT Same as --port"
|
||||
echo " TIMEOUT Same as --timeout"
|
||||
echo " MAX_RETRIES Same as --retries"
|
||||
echo " RETRY_DELAY Same as --delay"
|
||||
echo " CONTAINER_NAME Same as --container"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 # Check localhost:8000"
|
||||
echo " $0 -h production.example.com -p 80 # Check production server"
|
||||
echo " $0 -c unitforge-container # Include container memory check"
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-h|--host)
|
||||
HOST="$2"
|
||||
shift 2
|
||||
;;
|
||||
-p|--port)
|
||||
PORT="$2"
|
||||
shift 2
|
||||
;;
|
||||
-t|--timeout)
|
||||
TIMEOUT="$2"
|
||||
shift 2
|
||||
;;
|
||||
-r|--retries)
|
||||
MAX_RETRIES="$2"
|
||||
shift 2
|
||||
;;
|
||||
-d|--delay)
|
||||
RETRY_DELAY="$2"
|
||||
shift 2
|
||||
;;
|
||||
-c|--container)
|
||||
CONTAINER_NAME="$2"
|
||||
shift 2
|
||||
;;
|
||||
--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check dependencies
|
||||
if ! command -v curl > /dev/null 2>&1; then
|
||||
log_error "curl is required but not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v bc > /dev/null 2>&1; then
|
||||
log_warn "bc is not installed, performance timing may not work properly"
|
||||
fi
|
||||
|
||||
# Run the health check
|
||||
run_health_check
|
||||
exit $?
|
||||
445
scripts/setup-ci.sh
Executable file
445
scripts/setup-ci.sh
Executable file
@@ -0,0 +1,445 @@
|
||||
#!/bin/bash
|
||||
# CI/CD Setup Script for UnitForge
|
||||
# Sets up local environment for testing CI/CD workflows
|
||||
|
||||
set -e
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Helper functions
|
||||
log_info() {
|
||||
echo -e "${GREEN}[INFO]${NC} $1"
|
||||
}
|
||||
|
||||
log_warn() {
|
||||
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||
}
|
||||
|
||||
log_error() {
|
||||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
log_step() {
|
||||
echo -e "${BLUE}[STEP]${NC} $1"
|
||||
}
|
||||
|
||||
# Check if command exists
|
||||
command_exists() {
|
||||
command -v "$1" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Check Docker and Docker Buildx
|
||||
check_docker() {
|
||||
log_step "Checking Docker installation..."
|
||||
|
||||
if ! command_exists docker; then
|
||||
log_error "Docker is not installed"
|
||||
echo "Please install Docker from: https://docs.docker.com/get-docker/"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Docker found: $(docker --version)"
|
||||
|
||||
# Check if Docker daemon is running
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
log_error "Docker daemon is not running"
|
||||
echo "Please start Docker daemon"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check Docker Buildx
|
||||
if ! docker buildx version >/dev/null 2>&1; then
|
||||
log_warn "Docker Buildx not found, installing..."
|
||||
docker buildx install 2>/dev/null || true
|
||||
fi
|
||||
|
||||
log_info "Docker Buildx found: $(docker buildx version)"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Setup Docker Buildx for multi-arch builds
|
||||
setup_buildx() {
|
||||
log_step "Setting up Docker Buildx for multi-arch builds..."
|
||||
|
||||
# Create builder if it doesn't exist
|
||||
if ! docker buildx ls | grep -q "unitforge-builder"; then
|
||||
log_info "Creating unitforge-builder..."
|
||||
docker buildx create --name unitforge-builder --use
|
||||
else
|
||||
log_info "Using existing unitforge-builder"
|
||||
docker buildx use unitforge-builder
|
||||
fi
|
||||
|
||||
# Bootstrap the builder
|
||||
log_info "Bootstrapping builder..."
|
||||
docker buildx inspect --bootstrap
|
||||
|
||||
log_info "Builder setup complete"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Check container registry access
|
||||
check_registry() {
|
||||
log_step "Checking container registry configuration..."
|
||||
|
||||
if [ -f ".env" ]; then
|
||||
log_info "Found .env file"
|
||||
|
||||
if grep -q "CONTAINER_REGISTRY_URL" .env; then
|
||||
local registry_url
|
||||
registry_url=$(grep '^CONTAINER_REGISTRY_URL=' .env | cut -d'=' -f2)
|
||||
log_info "Registry URL: $registry_url"
|
||||
else
|
||||
log_warn "CONTAINER_REGISTRY_URL not found in .env"
|
||||
fi
|
||||
|
||||
if grep -q "CONTAINER_TAG" .env; then
|
||||
local container_tag
|
||||
container_tag=$(grep '^CONTAINER_TAG=' .env | cut -d'=' -f2)
|
||||
log_info "Container tag: $container_tag"
|
||||
else
|
||||
log_warn "CONTAINER_TAG not found in .env"
|
||||
fi
|
||||
else
|
||||
log_warn ".env file not found"
|
||||
log_info "Creating sample .env file..."
|
||||
|
||||
cat > .env << EOF
|
||||
# Container Registry Configuration
|
||||
CONTAINER_REGISTRY_URL=gitea-http.taildb3494.ts.net/will/unitforge
|
||||
CONTAINER_TAG=latest
|
||||
|
||||
# Development Configuration
|
||||
DEBUG=true
|
||||
LOG_LEVEL=debug
|
||||
EOF
|
||||
|
||||
log_info "Sample .env file created. Please update with your registry details."
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Verify vendor assets
|
||||
check_vendor_assets() {
|
||||
log_step "Checking vendor assets..."
|
||||
|
||||
local assets=(
|
||||
"frontend/static/vendor/bootstrap/css/bootstrap.min.css"
|
||||
"frontend/static/vendor/bootstrap/js/bootstrap.bundle.min.js"
|
||||
"frontend/static/vendor/fontawesome/css/all.min.css"
|
||||
"frontend/static/vendor/fontawesome/webfonts/fa-solid-900.woff2"
|
||||
"frontend/static/img/osi-logo.svg"
|
||||
)
|
||||
|
||||
local missing_assets=0
|
||||
|
||||
for asset in "${assets[@]}"; do
|
||||
if [ ! -f "$asset" ]; then
|
||||
log_warn "Missing asset: $asset"
|
||||
missing_assets=$((missing_assets + 1))
|
||||
else
|
||||
log_info "Found asset: $asset"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $missing_assets -gt 0 ]; then
|
||||
log_error "$missing_assets vendor assets are missing"
|
||||
log_info "Please ensure all vendor assets are downloaded and committed"
|
||||
log_info "Run: make setup-dev to download missing assets"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "All vendor assets found"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Test local build
|
||||
test_local_build() {
|
||||
log_step "Testing local Docker build..."
|
||||
|
||||
if docker build -t unitforge:test . >/dev/null 2>&1; then
|
||||
log_info "Local Docker build successful"
|
||||
|
||||
# Test container startup
|
||||
log_info "Testing container startup..."
|
||||
if docker run -d --name unitforge-test -p 8080:8000 unitforge:test >/dev/null 2>&1; then
|
||||
sleep 5
|
||||
|
||||
if curl -s -f http://localhost:8080/ >/dev/null 2>&1; then
|
||||
log_info "Container startup test successful"
|
||||
else
|
||||
log_warn "Container started but not responding on port 8080"
|
||||
fi
|
||||
|
||||
docker stop unitforge-test >/dev/null 2>&1
|
||||
docker rm unitforge-test >/dev/null 2>&1
|
||||
else
|
||||
log_warn "Container startup test failed"
|
||||
fi
|
||||
|
||||
# Clean up test image
|
||||
docker rmi unitforge:test >/dev/null 2>&1 || true
|
||||
|
||||
return 0
|
||||
else
|
||||
log_error "Local Docker build failed"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Test multi-arch build
|
||||
test_multiarch_build() {
|
||||
log_step "Testing multi-architecture build..."
|
||||
|
||||
if docker buildx build --platform linux/amd64,linux/arm64 -t unitforge:multiarch-test . >/dev/null 2>&1; then
|
||||
log_info "Multi-architecture build successful"
|
||||
|
||||
# Clean up
|
||||
docker buildx rm --force >/dev/null 2>&1 || true
|
||||
|
||||
return 0
|
||||
else
|
||||
log_error "Multi-architecture build failed"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check development environment
|
||||
check_dev_environment() {
|
||||
log_step "Checking development environment..."
|
||||
|
||||
# Check uv
|
||||
if ! command_exists uv; then
|
||||
log_error "uv is not installed"
|
||||
echo "Install with: curl -LsSf https://astral.sh/uv/install.sh | sh"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "uv found: $(uv --version)"
|
||||
|
||||
# Check Python
|
||||
if ! command_exists python3; then
|
||||
log_error "Python 3 is not installed"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log_info "Python found: $(python3 --version)"
|
||||
|
||||
# Check if virtual environment exists
|
||||
if [ -d ".venv" ]; then
|
||||
log_info "Virtual environment exists"
|
||||
else
|
||||
log_warn "Virtual environment not found"
|
||||
log_info "Run: make setup-dev to create it"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Test CI/CD workflow syntax
|
||||
check_workflow_syntax() {
|
||||
log_step "Checking workflow syntax..."
|
||||
|
||||
local workflows_dir=".gitea/workflows"
|
||||
|
||||
if [ ! -d "$workflows_dir" ]; then
|
||||
log_error "Workflows directory not found: $workflows_dir"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local yaml_files=("$workflows_dir"/*.yml)
|
||||
|
||||
if [ ${#yaml_files[@]} -eq 0 ]; then
|
||||
log_warn "No YAML workflow files found"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local syntax_errors=0
|
||||
|
||||
for file in "${yaml_files[@]}"; do
|
||||
if [ -f "$file" ]; then
|
||||
log_info "Checking syntax: $(basename "$file")"
|
||||
|
||||
# Basic YAML syntax check (if python3 is available)
|
||||
if command_exists python3; then
|
||||
if python3 -c "import yaml; yaml.safe_load(open('$file'))" 2>/dev/null; then
|
||||
log_info "✓ $(basename "$file") syntax OK"
|
||||
else
|
||||
log_error "✗ $(basename "$file") has syntax errors"
|
||||
syntax_errors=$((syntax_errors + 1))
|
||||
fi
|
||||
else
|
||||
log_warn "Python3 not available, skipping YAML syntax check"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $syntax_errors -eq 0 ]; then
|
||||
log_info "All workflow files have valid syntax"
|
||||
return 0
|
||||
else
|
||||
log_error "$syntax_errors workflow files have syntax errors"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate CI/CD documentation
|
||||
generate_docs() {
|
||||
log_step "Generating CI/CD documentation..."
|
||||
|
||||
local docs_dir="docs/ci-cd"
|
||||
mkdir -p "$docs_dir"
|
||||
|
||||
cat > "$docs_dir/local-testing.md" << 'EOF'
|
||||
# Local CI/CD Testing
|
||||
|
||||
This guide helps you test CI/CD workflows locally before pushing to the repository.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker with Buildx support
|
||||
- uv package manager
|
||||
- Python 3.8+
|
||||
|
||||
## Local Testing Commands
|
||||
|
||||
```bash
|
||||
# Test local build
|
||||
make docker-build
|
||||
|
||||
# Test multi-arch build
|
||||
make docker-buildx-local
|
||||
|
||||
# Test full development workflow
|
||||
make dev
|
||||
|
||||
# Run health checks
|
||||
./scripts/health_check.sh
|
||||
```
|
||||
|
||||
## Workflow Testing
|
||||
|
||||
Use `act` to test GitHub/Gitea workflows locally:
|
||||
|
||||
```bash
|
||||
# Install act
|
||||
curl https://raw.githubusercontent.com/nektos/act/master/install.sh | sudo bash
|
||||
|
||||
# Test PR workflow
|
||||
act pull_request -s CONTAINER_REGISTRY_USERNAME=test -s CONTAINER_REGISTRY_PASSWORD=test
|
||||
|
||||
# Test release workflow
|
||||
act push -e tests/fixtures/release-event.json
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Build Issues
|
||||
- Ensure all vendor assets are committed
|
||||
- Check Docker daemon is running
|
||||
- Verify buildx is properly configured
|
||||
|
||||
### Registry Issues
|
||||
- Check .env file configuration
|
||||
- Verify registry credentials
|
||||
- Test registry connectivity
|
||||
|
||||
### Performance Issues
|
||||
- Use build cache: `--cache-from type=gha`
|
||||
- Optimize Docker layers
|
||||
- Use multi-stage builds
|
||||
```
|
||||
EOF
|
||||
|
||||
log_info "Local testing documentation generated: $docs_dir/local-testing.md"
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Main setup function
|
||||
main() {
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo -e "${BLUE} UnitForge CI/CD Setup${NC}"
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
echo ""
|
||||
|
||||
local failed_checks=0
|
||||
|
||||
# Run all checks
|
||||
check_docker || failed_checks=$((failed_checks + 1))
|
||||
setup_buildx || failed_checks=$((failed_checks + 1))
|
||||
check_registry || true # Don't fail on registry issues
|
||||
check_vendor_assets || failed_checks=$((failed_checks + 1))
|
||||
check_dev_environment || failed_checks=$((failed_checks + 1))
|
||||
check_workflow_syntax || failed_checks=$((failed_checks + 1))
|
||||
|
||||
# Optional tests
|
||||
if [ "$1" = "--test-build" ]; then
|
||||
test_local_build || failed_checks=$((failed_checks + 1))
|
||||
test_multiarch_build || failed_checks=$((failed_checks + 1))
|
||||
fi
|
||||
|
||||
# Generate documentation
|
||||
generate_docs || true
|
||||
|
||||
echo ""
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
|
||||
if [ $failed_checks -eq 0 ]; then
|
||||
log_info "✅ CI/CD setup completed successfully!"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Update .env with your registry details"
|
||||
echo "2. Test local build: make docker-buildx-local"
|
||||
echo "3. Run full test suite: make dev"
|
||||
echo "4. Check workflow syntax: ./scripts/setup-ci.sh"
|
||||
echo ""
|
||||
echo "For testing builds:"
|
||||
echo " ./scripts/setup-ci.sh --test-build"
|
||||
else
|
||||
log_error "❌ CI/CD setup completed with $failed_checks issues"
|
||||
echo ""
|
||||
echo "Please fix the issues above before proceeding."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}========================================${NC}"
|
||||
}
|
||||
|
||||
# Usage information
|
||||
usage() {
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --test-build Run local and multi-arch build tests"
|
||||
echo " --help Show this help message"
|
||||
echo ""
|
||||
echo "This script sets up your local environment for CI/CD development."
|
||||
echo "It checks Docker, Buildx, dependencies, and workflow syntax."
|
||||
}
|
||||
|
||||
# Parse command line arguments
|
||||
case "${1:-}" in
|
||||
--help)
|
||||
usage
|
||||
exit 0
|
||||
;;
|
||||
--test-build)
|
||||
main --test-build
|
||||
;;
|
||||
"")
|
||||
main
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
Reference in New Issue
Block a user