name: CI on: push: branches: [main] pull_request: branches: [main] env: PYTHON_VERSION: '3.11' NODE_VERSION: '20' # Cancel in-progress runs for the same branch concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: # ============================================================================ # Backend Checks # ============================================================================ 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/ - name: Run ruff format check run: ruff format --check backend/ backend-tests: name: Backend 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 pytest-asyncio pytest-cov - name: Run tests run: | cd backend python -m pytest tests/ -v --tb=short # ============================================================================ # Frontend Checks # ============================================================================ 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-typecheck: 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-tests: name: Frontend Tests runs-on: ubuntu-latest needs: [frontend-lint, frontend-typecheck] 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 working-directory: frontend run: npm run test:run frontend-build: name: Frontend Build runs-on: ubuntu-latest needs: [frontend-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 # ============================================================================ # Docker Build & Test # ============================================================================ docker-test: name: Docker Test runs-on: ubuntu-latest needs: [backend-tests, frontend-build] steps: - uses: actions/checkout@v4 - name: Build Docker image run: docker build -t bambuddy:test . - name: Verify backend imports run: docker run --rm bambuddy:test python -c "import backend.app.main; print('Backend imports OK')" - name: Verify static files exist run: docker run --rm bambuddy:test test -d /app/static - name: Start container run: | docker run -d --name bambuddy-test -p 8000:8000 bambuddy:test sleep 10 - name: Test health endpoint run: | HEALTH=$(curl -s http://localhost:8000/health) echo "$HEALTH" echo "$HEALTH" | grep -q "healthy" - name: Test API endpoint run: | curl -s http://localhost:8000/api/v1/printers | head -c 200 - name: Test static files served run: | STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/) echo "Static files HTTP status: $STATUS" [ "$STATUS" = "200" ] - name: Show container logs on failure if: failure() run: docker logs bambuddy-test - name: Cleanup if: always() run: docker rm -f bambuddy-test || true