name: Build, Test, and Deploy Trading Platform on: push: branches: [main] paths: - 'trading-platform/**' pull_request: branches: [main] paths: - 'trading-platform/**' workflow_dispatch: inputs: environment: description: 'Deploy environment' type: choice options: - staging - production default: staging env: REGISTRY: ghcr.io IMAGE_PREFIX: ${{ github.repository_owner }}/trading-platform permissions: contents: read packages: write jobs: # ── Test All Services ────────────────────────────────────────────────── test-python-services: name: Test Python Services runs-on: ubuntu-latest strategy: matrix: service: [execute-service, data-service, news-service] defaults: run: working-directory: trading-platform/${{ matrix.service }} steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: '3.12' cache: 'pip' - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e ".[dev]" working-directory: trading-platform/${{ matrix.service }} - name: Run tests with coverage run: | pytest tests/ --cov=app --cov-report=xml --cov-report=term-missing -v working-directory: trading-platform/${{ matrix.service }} - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 with: file: trading-platform/${{ matrix.service }}/coverage.xml flags: ${{ matrix.service }} test-dashboard: name: Test Dashboard (Next.js) runs-on: ubuntu-latest defaults: run: working-directory: trading-platform/dashboard steps: - uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' cache-dependency-path: trading-platform/dashboard/package-lock.json - name: Install dependencies run: npm ci working-directory: trading-platform/dashboard - name: Run linting run: npm run lint working-directory: trading-platform/dashboard - name: Build application run: npm run build working-directory: trading-platform/dashboard test-api-gateway: name: Lint API Gateway Configs runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Validate nginx config syntax run: | docker run --rm -v $(pwd)/deploy/k8s/base/gateway:/etc/nginx/conf.d:ro nginx:1.25-alpine nginx -t # ── Build and Push Container Images ───────────────────────────────────── build-and-push: needs: [test-python-services, test-dashboard, test-api-gateway] name: Build & Push Images runs-on: ubuntu-latest if: github.event_name == 'push' || github.event_name == 'workflow_dispatch' strategy: matrix: service: [execute-service, data-service, news-service, api-gateway, dashboard] steps: - uses: actions/checkout@v4 - name: Log in to Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Extract metadata (tags, labels) id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_PREFIX }}/${{ matrix.service }} tags: | type=sha,prefix= type=ref,event=branch type=semver,pattern={{version}} type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }} - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . file: trading-platform/deploy/dockerfiles/${{ matrix.service }}.Dockerfile push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max # ── Deploy to Kubernetes (Helm) ──────────────────────────────────────── deploy-staging: needs: [build-and-push] name: Deploy to Staging runs-on: ubuntu-latest if: github.event_name == 'push' || (github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'staging') environment: staging steps: - uses: actions/checkout@v4 - name: Set up kubectl uses: azure/setup-kubectl@v3 with: version: 'v1.29.0' - name: Configure kubeconfig run: | echo "${{ secrets.STAGING_KUBECONFIG }}" | base64 -d > $HOME/.kube/config env: STAGING_KUBECONFIG: ${{ secrets.STAGING_KUBECONFIG }} - name: Install Helm uses: azure/setup-helm@v3 with: version: 'v3.14.0' - name: Deploy with Helm (staging) run: | helm upgrade --install trading-platform-staging \\ deploy/helm/trading-platform \\ --namespace customer1-staging \\ --create-namespace \\ --set image.tag=${{ github.sha }} \\ --wait --timeout 10m - name: Verify deployment run: | kubectl rollout status deployment/execute-service -n customer1-staging --timeout=5m kubectl rollout status deployment/data-service -n customer1-staging --timeout=5m kubectl rollout status deployment/news-service -n customer1-staging --timeout=5m kubectl rollout status deployment/api-gateway -n customer1-staging --timeout=5m kubectl rollout status deployment/dashboard -n customer1-staging --timeout=5m deploy-production: needs: [deploy-staging] name: Deploy to Production runs-on: ubuntu-latest if: github.event_name == 'workflow_dispatch' && github.event.inputs.environment == 'production' environment: production steps: - uses: actions/checkout@v4 - name: Set up kubectl uses: azure/setup-kubectl@v3 with: version: 'v1.29.0' - name: Configure kubeconfig run: | echo "${{ secrets.PRODUCTION_KUBECONFIG }}" | base64 -d > $HOME/.kube/config - name: Install Helm uses: azure/setup-helm@v3 with: version: 'v3.14.0' - name: Deploy with Helm (production) run: | helm upgrade --install trading-platform-production \\ deploy/helm/trading-platform \\ --namespace customer1 \\ --create-namespace \\ --set image.tag=${{ github.sha }} \\ --values deploy/helm/trading-platform/values-production.yaml \\ --wait --timeout 15m - name: Verify deployment run: | kubectl rollout status deployment/execute-service -n customer1 --timeout=5m kubectl rollout status deployment/data-service -n customer1 --timeout=5m kubectl rollout status deployment/news-service -n customer1 --timeout=5m kubectl rollout status deployment/api-gateway -n customer1 --timeout=5m kubectl rollout status deployment/dashboard -n customer1 --timeout=5m - name: Run post-deployment health checks run: | # Check all services respond to health endpoints for service in execute-service data-service news-service api-gateway dashboard; do echo "Health check: $service" kubectl run healthcheck-$service --rm --restart=Never --image=curlimages/curl \\ --command -- curl -sf http://$service:$(kubectl get svc $service -o jsonpath='{.spec.ports[0].port}')/health || exit 1 done