name: CI on: push: branches: [main, develop] pull_request: branches: [main, develop] env: PYTHON_VERSION: '3.11' NODE_VERSION: '20' jobs: # ============================================================================ # Backend Jobs # ============================================================================ backend-lint: name: Backend Lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install ruff run: pip install ruff - name: Run ruff check run: ruff check backend/ backend-unit-tests: name: Backend Unit Tests runs-on: ubuntu-latest needs: backend-lint steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Cache pip uses: actions/cache@v4 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-cov - name: Run unit tests run: | cd backend python -m pytest tests/unit/ -v --cov=app --cov-report=xml -m "not slow" - name: Upload coverage uses: codecov/codecov-action@v4 if: always() with: files: backend/coverage.xml flags: backend-unit fail_ci_if_error: false backend-integration-tests: name: Backend Integration Tests runs-on: ubuntu-latest needs: backend-unit-tests steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Cache pip uses: actions/cache@v4 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-cov - name: Run integration tests run: | cd backend python -m pytest tests/integration/ -v --cov=app --cov-report=xml - name: Upload coverage uses: codecov/codecov-action@v4 if: always() with: files: backend/coverage.xml flags: backend-integration fail_ci_if_error: false # ============================================================================ # Frontend Jobs # ============================================================================ frontend-lint: name: Frontend Lint runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'npm' cache-dependency-path: frontend/package-lock.json - name: Install dependencies working-directory: frontend run: npm ci - name: Run ESLint working-directory: frontend run: npm run lint frontend-type-check: name: Frontend Type Check runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'npm' cache-dependency-path: frontend/package-lock.json - name: Install dependencies working-directory: frontend run: npm ci - name: Run TypeScript check working-directory: frontend run: npx tsc --noEmit frontend-unit-tests: name: Frontend Unit Tests runs-on: ubuntu-latest needs: [frontend-lint, frontend-type-check] steps: - uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'npm' cache-dependency-path: frontend/package-lock.json - name: Install dependencies working-directory: frontend run: npm ci - name: Run tests with coverage working-directory: frontend run: npm run test:coverage - name: Upload coverage uses: codecov/codecov-action@v4 if: always() with: files: frontend/coverage/coverage-final.json flags: frontend-unit fail_ci_if_error: false frontend-build: name: Frontend Build runs-on: ubuntu-latest needs: frontend-unit-tests steps: - uses: actions/checkout@v4 - name: Set up Node.js uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: 'npm' cache-dependency-path: frontend/package-lock.json - name: Install dependencies working-directory: frontend run: npm ci - name: Build working-directory: frontend run: npm run build - name: Upload build artifacts uses: actions/upload-artifact@v4 with: name: frontend-build path: static/ # ============================================================================ # E2E Tests # ============================================================================ e2e-tests: name: E2E Tests runs-on: ubuntu-latest needs: [backend-integration-tests, frontend-build] steps: - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} - name: Install backend dependencies run: | python -m pip install --upgrade pip pip install -r requirements.txt pip install playwright playwright install chromium --with-deps - name: Download frontend build uses: actions/download-artifact@v4 with: name: frontend-build path: static/ - name: Start backend server run: | python -m uvicorn backend.app.main:app --host 0.0.0.0 --port 8000 & sleep 15 env: DEBUG: 'false' - name: Run E2E tests run: | python tests/e2e_comprehensive_test.py || true python tests/e2e_toggle_persistence_test.py - name: Upload test screenshots uses: actions/upload-artifact@v4 if: always() with: name: e2e-screenshots path: /tmp/bambuddy_*.png if-no-files-found: ignore # ============================================================================ # Summary Job # ============================================================================ ci-summary: name: CI Summary runs-on: ubuntu-latest needs: [backend-integration-tests, frontend-build, e2e-tests] if: always() steps: - name: Check results run: | echo "Backend Integration Tests: ${{ needs.backend-integration-tests.result }}" echo "Frontend Build: ${{ needs.frontend-build.result }}" echo "E2E Tests: ${{ needs.e2e-tests.result }}" if [[ "${{ needs.backend-integration-tests.result }}" == "failure" ]] || \ [[ "${{ needs.frontend-build.result }}" == "failure" ]]; then echo "CI failed!" exit 1 fi echo "CI passed!"