Files
dance-lessons-coach/scripts/test-local-ci-cd.sh
Gabriel Radureau c1e628f339 📝 docs: update comprehensive documentation and project infrastructure
Documentation Updates:
- Enhanced AGENTS.md with user authentication details
- Updated README.md with authentication API documentation
- Added CONTRIBUTING.md guidelines for BDD testing
- Version management guide improvements
- Local CI/CD testing documentation

Project Infrastructure:
- Updated .gitignore for new file patterns
- Enhanced git hooks documentation
- YAML linting configuration
- Script improvements and organization
- Configuration management updates

API Enhancements:
- Greet service integration with authentication
- Server middleware for JWT validation
- Telemetry improvements
- Version management utilities

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
2026-04-09 00:26:15 +02:00

386 lines
13 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Local CI/CD Testing Script
# Simulates the CI/CD pipeline but builds Docker image locally
# Use this for local development and testing without Gitea
set -eu
echo "🚀 Local CI/CD Testing"
echo "======================"
echo ""
# 1. Setup
echo "1. Setting up environment..."
if ! command -v go >/dev/null 2>&1; then
echo "❌ Go not found. Please install Go 1.26.1+"
exit 1
fi
# Assume Docker is available (required for this workflow)
if ! command -v docker >/dev/null 2>&1; then
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"
echo ""
# 2. Calculate dependency hash (match CI workflow)
echo "2. Calculating dependency hash..."
# Use shasum on macOS, sha256sum on Linux
if command -v sha256sum >/dev/null 2>&1; then
export DEPS_HASH=$(sha256sum go.mod go.sum | sha256sum | cut -d' ' -f1 | head -c 12)
else
export DEPS_HASH=$(shasum -a 256 go.mod go.sum | shasum -a 256 | cut -d' ' -f1 | head -c 12)
fi
echo "Dependency hash: $DEPS_HASH"
echo "✅ Dependency hash calculated"
echo ""
# 3. Check for Docker cache
echo "3. Checking for Docker build cache..."
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
echo ""
# 4. Start PostgreSQL with Docker Compose
echo "4. Starting PostgreSQL..."
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
export DLC_DATABASE_HOST="localhost" # PostgreSQL port is mapped to host
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. Install dependencies
if [ "$USE_DOCKER_CACHE" = true ]; then
echo "5. Checking dependencies..."
echo "✅ Using pre-installed dependencies from Docker cache"
else
echo "5. Installing dependencies..."
go mod tidy
fi
echo "✅ Dependencies ready"
echo ""
# 6. Generate Swagger Docs
if [ "$USE_DOCKER_CACHE" = true ]; then
echo "6. Generating Swagger documentation..."
echo "Running in Docker container..."
docker run --rm \
--network dance-lessons-coach-network \
-v "$(pwd):/workspace" \
-w /workspace/pkg/server \
"$IMAGE_NAME" \
sh -c "go generate"
else
echo "6. Generating Swagger documentation..."
echo "Running natively..."
cd pkg/server && go generate
cd ../..
fi
echo "✅ Swagger documentation generated"
echo ""
# 7. Build and test
if [ "$USE_DOCKER_CACHE" = true ]; then
echo "7. Building and testing..."
echo "Running in Docker container..."
docker run --rm \
--network dance-lessons-coach-network \
-v "$(pwd):/workspace" \
-w /workspace \
"$IMAGE_NAME" \
sh -c "go build ./..."
else
echo "7. Building and testing..."
echo "Running natively..."
go build ./...
fi
echo "✅ Code compiled successfully"
if [ "$USE_DOCKER_CACHE" = true ]; then
echo "Running in Docker container with PostgreSQL..."
docker run --rm \
--network dance-lessons-coach-network \
-v "$(pwd):/workspace" \
-w /workspace \
-e DLC_DATABASE_HOST=dance-lessons-coach-postgres \
-e DLC_DATABASE_PORT=5432 \
-e DLC_DATABASE_USER=postgres \
-e DLC_DATABASE_PASSWORD=postgres \
-e DLC_DATABASE_NAME=dance_lessons_coach_bdd_test \
-e DLC_DATABASE_SSL_MODE=disable \
"$IMAGE_NAME" \
sh -c "go test ./... -coverprofile=coverage.out -v && go tool cover -func=coverage.out > coverage.txt"
else
echo "Running natively with Docker Compose PostgreSQL..."
go test ./... -coverprofile=coverage.out -v
go tool cover -func=coverage.out > coverage.txt
fi
echo "✅ Tests passed"
echo ""
# 8. Build binaries
if [ "$USE_DOCKER_CACHE" = true ]; then
echo "8. Building binaries..."
echo "Running in Docker container..."
docker run --rm \
--network dance-lessons-coach-network \
-v "$(pwd):/workspace" \
-w /workspace \
"$IMAGE_NAME" \
sh -c "./scripts/build.sh"
else
echo "8. Building binaries..."
echo "Running natively..."
./scripts/build.sh
fi
echo "✅ Binaries built"
ls -la bin/
echo ""
# 9. Version bump simulation
echo "9. Version bump simulation..."
LAST_COMMIT=$(git log -1 --pretty=%B | head -1)
echo "Last commit: $LAST_COMMIT"
if echo "$LAST_COMMIT" | grep -q "^feat:"; then
echo "🎯 Feature commit detected - would bump MINOR version"
echo "Run: ./scripts/version-bump.sh minor"
elif echo "$LAST_COMMIT" | grep -q "^fix:"; then
echo "🐛 Fix commit detected - would bump PATCH version"
echo "Run: ./scripts/version-bump.sh patch"
elif echo "$LAST_COMMIT" | grep -q "BREAKING CHANGE"; then
echo "💥 Breaking change detected - would bump MAJOR version"
echo "Run: ./scripts/version-bump.sh major"
else
echo "⏭️ No automatic version bump needed"
fi
# Show current version
source VERSION
CURRENT_VERSION="$MAJOR.$MINOR.$PATCH${PRERELEASE:+-$PRERELEASE}"
echo "📊 Current version: $CURRENT_VERSION"
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 <container_id> && docker rm <container_id>"
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 ""
# 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"
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
fi
echo ""
echo "✅ LOCAL CI/CD TEST COMPLETE"
echo "==========================="
echo ""
echo "📋 What was tested:"
echo " ✅ Dependency hash calculation (matching CI workflow)"
echo " ✅ Docker cache detection and usage"
echo " ✅ PostgreSQL service with Docker Compose"
echo " ✅ Go dependencies installation"
echo " ✅ Swagger documentation generation"
echo " ✅ Code compilation"
echo " ✅ Unit tests with coverage"
echo " ✅ Binary build"
echo " ✅ Version bump simulation"
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"
echo " Docker image will be built and pushed to Gitea Container Registry"
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