Make backend compatible with main branch SQLite implementation and fi… #3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # IntelliWeather CI/CD Pipeline | ||
|
Check failure on line 1 in .github/workflows/ci-cd.yml
|
||
| # Runs tests, builds Docker image, and optionally deploys to Kubernetes | ||
| name: CI/CD Pipeline | ||
| on: | ||
| push: | ||
| branches: [main, develop] | ||
| tags: ['v*'] | ||
| pull_request: | ||
| branches: [main] | ||
| env: | ||
| REGISTRY: ghcr.io | ||
| IMAGE_NAME: ${{ github.repository }} | ||
| jobs: | ||
| # ==================== LINT & TEST ==================== | ||
| test: | ||
| name: Test | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| steps: | ||
| - name: Checkout code | ||
| 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 -r requirements.txt | ||
| pip install pytest pytest-cov pytest-asyncio flake8 black mypy | ||
| - name: Lint with flake8 | ||
| run: | | ||
| # Stop the build if there are Python syntax errors or undefined names | ||
| flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics | ||
| # Exit-zero treats all errors as warnings | ||
| flake8 . --count --exit-zero --max-complexity=10 --max-line-length=120 --statistics | ||
| continue-on-error: true | ||
| - name: Check formatting with black | ||
| run: black --check --diff . || true | ||
| continue-on-error: true | ||
| - name: Type check with mypy | ||
| run: mypy --ignore-missing-imports . || true | ||
| continue-on-error: true | ||
| - name: Run tests | ||
| run: | | ||
| pytest tests/ -v --cov=. --cov-report=xml --cov-report=term-missing | ||
| env: | ||
| DEBUG: "true" | ||
| - name: Upload coverage reports | ||
| uses: codecov/codecov-action@v3 | ||
| with: | ||
| files: ./coverage.xml | ||
| fail_ci_if_error: false | ||
| # ==================== BUILD DOCKER IMAGE ==================== | ||
| build: | ||
| name: Build | ||
| runs-on: ubuntu-latest | ||
| needs: test | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| 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 | ||
| if: github.event_name != 'pull_request' | ||
| 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= | ||
| - name: Build and push Docker image | ||
| uses: docker/build-push-action@v5 | ||
| with: | ||
| context: . | ||
| push: ${{ github.event_name != 'pull_request' }} | ||
| tags: ${{ steps.meta.outputs.tags }} | ||
| labels: ${{ steps.meta.outputs.labels }} | ||
| cache-from: type=gha | ||
| cache-to: type=gha,mode=max | ||
| platforms: linux/amd64,linux/arm64 | ||
| # ==================== SECURITY SCAN ==================== | ||
| security: | ||
| name: Security Scan | ||
| runs-on: ubuntu-latest | ||
| needs: build | ||
| if: github.event_name != 'pull_request' | ||
| permissions: | ||
| contents: read | ||
| security-events: write | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| - name: Run Trivy vulnerability scanner | ||
| uses: aquasecurity/trivy-action@master | ||
| with: | ||
| image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} | ||
| format: 'sarif' | ||
| output: 'trivy-results.sarif' | ||
| continue-on-error: true | ||
| - name: Upload Trivy scan results | ||
| uses: github/codeql-action/upload-sarif@v2 | ||
| with: | ||
| sarif_file: 'trivy-results.sarif' | ||
| continue-on-error: true | ||
| # ==================== DEPLOY TO STAGING ==================== | ||
| deploy-staging: | ||
| name: Deploy to Staging | ||
| runs-on: ubuntu-latest | ||
| needs: [build, security] | ||
| permissions: | ||
| contents: read | ||
| if: github.ref == 'refs/heads/develop' | ||
| environment: staging | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| - name: Set up kubectl | ||
| uses: azure/setup-kubectl@v3 | ||
| - name: Configure kubectl | ||
| run: | | ||
| mkdir -p ~/.kube | ||
| echo "${{ secrets.KUBE_CONFIG_STAGING }}" | base64 -d > ~/.kube/config | ||
| if: ${{ secrets.KUBE_CONFIG_STAGING != '' }} | ||
| - name: Deploy to staging | ||
| run: | | ||
| if [ -f ~/.kube/config ]; then | ||
| kubectl set image deployment/intelliweather \ | ||
| intelliweather=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} \ | ||
| --namespace=staging || echo "Kubectl deployment skipped (no cluster configured)" | ||
| else | ||
| echo "Staging deployment skipped (no KUBE_CONFIG_STAGING secret)" | ||
| fi | ||
| # ==================== DEPLOY TO PRODUCTION ==================== | ||
| deploy-production: | ||
| name: Deploy to Production | ||
| runs-on: ubuntu-latest | ||
| needs: [build, security] | ||
| if: startsWith(github.ref, 'refs/tags/v') | ||
| environment: production | ||
| permissions: | ||
| contents: read | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| - name: Set up kubectl | ||
| uses: azure/setup-kubectl@v3 | ||
| - name: Configure kubectl | ||
| run: | | ||
| mkdir -p ~/.kube | ||
| echo "${{ secrets.KUBE_CONFIG_PRODUCTION }}" | base64 -d > ~/.kube/config | ||
| if: ${{ secrets.KUBE_CONFIG_PRODUCTION != '' }} | ||
| - name: Deploy to production | ||
| run: | | ||
| if [ -f ~/.kube/config ]; then | ||
| # Extract version from tag | ||
| VERSION=${GITHUB_REF#refs/tags/} | ||
| # Deploy using Helm | ||
| helm upgrade --install intelliweather ./helm/intelliweather \ | ||
| --namespace=production \ | ||
| --set image.tag=$VERSION \ | ||
| --wait --timeout=5m || echo "Helm deployment skipped" | ||
| else | ||
| echo "Production deployment skipped (no KUBE_CONFIG_PRODUCTION secret)" | ||
| fi | ||
| # ==================== NOTIFY ==================== | ||
| notify: | ||
| name: Notify | ||
| runs-on: ubuntu-latest | ||
| needs: [test, build] | ||
| if: always() | ||
| permissions: {} | ||
| steps: | ||
| - name: Notify on success | ||
| if: needs.test.result == 'success' && needs.build.result == 'success' | ||
| run: | | ||
| echo "✅ Pipeline succeeded!" | ||
| echo "Tests: ${{ needs.test.result }}" | ||
| echo "Build: ${{ needs.build.result }}" | ||
| - name: Notify on failure | ||
| if: needs.test.result == 'failure' || needs.build.result == 'failure' | ||
| run: | | ||
| echo "❌ Pipeline failed!" | ||
| echo "Tests: ${{ needs.test.result }}" | ||
| echo "Build: ${{ needs.build.result }}" | ||