- Add cargo fmt --check to enforce code formatting
- Add pull_request trigger for PR validation
- Split workflow into parallel jobs (format, clippy, build, docker)
- Integrate Docker Buildx with DinD service
- Add BuildKit caching for faster builds
- Add local test script (scripts/test-ci-locally.sh)
- Add comprehensive documentation
All local CI checks pass ✅
8.9 KiB
CI/CD Improvements - Format Check, PR Validation, and Docker Buildx
Date: 2026-03-17
Status: ✅ Implemented
Author: AI Agent
Summary
Enhanced the Forgejo CI/CD pipeline with three major improvements:
- Format checking - Enforces consistent code style
- PR validation - Automated checks for pull requests
- Docker Buildx - Multi-platform Docker builds with caching
Changes Made
1. Pull Request Validation
Before:
on:
push:
branches: [main]
After:
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
Benefits:
- ✅ Validates code before merging to main
- ✅ Catches issues early in development cycle
- ✅ Supports
developbranch workflow - ✅ Provides automated feedback on PRs
2. Code Format Checking
New Job: format
format:
name: Check Code Formatting
runs-on: docker
container:
image: rust:1.83-slim
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Check formatting
working-directory: ./backend
run: cargo fmt --all -- --check
Behavior:
- Runs
rustfmtin check mode - Fails if code is not properly formatted
- Runs in parallel with Clippy (faster feedback)
- Uses strict formatting rules from
backend/rustfmt.toml
How to Fix Format Issues:
cd backend
cargo fmt --all # Auto-format all code
git commit -am "style: auto-format code with rustfmt"
3. Job Parallelization
Before: Single monolithic job (sequential)
After: Multiple parallel jobs
┌─────────────┐ ┌─────────────┐
│ Format │ │ Clippy │ ← Run in parallel
└──────┬──────┘ └──────┬──────┘
│ │
└────────┬───────┘
▼
┌─────────────┐
│ Build │ ← Depends on format + clippy
└──────┬──────┘
▼
┌─────────────┐
│ Docker Build│ ← Depends on build
└─────────────┘
Benefits:
- ⚡ Faster feedback (format + clippy run simultaneously)
- 🎯 Clearer failure messages (separate jobs)
- 📊 Better resource utilization
- 🔄 Can run format/clippy without building
4. Docker Buildx Integration
New Job: docker-build
Configuration:
- Uses
docker:clicontainer - DinD service for isolated builds
- Buildx for advanced features
- Local caching for faster builds
Features:
services:
docker:
image: docker:dind
command: ["dockerd", "--host=tcp://0.0.0.0:2375", "--tls=false"]
options: >-
--privileged
-e DOCKER_TLS_CERTDIR=
Buildx Commands:
# Create builder with host networking
docker buildx create --use --name builder --driver docker --driver-opt network=host
# Build with caching
docker buildx build \
--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 \
.
Benefits:
- 🏗️ Multi-platform build support (can build for ARM, etc.)
- 💾 Smart caching (faster subsequent builds)
- 🔒 Isolated builds (DinD)
- 🐳 Production-ready images
- 📦 Versioned images (Git SHA tags)
Workflow Structure
Job Dependencies
format: # No dependencies
clippy: # No dependencies
build: # needs: [format, clippy]
docker: # needs: [build]
summary: # needs: [format, clippy, build, docker]
Execution Flow
-
Parallel Stage (Fast feedback)
- Format check (~10s)
- Clippy lint (~30s)
-
Build Stage (If quality checks pass)
- Build release binary (~60s)
-
Docker Stage (If build succeeds)
- Build Docker image with Buildx (~40s)
-
Summary Stage (Always runs)
- Report overall status
- Fail if any job failed
CI Environment
Runner Details
- Location: Solaria server
- Type: Docker-based runner
- Label:
docker - Docker Version: 29.0.0
- Buildx Version: v0.29.1
Docker-in-Docker Setup
- Service:
docker:dind - Socket: TCP endpoint (not Unix socket)
- Privileged Mode: Enabled
- TLS: Disabled for local communication
Why TCP Socket?
Previous attempts used Unix socket mounting:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
This approach has issues:
- ⚠️ Security concerns (host Docker access)
- ⚠️ Permission issues
- ⚠️ Not portable
Current approach uses TCP:
services:
docker:
image: docker:dind
command: ["dockerd", "--host=tcp://0.0.0.0:2375", "--tls=false"]
Benefits:
- ✅ Isolated Docker daemon
- ✅ No permission issues
- ✅ Better security
- ✅ Portable across runners
Artifacts
Binary Upload
- name: Upload binary artifact
uses: actions/upload-artifact@v4
with:
name: normogen-backend
path: backend/target/release/normogen-backend
Docker Images
Built images are tagged:
normogen-backend:latest- Latest buildnormogen-backend:{sha}- Versioned by commit SHA
Note: Pushing to registry is commented out (requires secrets)
Usage
For Developers
Before Pushing:
# Check formatting locally
cd backend
cargo fmt --all -- --check
# Run clippy locally
cargo clippy --all-targets --all-features -- -D warnings
# Build to ensure it compiles
cargo build --release
If Format Check Fails:
# Auto-fix formatting
cargo fmt --all
# Commit the changes
git add .
git commit -m "style: auto-format code"
git push
Triggering CI:
- Push to
mainordevelop - Open/Update a PR to
mainordevelop
For PR Review
CI will automatically check:
- ✅ Code is properly formatted
- ✅ No Clippy warnings
- ✅ Builds successfully
- ✅ Docker image builds
All checks must pass before merging!
Troubleshooting
Format Check Fails
Error: code is not properly formatted
Solution:
cd backend
cargo fmt --all
git commit -am "style: fix formatting"
Clippy Fails
Error: warning: unused variable etc.
Solution:
- Fix warnings locally
- Run
cargo clippy --all-targets --all-features -- -D warnings - Commit fixes
Docker Build Fails
Error: Cannot connect to Docker daemon
Check:
- DinD service is running
- TCP endpoint is accessible
- No firewall issues
Solution: The workflow uses privileged mode and proper networking - if it fails, check runner configuration.
Build Cache Issues
Error: Cache growing too large
Solution: The workflow uses a cache rotation strategy:
# Build with new cache
--cache-to type=local,dest=/tmp/.buildx-cache-new,mode=max
# Move new cache (removes old)
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
Future Enhancements
Ready to Enable (Commented Out)
1. Docker Registry Push
- name: Push Docker image
if: github.ref == 'refs/heads/main'
run: |
docker push normogen-backend:${{ github.sha }}
docker push normogen-backend:latest
Requires:
- Set up container registry
- Configure secrets:
REGISTRY_USER,REGISTRY_PASSWORD
2. Integration Tests
test:
services:
mongodb:
image: mongo:7
steps:
- name: Run tests
run: cargo test --verbose
3. Security Scanning
security:
steps:
- name: Run cargo audit
run: cargo audit
Planned Enhancements
- Add MongoDB for integration tests
- Add code coverage reporting (tarpaulin)
- Add security audit (cargo-audit)
- Add deployment automation to Solaria
- Add staging environment deployment
- Add performance benchmarking
Monitoring
View Workflow Results
- Go to: http://gitea.soliverez.com.ar/alvaro/normogen/actions
- Click on the latest workflow run
- View individual job results:
- Format check
- Clippy lint
- Build
- Docker build
- Summary
Job Status Badges
Add to README.md (when Forgejo supports badges):

Related Documentation
Summary
✅ Format checking - Ensures consistent code style
✅ PR validation - Automated checks for pull requests
✅ Docker Buildx - Advanced Docker builds with caching
✅ Parallel jobs - Faster feedback
✅ Better diagnostics - Separate jobs for each concern
✅ Production-ready - Builds and tests Docker images
Status: Ready to deploy! 🚀