diff --git a/scripts/test-local-ci-cd.sh b/scripts/test-local-ci-cd.sh index 5451607..0e29128 100755 --- a/scripts/test-local-ci-cd.sh +++ b/scripts/test-local-ci-cd.sh @@ -16,17 +16,17 @@ if ! command -v go >/dev/null 2>&1; then exit 1 fi +# Assume Docker is available (required for this workflow) if ! command -v docker >/dev/null 2>&1; then - echo "⚠️ Docker not found. Docker build steps will be skipped" - HAS_DOCKER=false -else - HAS_DOCKER=true - - # Check for docker compose plugin - if ! docker compose version >/dev/null 2>&1; then - echo "⚠️ Docker Compose plugin not found. Installing..." - sudo apt-get update && sudo apt-get install -y docker-compose-plugin - fi + echo "❌ Docker is required for this CI/CD workflow" + echo "Please install Docker and Docker Compose plugin" + exit 1 +fi + +# Check for docker compose plugin +if ! docker compose version >/dev/null 2>&1; then + echo "⚠️ Docker Compose plugin not found. Installing..." + sudo apt-get update && sudo apt-get install -y docker-compose-plugin fi echo "✅ Environment ready" @@ -41,74 +41,60 @@ echo "" # 3. Check for Docker cache echo "3. Checking for Docker build cache..." -if [ "$HAS_DOCKER" = true ]; then - IMAGE_NAME="gitea.arcodange.lab/arcodange/dance-lessons-coach-build-cache:$DEPS_HASH" - - # Try to pull the cache image - if docker pull "$IMAGE_NAME" >/dev/null 2>&1; then - echo "✅ Cache hit - using existing build cache" - USE_DOCKER_CACHE=true - else - echo "⚠️ Cache miss - will build without cache" - USE_DOCKER_CACHE=false - fi +IMAGE_NAME="gitea.arcodange.lab/arcodange/dance-lessons-coach-build-cache:$DEPS_HASH" + +# Try to pull the cache image +if docker pull "$IMAGE_NAME" >/dev/null 2>&1; then + echo "✅ Cache hit - using existing build cache" + USE_DOCKER_CACHE=true else - echo "⚠️ Docker not available - running natively" + echo "⚠️ Cache miss - will build without cache" USE_DOCKER_CACHE=false fi echo "" # 4. Start PostgreSQL with Docker Compose echo "4. Starting PostgreSQL..." -if [ "$HAS_DOCKER" = true ]; then - docker compose -f docker-compose.yml up -d postgres - - # Wait for PostgreSQL to be ready - echo "Waiting for PostgreSQL to be ready..." - for i in {1..30}; do - if docker exec dance-lessons-coach-postgres pg_isready -U postgres; then - echo "✅ PostgreSQL is ready!" - break - fi - echo "Waiting for PostgreSQL... ($i/30)" - sleep 2 - done - - # Set PostgreSQL environment variables for BDD tests - # Use container name for Docker, localhost for native (port mapping) - if [ "$HAS_DOCKER" = true ]; then - export DLC_DATABASE_HOST="dance-lessons-coach-postgres" - else - export DLC_DATABASE_HOST="localhost" +docker compose -f docker-compose.yml up -d postgres + +# Wait for PostgreSQL to be ready +echo "Waiting for PostgreSQL to be ready..." +for i in {1..30}; do + if docker exec dance-lessons-coach-postgres pg_isready -U postgres; then + echo "✅ PostgreSQL is ready!" + break fi - export DLC_DATABASE_PORT=5432 - export DLC_DATABASE_USER=postgres - export DLC_DATABASE_PASSWORD=postgres - export DLC_DATABASE_NAME=dance_lessons_coach_bdd_test - export DLC_DATABASE_SSL_MODE=disable -else - echo "⚠️ Docker not available - PostgreSQL tests will be skipped" -fi + echo "Waiting for PostgreSQL... ($i/30)" + sleep 2 +done + +# Set PostgreSQL environment variables for BDD tests +export DLC_DATABASE_HOST="dance-lessons-coach-postgres" +export DLC_DATABASE_PORT=5432 +export DLC_DATABASE_USER=postgres +export DLC_DATABASE_PASSWORD=postgres +export DLC_DATABASE_NAME=dance_lessons_coach_bdd_test +export DLC_DATABASE_SSL_MODE=disable echo "" -# 5. Check dependencies -echo "5. Checking dependencies..." +# 5. Install dependencies if [ "$USE_DOCKER_CACHE" = true ]; then + echo "5. Checking dependencies..." echo "✅ Using pre-installed dependencies from Docker cache" - # No need to run go mod tidy - dependencies are already in the cache else - echo "Running natively - ensuring dependencies are up to date..." + echo "5. Installing dependencies..." go mod tidy fi echo "✅ Dependencies ready" echo "" # 6. Generate Swagger Docs -echo "6. Generating Swagger documentation..." if [ "$USE_DOCKER_CACHE" = true ]; then + echo "6. Generating Swagger documentation..." echo "Running in Docker Compose container..." docker compose -f docker-compose.build.yml run -w /workspace/pkg/server build-cache sh -c "go generate" else + echo "6. Generating Swagger documentation..." echo "Running natively..." cd pkg/server && go generate cd ../.. @@ -117,11 +103,12 @@ echo "✅ Swagger documentation generated" echo "" # 7. Build and test -echo "7. Building and testing..." if [ "$USE_DOCKER_CACHE" = true ]; then + echo "7. Building and testing..." echo "Running in Docker Compose container..." docker compose -f docker-compose.build.yml run -w /workspace build-cache sh -c "go build ./..." else + echo "7. Building and testing..." echo "Running natively..." go build ./... fi @@ -141,12 +128,6 @@ if [ "$USE_DOCKER_CACHE" = true ]; then sh -c "go test ./... -coverprofile=coverage.out -v && go tool cover -func=coverage.out > coverage.txt" else echo "Running natively with Docker Compose PostgreSQL..." - export DLC_DATABASE_HOST=dance-lessons-coach-postgres - export DLC_DATABASE_PORT=5432 - export DLC_DATABASE_USER=postgres - export DLC_DATABASE_PASSWORD=postgres - export DLC_DATABASE_NAME=dance_lessons_coach_bdd_test - export DLC_DATABASE_SSL_MODE=disable go test ./... -coverprofile=coverage.out -v go tool cover -func=coverage.out > coverage.txt fi @@ -154,11 +135,12 @@ echo "✅ Tests passed" echo "" # 8. Build binaries -echo "8. Building binaries..." if [ "$USE_DOCKER_CACHE" = true ]; then + echo "8. Building binaries..." echo "Running in Docker Compose container..." docker compose -f docker-compose.build.yml run -w /workspace build-cache sh -c "./scripts/build.sh" else + echo "8. Building binaries..." echo "Running natively..." ./scripts/build.sh fi @@ -190,174 +172,170 @@ CURRENT_VERSION="$MAJOR.$MINOR.$PATCH${PRERELEASE:+-$PRERELEASE}" echo "📊 Current version: $CURRENT_VERSION" echo "" -# 7. Local Docker build instructions -if [ "$HAS_DOCKER" = true ]; then - echo "🐳 LOCAL DOCKER BUILD INSTRUCTIONS" - echo "================================" - echo "" +# 10. Local Docker build instructions +echo "🐳 LOCAL DOCKER BUILD INSTRUCTIONS" +echo "================================" +echo "" + +echo "1. Build Docker image locally (development):" +echo " docker build -t dance-lessons-coach:$CURRENT_VERSION ." +echo "" + +echo "2. Build production image using docker/Dockerfile.prod:" +echo " # Note: Local docker/Dockerfile.prod uses 'latest' tag for testing" +echo " docker build -t dance-lessons-coach-prod:$CURRENT_VERSION -f docker/Dockerfile.prod ." +echo " # For CI/CD, the workflow generates correct docker/Dockerfile.prod with dependency hash" +echo "" + +echo "3. Compare image sizes:" +echo " docker images | grep dance-lessons-coach" +echo "" + +echo "4. Tag the image:" +echo " docker tag dance-lessons-coach:$CURRENT_VERSION dance-lessons-coach:latest" +echo "" + +echo "5. Test the local image (check port availability first):" +echo " docker run -d -p 8080:8080 dance-lessons-coach:$CURRENT_VERSION" +echo " # Or use alternative port if 8080 is in use:" +echo " docker run -d -p 8081:8080 dance-lessons-coach:$CURRENT_VERSION" +echo "" +echo "6. Branch-specific container naming (recommended):" +echo " BRANCH=\"$(git rev-parse --abbrev-ref HEAD | tr '/' '-')\"" +echo " docker run -d -p 8080:8080 --name dance-lessons-coach-\"$BRANCH\" dance-lessons-coach:$CURRENT_VERSION" +echo "" + +echo "7. Test API endpoints:" +echo " curl http://localhost:8080/api/health" +echo " curl http://localhost:8080/api/v1/greet/YourName" +echo "" + +echo "8. Clean up:" +echo " docker stop && docker rm " +echo "" + +echo "💡 Tip: Use 'docker images' to see your built images" +echo "💡 Use 'docker ps' to see running containers" +echo "" + +# Ask if user wants to build Docker image now +read -p "🚀 Do you want to build the Docker image now? (y/n): " -n 1 -r +echo "" +if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "🐳 Building Docker image..." + read -p "📋 Build (d)development or (p)production image? [d/p]: " -n 1 -r +echo "" + if [[ $REPLY =~ ^[Pp]$ ]]; then + echo "🏗️ Building production image with docker/Dockerfile.prod..." + docker build -t dance-lessons-coach-prod:$CURRENT_VERSION -f docker/Dockerfile.prod . + docker tag dance-lessons-coach-prod:$CURRENT_VERSION dance-lessons-coach-prod:latest + echo "✅ Production Docker image built: dance-lessons-coach-prod:$CURRENT_VERSION" + CONTAINER_IMAGE="dance-lessons-coach-prod:$CURRENT_VERSION" + else + echo "🏗️ Building development image with Dockerfile..." + docker build -t dance-lessons-coach:$CURRENT_VERSION . + docker tag dance-lessons-coach:$CURRENT_VERSION dance-lessons-coach:latest + echo "✅ Development Docker image built: dance-lessons-coach:$CURRENT_VERSION" + CONTAINER_IMAGE="dance-lessons-coach:$CURRENT_VERSION" + fi +echo "" - echo "1. Build Docker image locally (development):" - echo " docker build -t dance-lessons-coach:$CURRENT_VERSION ." - echo "" - - echo "2. Build production image using docker/Dockerfile.prod:" - echo " # Note: Local docker/Dockerfile.prod uses 'latest' tag for testing" - echo " docker build -t dance-lessons-coach-prod:$CURRENT_VERSION -f docker/Dockerfile.prod ." - echo " # For CI/CD, the workflow generates correct docker/Dockerfile.prod with dependency hash" - echo "" - - echo "3. Compare image sizes:" - echo " docker images | grep dance-lessons-coach" - echo "" - - echo "4. Tag the image:" - echo " docker tag dance-lessons-coach:$CURRENT_VERSION dance-lessons-coach:latest" - echo "" - - echo "3. Test the local image (check port availability first):" - echo " docker run -d -p 8080:8080 dance-lessons-coach:$CURRENT_VERSION" - echo " # Or use alternative port if 8080 is in use:" - echo " docker run -d -p 8081:8080 dance-lessons-coach:$CURRENT_VERSION" - echo "" - echo "4. Branch-specific container naming (recommended):" - echo " BRANCH=\"(git rev-parse --abbrev-ref HEAD | tr '/' '-')" - echo " docker run -d -p 8080:8080 --name dance-lessons-coach-\"$BRANCH\" dance-lessons-coach:$CURRENT_VERSION" - echo "" - - echo "5. Test API endpoints:" - echo " curl http://localhost:8080/api/health" - echo " curl http://localhost:8080/api/v1/greet/YourName" - echo "" - - echo "5. Clean up:" - echo " docker stop && docker rm " - echo "" - - echo "💡 Tip: Use 'docker images' to see your built images" - echo "💡 Use 'docker ps' to see running containers" - echo "" - - # Ask if user wants to build Docker image now - read -p "🚀 Do you want to build the Docker image now? (y/n): " -n 1 -r - echo "" - if [[ $REPLY =~ ^[Yy]$ ]]; then - echo "🐳 Building Docker image..." - read -p "📋 Build (d)development or (p)production image? [d/p]: " -n 1 -r - echo "" - if [[ $REPLY =~ ^[Pp]$ ]]; then - echo "🏗️ Building production image with docker/Dockerfile.prod..." - docker build -t dance-lessons-coach-prod:$CURRENT_VERSION -f docker/Dockerfile.prod . - docker tag dance-lessons-coach-prod:$CURRENT_VERSION dance-lessons-coach-prod:latest - echo "✅ Production Docker image built: dance-lessons-coach-prod:$CURRENT_VERSION" - CONTAINER_IMAGE="dance-lessons-coach-prod:$CURRENT_VERSION" + # Check if port 8080 is available + echo "🔍 Checking port availability..." + if lsof -i :8080 > /dev/null 2>&1; then + echo "⚠️ Port 8080 is already in use" + read -p "🚀 Do you want to use a different port? (y/n): " -n 1 -r +echo "" + if [[ $REPLY =~ ^[Yy]$ ]]; then + read -p "Enter port number (e.g., 8081): " CUSTOM_PORT +echo "" + PORT=$CUSTOM_PORT else - echo "🏗️ Building development image with Dockerfile..." - docker build -t dance-lessons-coach:$CURRENT_VERSION . - docker tag dance-lessons-coach:$CURRENT_VERSION dance-lessons-coach:latest - echo "✅ Development Docker image built: dance-lessons-coach:$CURRENT_VERSION" - CONTAINER_IMAGE="dance-lessons-coach:$CURRENT_VERSION" - fi - echo "" - - # Check if port 8080 is available - echo "🔍 Checking port availability..." - if lsof -i :8080 > /dev/null 2>&1; then - echo "⚠️ Port 8080 is already in use" - read -p "🚀 Do you want to use a different port? (y/n): " -n 1 -r - echo "" - if [[ $REPLY =~ ^[Yy]$ ]]; then - read -p "Enter port number (e.g., 8081): " CUSTOM_PORT - echo "" - PORT=$CUSTOM_PORT - else - echo "ℹ️ Using port 8080 anyway (may fail if service is running)" - PORT=8080 - fi - else - echo "✅ Port 8080 is available" + echo "ℹ️ Using port 8080 anyway (may fail if service is running)" PORT=8080 fi - - read -p "🚀 Do you want to run the container now on port $PORT? (y/n): " -n 1 -r - echo "" - if [[ $REPLY =~ ^[Yy]$ ]]; then - # Get current branch name for container naming - BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD | tr '/' '-') - CONTAINER_NAME="dance-lessons-coach-$BRANCH_NAME" - - echo "🐳 Preparing container '$CONTAINER_NAME' on port $PORT..." - - # Remove existing container if it exists - if docker ps -a --format '{{.Names}}' | grep -q "^$CONTAINER_NAME$"; then - echo "⚠️ Container '$CONTAINER_NAME' already exists - removing it..." - docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true - docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true - echo "✅ Old container removed" - fi - - # Also remove the generic test container if it exists - if docker ps -a --format '{{.Names}}' | grep -q "^dance-lessons-coach-test$"; then - echo "⚠️ Generic test container exists - removing it..." - docker stop dance-lessons-coach-test > /dev/null 2>&1 || true - docker rm dance-lessons-coach-test > /dev/null 2>&1 || true - echo "✅ Old generic container removed" - fi - - echo "🐳 Starting container '$CONTAINER_NAME' on port $PORT..." - docker run -d -p $PORT:8080 --name "$CONTAINER_NAME" "$CONTAINER_IMAGE" - echo "✅ Container '$CONTAINER_NAME' started on port $PORT" - echo "" - - # Wait for container to be ready - echo "🕒 Waiting for container to be ready..." - MAX_ATTEMPTS=10 - ATTEMPT=1 - READY=false - - while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do - if curl -s http://localhost:$PORT/api/health | grep -q "healthy"; then - READY=true - break - fi - sleep 1 - ATTEMPT=$((ATTEMPT + 1)) - echo "🕒 Attempt $ATTEMPT/$MAX_ATTEMPTS..." - done - - if [ "$READY" = true ]; then - echo "✅ Container is ready!" - else - echo "❌ Container failed to start properly" - echo "📋 Container logs:" - docker logs dance-lessons-coach-test - echo "" - echo "💡 Check container status with: docker ps -a" - echo "💡 View full logs with: docker logs dance-lessons-coach-test" - continue # Skip endpoint testing - fi - - echo "📋 Testing endpoints..." - - if curl -s http://localhost:$PORT/api/health | grep -q "healthy"; then - echo "✅ Health check passed" - else - echo "❌ Health check failed" - fi - - if curl -s http://localhost:$PORT/api/v1/greet/ | grep -q "Hello"; then - echo "✅ Greet endpoint working" - else - echo "❌ Greet endpoint failed" - fi - - echo "" - echo "📖 Swagger UI available at: http://localhost:$PORT/swagger/" - echo "💡 Press Ctrl+C to stop the container when done" - echo " Or run: docker stop $CONTAINER_NAME && docker rm $CONTAINER_NAME" - fi + else + echo "✅ Port 8080 is available" + PORT=8080 + fi + + read -p "🚀 Do you want to run the container now on port $PORT? (y/n): " -n 1 -r +echo "" + if [[ $REPLY =~ ^[Yy]$ ]]; then + # Get current branch name for container naming + BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD | tr '/' '-') + CONTAINER_NAME="dance-lessons-coach-$BRANCH_NAME" + + echo "🐳 Preparing container '$CONTAINER_NAME' on port $PORT..." + + # Remove existing container if it exists + if docker ps -a --format '{{.Names}}' | grep -q "^$CONTAINER_NAME$"; then + echo "⚠️ Container '$CONTAINER_NAME' already exists - removing it..." + docker stop "$CONTAINER_NAME" > /dev/null 2>&1 || true + docker rm "$CONTAINER_NAME" > /dev/null 2>&1 || true + echo "✅ Old container removed" + fi + + # Also remove the generic test container if it exists + if docker ps -a --format '{{.Names}}' | grep -q "^dance-lessons-coach-test$"; then + echo "⚠️ Generic test container exists - removing it..." + docker stop dance-lessons-coach-test > /dev/null 2>&1 || true + docker rm dance-lessons-coach-test > /dev/null 2>&1 || true + echo "✅ Old generic container removed" + fi + + echo "🐳 Starting container '$CONTAINER_NAME' on port $PORT..." + docker run -d -p $PORT:8080 --name "$CONTAINER_NAME" "$CONTAINER_IMAGE" + echo "✅ Container '$CONTAINER_NAME' started on port $PORT" + echo "" + + # Wait for container to be ready + echo "🕒 Waiting for container to be ready..." + MAX_ATTEMPTS=10 + ATTEMPT=1 + READY=false + + while [ $ATTEMPT -le $MAX_ATTEMPTS ]; do + if curl -s http://localhost:$PORT/api/health | grep -q "healthy"; then + READY=true + break + fi + sleep 1 + ATTEMPT=$((ATTEMPT + 1)) + echo "🕒 Attempt $ATTEMPT/$MAX_ATTEMPTS..." + done + + if [ "$READY" = true ]; then + echo "✅ Container is ready!" + else + echo "❌ Container failed to start properly" + echo "📋 Container logs:" + docker logs dance-lessons-coach-test + echo "" + echo "💡 Check container status with: docker ps -a" + echo "💡 View full logs with: docker logs dance-lessons-coach-test" + continue # Skip endpoint testing + fi + + echo "📋 Testing endpoints..." + + if curl -s http://localhost:$PORT/api/health | grep -q "healthy"; then + echo "✅ Health check passed" + else + echo "❌ Health check failed" + fi + + if curl -s http://localhost:$PORT/api/v1/greet/ | grep -q "Hello"; then + echo "✅ Greet endpoint working" + else + echo "❌ Greet endpoint failed" + fi + + echo "" + echo "📖 Swagger UI available at: http://localhost:$PORT/swagger/" + echo "💡 Press Ctrl+C to stop the container when done" + echo " Or run: docker stop $CONTAINER_NAME && docker rm $CONTAINER_NAME" fi -else - echo "ℹ️ Docker not available - skipping Docker build instructions" fi echo "" @@ -374,9 +352,7 @@ echo " ✅ Code compilation" echo " ✅ Unit tests with coverage" echo " ✅ Binary build" echo " ✅ Version bump simulation" -if [ "$HAS_DOCKER" = true ]; then - echo " ✅ Docker build (development and/or production if chosen)" -fi +echo " ✅ Docker build (development and/or production if chosen)" echo "" echo "🎯 When ready for production:" echo " Push to main branch to trigger full CI/CD pipeline" @@ -385,4 +361,4 @@ echo "" echo "💡 Local testing complete! Your changes are ready for CI/CD." echo "💡 This script now matches the Gitea workflow structure and behavior." # ⚠️ IMPORTANT: Local Dockerfile.prod uses 'latest' tag for testing only -# ✅ CI/CD workflow generates correct Dockerfile.prod with dependency hash +# ✅ CI/CD workflow generates correct Dockerfile.prod with dependency hash \ No newline at end of file