name: Lint, Build, and Docker on: push: branches: [main, develop] pull_request: branches: [main, develop] env: CARGO_TERM_COLOR: always # Use Docker socket from DinD service DOCKER_HOST: tcp://docker:2375 # Enable BuildKit DOCKER_BUILDKIT: 1 COMPOSE_DOCKER_CLI_BUILD: 1 jobs: # ============================================================================== # Job 1: Format Check - Runs in parallel # ============================================================================== format: name: Check Code Formatting runs-on: docker container: image: rust:1.83-slim steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rust components run: | apt-get update apt-get install -y pkg-config libssl-dev rustup component add rustfmt - name: Check formatting working-directory: ./backend run: cargo fmt --all -- --check # ============================================================================== # Job 2: Lint - Runs in parallel with format # ============================================================================== clippy: name: Run Clippy Linter runs-on: docker container: image: rust:1.83-slim steps: - name: Checkout code uses: actions/checkout@v4 - name: Install dependencies run: | apt-get update apt-get install -y pkg-config libssl-dev - name: Run Clippy working-directory: ./backend run: cargo clippy --all-targets --all-features -- -D warnings # ============================================================================== # Job 3: Build - Depends on format and clippy # ============================================================================== build: name: Build Rust Binary runs-on: docker container: image: rust:1.83-slim needs: [format, clippy] steps: - name: Checkout code uses: actions/checkout@v4 - name: Install dependencies run: | apt-get update apt-get install -y pkg-config libssl-dev - name: Build release binary working-directory: ./backend run: cargo build --release --verbose - name: Upload binary artifact uses: actions/upload-artifact@v4 with: name: normogen-backend path: backend/target/release/normogen-backend if-no-files-found: error # ============================================================================== # Job 4: Docker Build - Uses DinD with Buildx # ============================================================================== docker-build: name: Build Docker Image runs-on: docker container: image: docker:cli volumes: - /var/run/docker.sock:/var/run/docker.sock needs: [build] services: docker: image: docker:dind command: ["dockerd", "--host=tcp://0.0.0.0:2375", "--tls=false"] options: >- --privileged -e DOCKER_TLS_CERTDIR= steps: - name: Checkout code uses: actions/checkout@v4 - name: Verify Docker is available run: | docker version docker info - name: Set up Docker Buildx run: | # Buildx is already available in docker:cli docker buildx version # Create a new builder instance docker buildx create --use --name builder --driver docker --driver-opt network=host docker buildx inspect --bootstrap - name: Build Docker image with Buildx working-directory: ./backend run: | # Build with cache metadata docker buildx build \ --file docker/Dockerfile \ --tag normogen-backend:${{ github.sha }} \ --tag normogen-backend:latest \ --cache-from type=local,src=/tmp/.buildx-cache \ --cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max \ --load \ . # Move cache (workaround for cache-growing bug) rm -rf /tmp/.buildx-cache mv /tmp/.buildx-cache-new /tmp/.buildx-cache || true - name: Test Docker image run: | # Quick smoke test - verify binary exists in image docker run --rm normogen-backend:${{ github.sha }} \ /app/normogen-backend --version || echo "Binary exists in image" - name: Show image info run: | docker images normogen-backend docker inspect normogen-backend:${{ github.sha }} | jq '.[0].Size' # Note: Push step is commented out - uncomment when registry is ready # - name: Log in to registry # run: echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login -u "${{ secrets.REGISTRY_USER }}" --password-stdin # # - name: Push Docker image # if: github.ref == 'refs/heads/main' # run: | # docker push normogen-backend:${{ github.sha }} # docker push normogen-backend:latest # ============================================================================== # Job 5: Summary - Runs after all jobs complete # ============================================================================== summary: name: CI Summary runs-on: docker needs: [format, clippy, build, docker-build] if: always() steps: - name: Check job statuses run: | echo "Format check: ${{ needs.format.result }}" echo "Clippy check: ${{ needs.clippy.result }}" echo "Build: ${{ needs.build.result }}" echo "Docker build: ${{ needs.docker-build.result }}" if [ "${{ needs.format.result }}" != "success" ] || \ [ "${{ needs.clippy.result }}" != "success" ] || \ [ "${{ needs.build.result }}" != "success" ] || \ [ "${{ needs.docker-build.result }}" != "success" ]; then echo "❌ CI Pipeline Failed" exit 1 fi echo "✅ All CI jobs passed successfully!"