name: CI/CD Pipeline on: push: branches: [ main, develop ] pull_request: branches: [ main ] env: REGISTRY: ${{ secrets.CI_HOST }}:5000 IMAGE_NAME: ${{ secrets.APP_NAME || 'sharenet' }} jobs: test-backend: name: Test Backend runs-on: ubuntu-latest services: postgres: image: postgres:15 env: POSTGRES_PASSWORD: postgres POSTGRES_DB: ${{ secrets.APP_NAME || 'sharenet' }}_test options: >- --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 ports: - 5432:5432 steps: - name: Checkout code uses: actions/checkout@v4 - name: Install Rust toolchain uses: actions-rs/toolchain@v1 with: toolchain: stable override: true - name: Install SQLx CLI run: cargo install sqlx-cli --no-default-features --features postgres - name: Cache Rust dependencies uses: actions/cache@v3 with: path: | ~/.cargo/registry ~/.cargo/git backend/target key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} restore-keys: | ${{ runner.os }}-cargo- - name: Make scripts executable run: chmod +x scripts/*.sh - name: Validate migration files env: DATABASE_URL: postgres://postgres:postgres@localhost:5432/${{ secrets.APP_NAME || 'sharenet' }}_test run: | # Wait for PostgreSQL to be ready echo "Waiting for PostgreSQL to be ready..." timeout 60 bash -c 'until pg_isready -h localhost -p 5432 -U postgres; do sleep 1; done' # Create test database if it doesn't exist sqlx database create --database-url "$DATABASE_URL" || true # Run initial migrations to set up the database sqlx migrate run --database-url "$DATABASE_URL" || true # Validate migration files ./scripts/validate_migrations.sh --verbose - name: Run backend tests working-directory: ./backend env: DATABASE_URL: postgres://postgres:postgres@localhost:5432/${{ secrets.APP_NAME || 'sharenet' }}_test run: | cargo test --all cargo clippy --all -- -D warnings cargo fmt --all -- --check test-frontend: name: Test Frontend runs-on: ubuntu-latest steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' cache-dependency-path: frontend/package-lock.json - name: Install frontend dependencies working-directory: ./frontend run: npm ci - name: Run frontend tests working-directory: ./frontend run: | npm run lint npm run type-check npm run build build-and-push: name: Build and Push Docker Images needs: [test-backend, test-frontend] runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Configure Docker for local registry run: | echo '{"insecure-registries": ["${{ secrets.CI_HOST }}:5000"]}' | sudo tee /etc/docker/daemon.json sudo systemctl restart docker - name: Build and push backend image uses: docker/build-push-action@v5 with: context: ./backend file: ./backend/Dockerfile push: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/backend:${{ github.sha }} cache-from: type=gha cache-to: type=gha,mode=max - name: Build and push frontend image uses: docker/build-push-action@v5 with: context: ./frontend file: ./frontend/Dockerfile push: true tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/frontend:${{ github.sha }} cache-from: type=gha cache-to: type=gha,mode=max deploy: name: Deploy to Production needs: build-and-push runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - name: Checkout code uses: actions/checkout@v4 - name: Install SQLx CLI run: cargo install sqlx-cli --no-default-features --features postgres - name: Make scripts executable run: chmod +x scripts/*.sh - name: Deploy to production server uses: appleboy/ssh-action@v1.0.3 with: host: ${{ secrets.PROD_HOST }} username: ${{ secrets.PROD_USER }} key: ${{ secrets.PROD_SSH_KEY }} script: | cd /opt/${{ secrets.APP_NAME || 'sharenet' }} # Pull latest code from repository (includes scripts and docker-compose.yml) git pull origin main # Create environment file for this deployment echo "IMAGE_TAG=${{ github.sha }}" > .env echo "REGISTRY=${{ secrets.CI_HOST }}:5000" >> .env echo "IMAGE_NAME=${{ secrets.APP_NAME || 'sharenet' }}" >> .env echo "POSTGRES_PASSWORD=${{ secrets.POSTGRES_PASSWORD || 'your_secure_password_here' }}" >> .env echo "POSTGRES_USER=${{ secrets.POSTGRES_USER || 'sharenet' }}" >> .env echo "POSTGRES_DB=${{ secrets.POSTGRES_DB || 'sharenet' }}" >> .env echo "DATABASE_URL=postgresql://${{ secrets.POSTGRES_USER || 'sharenet' }}:${{ secrets.POSTGRES_PASSWORD || 'your_secure_password_here' }}@postgres:5432/${{ secrets.POSTGRES_DB || 'sharenet' }}" >> .env echo "NODE_ENV=production" >> .env echo "RUST_LOG=info" >> .env # Make scripts executable chmod +x scripts/*.sh # Validate migrations before deployment echo "Validating migration files before deployment..." ./scripts/validate_migrations.sh --verbose || { echo "ERROR: Migration validation failed. Deployment aborted." exit 1 } # Run deployment using the new deployment script ./scripts/deploy.sh deploy