name: Docker Build Validation on: pull_request: branches: - main merge_group: branches: - main workflow_dispatch: permissions: contents: read env: TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} TURBO_TEAM: ${{ vars.TURBO_TEAM }} jobs: validate-docker-build: name: Validate Docker Build runs-on: ubuntu-latest # Add PostgreSQL and Redis service containers services: postgres: image: pgvector/pgvector@sha256:9ae02a756ba16a2d69dd78058e25915e36e189bb36ddf01ceae86390d7ed786a env: POSTGRES_USER: test POSTGRES_PASSWORD: test POSTGRES_DB: formbricks ports: - 5432:5432 # Health check to ensure PostgreSQL is ready before using it options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 redis: image: valkey/valkey@sha256:12ba4f45a7c3e1d0f076acd616cb230834e75a77e8516dde382720af32832d6d ports: - 6379:6379 steps: - name: Harden the runner (Audit all outbound calls) uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout Repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Set up Docker Buildx uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Build Docker Image uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 env: GITHUB_SHA: ${{ github.sha }} with: context: . file: ./apps/web/Dockerfile push: false load: true tags: formbricks-test:${{ env.GITHUB_SHA }} cache-from: type=gha cache-to: type=gha,mode=max secrets: | database_url=${{ secrets.DUMMY_DATABASE_URL }} encryption_key=${{ secrets.DUMMY_ENCRYPTION_KEY }} redis_url=redis://localhost:6379 - name: Verify and Initialize PostgreSQL run: | echo "Verifying PostgreSQL connection..." # Install PostgreSQL client to test connection sudo apt-get update && sudo apt-get install -y postgresql-client # Test connection using psql with timeout and proper error handling echo "Testing PostgreSQL connection with 30 second timeout..." if timeout 30 bash -c 'until PGPASSWORD=test psql -h localhost -U test -d formbricks -c "\dt" >/dev/null 2>&1; do echo "Waiting for PostgreSQL to be ready..." sleep 2 done'; then echo "โœ… PostgreSQL connection successful" PGPASSWORD=test psql -h localhost -U test -d formbricks -c "SELECT version();" # Enable necessary extensions that might be required by migrations echo "Enabling required PostgreSQL extensions..." PGPASSWORD=test psql -h localhost -U test -d formbricks -c "CREATE EXTENSION IF NOT EXISTS vector;" || echo "Vector extension already exists or not available" else echo "โŒ PostgreSQL connection failed after 30 seconds" exit 1 fi # Show network configuration echo "Network configuration:" netstat -tulpn | grep 5432 || echo "No process listening on port 5432" - name: Verify Redis/Valkey Connection run: | echo "Verifying Redis/Valkey connection..." # Install Redis client to test connection sudo apt-get update && sudo apt-get install -y redis-tools # Test connection using redis-cli with timeout and proper error handling echo "Testing Redis connection with 30 second timeout..." if timeout 30 bash -c 'until redis-cli -h localhost -p 6379 ping >/dev/null 2>&1; do echo "Waiting for Redis to be ready..." sleep 2 done'; then echo "โœ… Redis connection successful" redis-cli -h localhost -p 6379 info server | head -5 else echo "โŒ Redis connection failed after 30 seconds" exit 1 fi # Show network configuration for Redis echo "Redis network configuration:" netstat -tulpn | grep 6379 || echo "No process listening on port 6379" - name: Test Docker Image with Health Check shell: bash env: GITHUB_SHA: ${{ github.sha }} DUMMY_ENCRYPTION_KEY: ${{ secrets.DUMMY_ENCRYPTION_KEY }} run: | echo "๐Ÿงช Testing if the Docker image starts correctly..." # Add extra docker run args to support host.docker.internal on Linux DOCKER_RUN_ARGS="--add-host=host.docker.internal:host-gateway" # Start the container with host.docker.internal pointing to the host docker run --name formbricks-test \ $DOCKER_RUN_ARGS \ -p 3000:3000 \ -e DATABASE_URL="postgresql://test:test@host.docker.internal:5432/formbricks" \ -e ENCRYPTION_KEY="$DUMMY_ENCRYPTION_KEY" \ -e REDIS_URL="redis://host.docker.internal:6379" \ -d "formbricks-test:$GITHUB_SHA" # Start health check polling immediately (every 5 seconds for up to 5 minutes) echo "๐Ÿฅ Polling /health endpoint every 5 seconds for up to 5 minutes..." MAX_RETRIES=60 # 60 attempts ร— 5 seconds = 5 minutes RETRY_COUNT=0 HEALTH_CHECK_SUCCESS=false set +e # Disable exit on error to allow for retries while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do RETRY_COUNT=$((RETRY_COUNT + 1)) # Check if container is still running if [ "$(docker inspect -f '{{.State.Running}}' formbricks-test 2>/dev/null)" != "true" ]; then echo "โŒ Container stopped running after $((RETRY_COUNT * 5)) seconds!" echo "๐Ÿ“‹ Container logs:" docker logs formbricks-test exit 1 fi # Show progress and diagnostic info every 12 attempts (1 minute intervals) if [ $((RETRY_COUNT % 12)) -eq 0 ] || [ $RETRY_COUNT -eq 1 ]; then echo "Health check attempt $RETRY_COUNT of $MAX_RETRIES ($(($RETRY_COUNT * 5)) seconds elapsed)..." echo "๐Ÿ“‹ Recent container logs:" docker logs --tail 10 formbricks-test fi # Try health endpoint with shorter timeout for faster polling # Use -f flag to make curl fail on HTTP error status codes (4xx, 5xx) if curl -f -s -m 10 http://localhost:3000/health >/dev/null 2>&1; then echo "โœ… Health check successful after $((RETRY_COUNT * 5)) seconds!" HEALTH_CHECK_SUCCESS=true break fi # Wait 5 seconds before next attempt sleep 5 done # Show full container logs for debugging echo "๐Ÿ“‹ Full container logs:" docker logs formbricks-test # Clean up the container echo "๐Ÿงน Cleaning up..." docker rm -f formbricks-test # Exit with failure if health check did not succeed if [ "$HEALTH_CHECK_SUCCESS" != "true" ]; then echo "โŒ Health check failed after $((MAX_RETRIES * 5)) seconds (5 minutes)" exit 1 fi echo "โœจ Docker validation complete - all checks passed!"