ci.yml 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  1. name: CI
  2. on:
  3. push:
  4. branches: [main, develop]
  5. pull_request:
  6. branches: [main, develop]
  7. env:
  8. PYTHON_VERSION: '3.11'
  9. NODE_VERSION: '20'
  10. jobs:
  11. # ============================================================================
  12. # Backend Jobs
  13. # ============================================================================
  14. backend-lint:
  15. name: Backend Lint
  16. runs-on: ubuntu-latest
  17. steps:
  18. - uses: actions/checkout@v4
  19. - name: Set up Python
  20. uses: actions/setup-python@v5
  21. with:
  22. python-version: ${{ env.PYTHON_VERSION }}
  23. - name: Install ruff
  24. run: pip install ruff
  25. - name: Run ruff check
  26. run: ruff check backend/
  27. backend-unit-tests:
  28. name: Backend Unit Tests
  29. runs-on: ubuntu-latest
  30. needs: backend-lint
  31. steps:
  32. - uses: actions/checkout@v4
  33. - name: Set up Python
  34. uses: actions/setup-python@v5
  35. with:
  36. python-version: ${{ env.PYTHON_VERSION }}
  37. - name: Cache pip
  38. uses: actions/cache@v4
  39. with:
  40. path: ~/.cache/pip
  41. key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
  42. restore-keys: |
  43. ${{ runner.os }}-pip-
  44. - name: Install dependencies
  45. run: |
  46. python -m pip install --upgrade pip
  47. pip install -r requirements.txt
  48. pip install pytest-cov
  49. - name: Run unit tests
  50. run: |
  51. cd backend
  52. python -m pytest tests/unit/ -v --cov=app --cov-report=xml -m "not slow"
  53. - name: Upload coverage
  54. uses: codecov/codecov-action@v4
  55. if: always()
  56. with:
  57. files: backend/coverage.xml
  58. flags: backend-unit
  59. fail_ci_if_error: false
  60. backend-integration-tests:
  61. name: Backend Integration Tests
  62. runs-on: ubuntu-latest
  63. needs: backend-unit-tests
  64. steps:
  65. - uses: actions/checkout@v4
  66. - name: Set up Python
  67. uses: actions/setup-python@v5
  68. with:
  69. python-version: ${{ env.PYTHON_VERSION }}
  70. - name: Cache pip
  71. uses: actions/cache@v4
  72. with:
  73. path: ~/.cache/pip
  74. key: ${{ runner.os }}-pip-${{ hashFiles('requirements.txt') }}
  75. restore-keys: |
  76. ${{ runner.os }}-pip-
  77. - name: Install dependencies
  78. run: |
  79. python -m pip install --upgrade pip
  80. pip install -r requirements.txt
  81. pip install pytest-cov
  82. - name: Run integration tests
  83. run: |
  84. cd backend
  85. python -m pytest tests/integration/ -v --cov=app --cov-report=xml
  86. - name: Upload coverage
  87. uses: codecov/codecov-action@v4
  88. if: always()
  89. with:
  90. files: backend/coverage.xml
  91. flags: backend-integration
  92. fail_ci_if_error: false
  93. # ============================================================================
  94. # Frontend Jobs
  95. # ============================================================================
  96. frontend-lint:
  97. name: Frontend Lint
  98. runs-on: ubuntu-latest
  99. steps:
  100. - uses: actions/checkout@v4
  101. - name: Set up Node.js
  102. uses: actions/setup-node@v4
  103. with:
  104. node-version: ${{ env.NODE_VERSION }}
  105. cache: 'npm'
  106. cache-dependency-path: frontend/package-lock.json
  107. - name: Install dependencies
  108. working-directory: frontend
  109. run: npm ci
  110. - name: Run ESLint
  111. working-directory: frontend
  112. run: npm run lint
  113. frontend-type-check:
  114. name: Frontend Type Check
  115. runs-on: ubuntu-latest
  116. steps:
  117. - uses: actions/checkout@v4
  118. - name: Set up Node.js
  119. uses: actions/setup-node@v4
  120. with:
  121. node-version: ${{ env.NODE_VERSION }}
  122. cache: 'npm'
  123. cache-dependency-path: frontend/package-lock.json
  124. - name: Install dependencies
  125. working-directory: frontend
  126. run: npm ci
  127. - name: Run TypeScript check
  128. working-directory: frontend
  129. run: npx tsc --noEmit
  130. frontend-unit-tests:
  131. name: Frontend Unit Tests
  132. runs-on: ubuntu-latest
  133. needs: [frontend-lint, frontend-type-check]
  134. steps:
  135. - uses: actions/checkout@v4
  136. - name: Set up Node.js
  137. uses: actions/setup-node@v4
  138. with:
  139. node-version: ${{ env.NODE_VERSION }}
  140. cache: 'npm'
  141. cache-dependency-path: frontend/package-lock.json
  142. - name: Install dependencies
  143. working-directory: frontend
  144. run: npm ci
  145. - name: Run tests with coverage
  146. working-directory: frontend
  147. run: npm run test:coverage
  148. - name: Upload coverage
  149. uses: codecov/codecov-action@v4
  150. if: always()
  151. with:
  152. files: frontend/coverage/coverage-final.json
  153. flags: frontend-unit
  154. fail_ci_if_error: false
  155. frontend-build:
  156. name: Frontend Build
  157. runs-on: ubuntu-latest
  158. needs: frontend-unit-tests
  159. steps:
  160. - uses: actions/checkout@v4
  161. - name: Set up Node.js
  162. uses: actions/setup-node@v4
  163. with:
  164. node-version: ${{ env.NODE_VERSION }}
  165. cache: 'npm'
  166. cache-dependency-path: frontend/package-lock.json
  167. - name: Install dependencies
  168. working-directory: frontend
  169. run: npm ci
  170. - name: Build
  171. working-directory: frontend
  172. run: npm run build
  173. - name: Upload build artifacts
  174. uses: actions/upload-artifact@v4
  175. with:
  176. name: frontend-build
  177. path: static/
  178. # ============================================================================
  179. # E2E Tests
  180. # ============================================================================
  181. e2e-tests:
  182. name: E2E Tests
  183. runs-on: ubuntu-latest
  184. needs: [backend-integration-tests, frontend-build]
  185. steps:
  186. - uses: actions/checkout@v4
  187. - name: Set up Python
  188. uses: actions/setup-python@v5
  189. with:
  190. python-version: ${{ env.PYTHON_VERSION }}
  191. - name: Install backend dependencies
  192. run: |
  193. python -m pip install --upgrade pip
  194. pip install -r requirements.txt
  195. pip install playwright
  196. playwright install chromium --with-deps
  197. - name: Download frontend build
  198. uses: actions/download-artifact@v4
  199. with:
  200. name: frontend-build
  201. path: static/
  202. - name: Start backend server
  203. run: |
  204. python -m uvicorn backend.app.main:app --host 0.0.0.0 --port 8000 &
  205. sleep 15
  206. env:
  207. DEBUG: 'false'
  208. - name: Run E2E tests
  209. run: |
  210. python tests/e2e_comprehensive_test.py || true
  211. python tests/e2e_toggle_persistence_test.py
  212. - name: Upload test screenshots
  213. uses: actions/upload-artifact@v4
  214. if: always()
  215. with:
  216. name: e2e-screenshots
  217. path: /tmp/bambuddy_*.png
  218. if-no-files-found: ignore
  219. # ============================================================================
  220. # Summary Job
  221. # ============================================================================
  222. ci-summary:
  223. name: CI Summary
  224. runs-on: ubuntu-latest
  225. needs: [backend-integration-tests, frontend-build, e2e-tests]
  226. if: always()
  227. steps:
  228. - name: Check results
  229. run: |
  230. echo "Backend Integration Tests: ${{ needs.backend-integration-tests.result }}"
  231. echo "Frontend Build: ${{ needs.frontend-build.result }}"
  232. echo "E2E Tests: ${{ needs.e2e-tests.result }}"
  233. if [[ "${{ needs.backend-integration-tests.result }}" == "failure" ]] || \
  234. [[ "${{ needs.frontend-build.result }}" == "failure" ]]; then
  235. echo "CI failed!"
  236. exit 1
  237. fi
  238. echo "CI passed!"