name: CI/CD Pipeline on: push: branches: [ main, develop ] pull_request: branches: [ main ] release: types: [ published ] env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: test: name: Run Tests runs-on: ubuntu-latest strategy: matrix: python-version: [3.9, 3.10, 3.11] steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: Cache Python dependencies uses: actions/cache@v3 with: path: ~/.cache/pip key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} restore-keys: | ${{ runner.os }}-pip- - name: Install dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt pip install pytest pytest-asyncio httpx - name: Lint with flake8 run: | pip install flake8 # Stop the build if there are Python syntax errors or undefined names flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics # Treat all errors as warnings flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test application startup run: | timeout 30 python run.py --host 127.0.0.1 --port 8001 & sleep 10 curl -f http://127.0.0.1:8001/api/stats || exit 1 pkill -f "python run.py" || true - name: Test Docker build run: | docker build -t test-image:latest . security: name: Security Scan runs-on: ubuntu-latest needs: test steps: - name: Checkout code uses: actions/checkout@v4 - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@master with: scan-type: 'fs' scan-ref: '.' format: 'sarif' output: 'trivy-results.sarif' - name: Upload Trivy scan results uses: github/codeql-action/upload-sarif@v2 if: always() with: sarif_file: 'trivy-results.sarif' build: name: Build and Push Docker Image runs-on: ubuntu-latest needs: [test, security] if: github.event_name != 'pull_request' steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - 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 id: meta uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} tags: | type=ref,event=branch type=ref,event=pr type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} type=sha,prefix=sha- - name: Build and push Docker image uses: docker/build-push-action@v5 with: context: . platforms: linux/amd64,linux/arm64 push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max deploy-staging: name: Deploy to Staging runs-on: ubuntu-latest needs: build if: github.ref == 'refs/heads/develop' environment: staging steps: - name: Checkout code uses: actions/checkout@v4 - name: Deploy to staging run: | echo "Deploying to staging environment..." # Add your staging deployment commands here # Example: kubectl, docker-compose, or cloud provider CLI commands deploy-production: name: Deploy to Production runs-on: ubuntu-latest needs: build if: github.ref == 'refs/heads/main' || github.event_name == 'release' environment: production steps: - name: Checkout code uses: actions/checkout@v4 - name: Deploy to production run: | echo "Deploying to production environment..." # Add your production deployment commands here # Example: kubectl, docker-compose, or cloud provider CLI commands notification: name: Send Notifications runs-on: ubuntu-latest needs: [deploy-staging, deploy-production] if: always() && (needs.deploy-staging.result != 'skipped' || needs.deploy-production.result != 'skipped') steps: - name: Notify deployment status run: | if [[ "${{ needs.deploy-staging.result }}" == "success" || "${{ needs.deploy-production.result }}" == "success" ]]; then echo "Deployment successful!" else echo "Deployment failed!" fi