name: Build and Deploy MonacoUSA Portal on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest name: Test Application steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Run linting run: npm run lint || echo "Linting not configured" - name: Run type checking run: npm run typecheck || echo "Type checking not configured" - name: Build application run: npm run build - name: Test health endpoint run: | # Start the application in background npm run preview & APP_PID=$! # Wait for app to start sleep 10 # Test health endpoint curl -f http://localhost:3000/api/health || exit 1 # Clean up kill $APP_PID build: runs-on: ubuntu-latest needs: test name: Build and Push Docker Image steps: - name: Checkout code uses: actions/checkout@v4 - name: Login To Registry uses: docker/login-action@v3 with: registry: ${{ vars.REGISTRY_HOST }} username: ${{ vars.REGISTRY_USERNAME }} password: ${{ secrets.REGISTRY_TOKEN }} - name: Set Up Docker Buildx uses: docker/setup-buildx-action@v3 - name: Build And Push uses: docker/build-push-action@v6 with: platforms: linux/amd64 push: true tags: | ${{ vars.REGISTRY_HOST }}/${{ vars.REGISTRY_USERNAME }}/${{ vars.IMAGE_NAME }}:latest ${{ vars.REGISTRY_HOST }}/${{ vars.REGISTRY_USERNAME }}/${{ vars.IMAGE_NAME }}:${{ github.ref_name }} deploy-staging: runs-on: ubuntu-latest needs: build name: Deploy to Staging if: github.ref == 'refs/heads/develop' environment: staging steps: - name: Deploy to staging server uses: appleboy/ssh-action@v1.0.0 with: host: ${{ secrets.STAGING_HOST }} username: ${{ secrets.STAGING_USER }} key: ${{ secrets.STAGING_SSH_KEY }} port: ${{ secrets.STAGING_PORT || 22 }} script: | # Navigate to application directory cd /opt/monacousa-portal-staging # Pull latest image docker pull ${{ vars.REGISTRY_HOST }}/${{ vars.REGISTRY_USERNAME }}/${{ vars.IMAGE_NAME }}:develop # Update docker-compose with new image sed -i 's|image:.*|image: ${{ vars.REGISTRY_HOST }}/${{ vars.REGISTRY_USERNAME }}/${{ vars.IMAGE_NAME }}:develop|' docker-compose.yml # Deploy with zero downtime docker-compose up -d --no-deps monacousa-portal # Wait for health check sleep 30 # Verify deployment curl -f http://localhost:3000/api/health || exit 1 # Clean up old images docker image prune -f deploy-production: runs-on: ubuntu-latest needs: build name: Deploy to Production if: github.ref == 'refs/heads/main' environment: production steps: - name: Deploy to production server uses: appleboy/ssh-action@v1.0.0 with: host: ${{ secrets.PRODUCTION_HOST }} username: ${{ secrets.PRODUCTION_USER }} key: ${{ secrets.PRODUCTION_SSH_KEY }} port: ${{ secrets.PRODUCTION_PORT || 22 }} script: | # Navigate to application directory cd /opt/monacousa-portal # Pull latest image docker pull ${{ vars.REGISTRY_HOST }}/${{ vars.REGISTRY_USERNAME }}/${{ vars.IMAGE_NAME }}:latest # Create backup of current deployment docker tag monacousa-portal:current monacousa-portal:backup-$(date +%Y%m%d-%H%M%S) || true # Update docker-compose with new image sed -i 's|image:.*|image: ${{ vars.REGISTRY_HOST }}/${{ vars.REGISTRY_USERNAME }}/${{ vars.IMAGE_NAME }}:latest|' docker-compose.yml # Deploy with zero downtime docker-compose up -d --no-deps monacousa-portal # Wait for health check sleep 30 # Verify deployment curl -f https://monacousa.org/api/health || exit 1 # Clean up old images (keep last 3) docker images ${{ vars.REGISTRY_HOST }}/${{ vars.REGISTRY_USERNAME }}/${{ vars.IMAGE_NAME }} --format "table {{.Repository}}:{{.Tag}}\t{{.CreatedAt}}" | tail -n +4 | awk '{print $1}' | xargs -r docker rmi || true notify: runs-on: ubuntu-latest needs: [deploy-staging, deploy-production] name: Notify Deployment if: always() steps: - name: Notify success if: ${{ needs.deploy-staging.result == 'success' || needs.deploy-production.result == 'success' }} run: | echo "Deployment successful!" # Add webhook notification here if needed # curl -X POST ${{ secrets.WEBHOOK_URL }} -d "Deployment successful for ${{ github.ref }}" - name: Notify failure if: ${{ needs.deploy-staging.result == 'failure' || needs.deploy-production.result == 'failure' }} run: | echo "Deployment failed!" # Add webhook notification here if needed # curl -X POST ${{ secrets.WEBHOOK_URL }} -d "Deployment failed for ${{ github.ref }}"