diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b031e7b8..16ac0949 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,8 +57,7 @@ jobs: - run: djlint frontend/templates/ --lint # ══════════════════════════════════════════════════════════════════════════ - # Stage 2: Parallel Heavy Lifters (Feedback within ~3-4 mins) - # All 4 of these now run simultaneously after Linting passes. + # Stage 2: Parallel Heavy Lifters (Consolidated for Efficiency) # ══════════════════════════════════════════════════════════════════════════ mypy: @@ -76,63 +75,6 @@ jobs: run: pip install -r requirements-dev.txt - run: mypy app/ - test-quick: - name: Quick Tests - runs-on: ubuntu-latest - needs: [lint] - services: - redis: - image: redis:7 - ports: ["6379:6379"] - options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 - steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - cache: 'pip' - - name: Install Dependencies - run: pip install -r requirements-dev.txt - - name: Run Quick Tests - run: > - pytest tests/ -v --timeout=120 --cov=app --cov-report=xml --cov-report=term - --junitxml=junit.xml -o junit_family=legacy - -m "not e2e and not requires_docker and not requires_external and not slow" - - name: Upload coverage to Codecov - if: always() - uses: codecov/codecov-action@v5 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: ./coverage.xml - - test-integration: - name: Integration Tests - runs-on: ubuntu-latest - needs: [lint] - services: - redis: - image: redis:7 - ports: ["6379:6379"] - rabbitmq: - image: rabbitmq:3-management - ports: ["5672:5672", "15672:15672"] - options: --health-cmd "rabbitmq-diagnostics -q ping" --health-interval 10s --health-timeout 5s --health-retries 5 - steps: - - uses: actions/checkout@v4 - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: "3.11" - cache: 'pip' - - name: Install Dependencies - run: pip install -r requirements-dev.txt - - name: Run Integration Tests - run: > - pytest tests/ -v --timeout=300 - --junitxml=junit-integration.xml -o junit_family=legacy - -m "(requires_docker or requires_external or slow) and not e2e" - dependency-scan: name: Dependency Scan runs-on: ubuntu-latest @@ -147,39 +89,84 @@ jobs: - run: pip install pip-audit>=2.7.0 - run: pip-audit -r requirements.txt --desc on + run-tests: + name: Execute All Tests (Quick + Integration) + runs-on: ubuntu-latest + needs: [lint] + services: + redis: + image: redis:7 + ports: ["6379:6379"] + options: --health-cmd "redis-cli ping" --health-interval 10s --health-timeout 5s --health-retries 5 + rabbitmq: + image: rabbitmq:3-management + ports: ["5672:5672", "15672:15672"] + options: --health-cmd "rabbitmq-diagnostics -q ping" --health-interval 10s --health-timeout 5s --health-retries 5 + steps: + - uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + cache: 'pip' + + - name: Install Dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements-dev.txt + + - name: Run Quick Tests + run: > + pytest tests/ -v --timeout=120 + --cov=app --cov-report=xml:coverage.xml + --junitxml=junit-quick.xml -o junit_family=legacy + -m "not e2e and not requires_docker and not requires_external and not slow" + + - name: Run Integration Tests + if: success() || failure() + run: > + pytest tests/ -v --timeout=300 + --cov=app --cov-append --cov-report=xml:coverage.xml + --junitxml=junit-integration.xml -o junit_family=legacy + -m "(requires_docker or requires_external or slow) and not e2e" + + - name: Upload Unified Coverage to Codecov + if: always() + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: ./coverage.xml + fail_ci_if_error: true + # ══════════════════════════════════════════════════════════════════════════ - # Stage 3: Build & Push (The Quality Gate) + # Stage 3: Build & Push (Quality Gate) # ══════════════════════════════════════════════════════════════════════════ build: name: Build & Push Docker Image runs-on: ubuntu-latest - needs: [test-quick, test-integration, mypy, dependency-scan, html-lint] + needs: [run-tests, mypy, dependency-scan, html-lint] if: github.event_name == 'push' steps: - name: Checkout Code uses: actions/checkout@v4 - - name: Generate Build Metadata run: | chmod +x scripts/generate_build_metadata.sh ./scripts/generate_build_metadata.sh - - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Log in to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Log in to GitHub Container Registry uses: docker/login-action@v3 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata for tags id: meta uses: docker/metadata-action@v5 @@ -192,7 +179,6 @@ jobs: type=sha,prefix={{branch}}- type=semver,pattern={{version}} type=raw,value=latest,enable={{is_default_branch}} - - name: Build and Push Docker Image uses: docker/build-push-action@v6 with: @@ -220,14 +206,12 @@ jobs: SHORT_SHA=$(echo "${{ github.sha }}" | cut -c1-7) echo "tag=main-${SHORT_SHA}" >> "$GITHUB_OUTPUT" echo "image=ghcr.io/${{ github.repository_owner }}/docuelevate:main-${SHORT_SHA}" >> "$GITHUB_OUTPUT" - - name: Checkout k8s-cluster-state uses: actions/checkout@v4 with: repository: christianlouis/k8s-cluster-state token: ${{ secrets.GH_PAT }} path: k8s-cluster-state - - name: Update image tag in preprod manifest uses: mikefarah/yq@v4.44.6 env: @@ -236,7 +220,6 @@ jobs: cmd: | yq -i '(.. | select(tag == "!!str") | select(test("^(ghcr\\.io/christianlouis/docuelevate|christianlouis/docuelevate):"))) = strenv(IMAGE)' \ k8s-cluster-state/apps/docuelevate/preprod/docuelevate-stack.yaml - - name: Commit and push run: | cd k8s-cluster-state