1+ name : Red Hat Learning Paths CI
2+
3+ on :
4+ push :
5+ branches : [ main, develop ]
6+ pull_request :
7+ branches : [ main, develop ]
8+ workflow_dispatch :
9+
10+ env :
11+ REGISTRY : ghcr.io
12+ IMAGE_NAME_BACKEND : ${{ github.repository }}-backend
13+ IMAGE_NAME_FRONTEND : ${{ github.repository }}-frontend
14+
15+ jobs :
16+ test-backend :
17+ name : Test Backend
18+ runs-on : ubuntu-latest
19+
20+ services :
21+ postgres :
22+ image : postgres:15-alpine
23+ env :
24+ POSTGRES_PASSWORD : password
25+ POSTGRES_USER : postgres
26+ POSTGRES_DB : test_db
27+ ports :
28+ - 5432:5432
29+ options : >-
30+ --health-cmd pg_isready
31+ --health-interval 10s
32+ --health-timeout 5s
33+ --health-retries 5
34+
35+ steps :
36+ - name : Checkout code
37+ uses : actions/checkout@v4
38+
39+ - name : Set up Python
40+ uses : actions/setup-python@v4
41+ with :
42+ python-version : ' 3.9'
43+ cache : ' pip'
44+
45+ - name : Install dependencies
46+ working-directory : ./backend
47+ run : |
48+ python -m pip install --upgrade pip
49+ pip install -r requirements.txt
50+ pip install pytest-cov pytest-mock
51+
52+ - name : Run tests
53+ working-directory : ./backend
54+ env :
55+ DATABASE_URL : postgresql://postgres:password@localhost:5432/test_db
56+ OLLAMA_BASE_URL : http://localhost:11434
57+ run : |
58+ python -m pytest test_main.py -v --cov=. --cov-report=xml --cov-report=term-missing
59+
60+ - name : Upload coverage to Codecov
61+ uses : codecov/codecov-action@v3
62+ with :
63+ file : ./backend/coverage.xml
64+ flags : backend
65+ name : backend-coverage
66+
67+ test-frontend :
68+ name : Test Frontend
69+ runs-on : ubuntu-latest
70+
71+ steps :
72+ - name : Checkout code
73+ uses : actions/checkout@v4
74+
75+ - name : Set up Node.js
76+ uses : actions/setup-node@v3
77+ with :
78+ node-version : ' 18'
79+ cache : ' npm'
80+ cache-dependency-path : ./frontend/package-lock.json
81+
82+ - name : Install dependencies
83+ working-directory : ./frontend
84+ run : npm ci
85+
86+ - name : Run unit tests
87+ working-directory : ./frontend
88+ run : npm test -- --coverage --watchAll=false
89+
90+ - name : Upload coverage to Codecov
91+ uses : codecov/codecov-action@v3
92+ with :
93+ file : ./frontend/coverage/lcov.info
94+ flags : frontend
95+ name : frontend-coverage
96+
97+ lint-and-format :
98+ name : Lint and Format Check
99+ runs-on : ubuntu-latest
100+
101+ steps :
102+ - name : Checkout code
103+ uses : actions/checkout@v4
104+
105+ - name : Set up Python
106+ uses : actions/setup-python@v4
107+ with :
108+ python-version : ' 3.9'
109+
110+ - name : Set up Node.js
111+ uses : actions/setup-node@v3
112+ with :
113+ node-version : ' 18'
114+ cache : ' npm'
115+ cache-dependency-path : ./frontend/package-lock.json
116+
117+ - name : Install Python linting tools
118+ run : |
119+ python -m pip install --upgrade pip
120+ pip install black flake8 isort mypy
121+
122+ - name : Lint Python code
123+ working-directory : ./backend
124+ run : |
125+ flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
126+ black --check .
127+ isort --check-only .
128+
129+ - name : Install frontend dependencies
130+ working-directory : ./frontend
131+ run : npm ci
132+
133+ - name : Lint frontend code
134+ working-directory : ./frontend
135+ run : npm run lint
136+
137+ security-scan :
138+ name : Security Scan
139+ runs-on : ubuntu-latest
140+
141+ steps :
142+ - name : Checkout code
143+ uses : actions/checkout@v4
144+
145+ - name : Run Trivy vulnerability scanner
146+ uses : aquasecurity/trivy-action@master
147+ with :
148+ scan-type : ' fs'
149+ scan-ref : ' .'
150+ format : ' sarif'
151+ output : ' trivy-results.sarif'
152+
153+ - name : Upload Trivy scan results to GitHub Security tab
154+ uses : github/codeql-action/upload-sarif@v2
155+ if : always()
156+ with :
157+ sarif_file : ' trivy-results.sarif'
158+
159+ build-images :
160+ name : Build Container Images
161+ runs-on : ubuntu-latest
162+ needs : [test-backend, test-frontend, lint-and-format]
163+ if : github.event_name == 'push' && github.ref == 'refs/heads/main'
164+
165+ steps :
166+ - name : Checkout code
167+ uses : actions/checkout@v4
168+
169+ - name : Set up Podman
170+ run : |
171+ sudo apt-get update
172+ sudo apt-get install -y podman
173+
174+ - name : Log in to Container Registry
175+ uses : redhat-actions/podman-login@v1
176+ with :
177+ registry : ${{ env.REGISTRY }}
178+ username : ${{ github.actor }}
179+ password : ${{ secrets.GITHUB_TOKEN }}
180+
181+ - name : Extract metadata for backend
182+ id : meta-backend
183+ uses : docker/metadata-action@v4
184+ with :
185+ images : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}
186+ tags : |
187+ type=ref,event=branch
188+ type=ref,event=pr
189+ type=sha,prefix={{branch}}-
190+ type=raw,value=latest,enable={{is_default_branch}}
191+
192+ - name : Extract metadata for frontend
193+ id : meta-frontend
194+ uses : docker/metadata-action@v4
195+ with :
196+ images : ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}
197+ tags : |
198+ type=ref,event=branch
199+ type=ref,event=pr
200+ type=sha,prefix={{branch}}-
201+ type=raw,value=latest,enable={{is_default_branch}}
202+
203+ - name : Build backend image
204+ working-directory : ./backend
205+ run : |
206+ podman build \
207+ --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}:latest \
208+ --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}:${{ github.sha }} \
209+ --file Containerfile .
210+
211+ - name : Build frontend image
212+ working-directory : ./frontend
213+ run : |
214+ podman build \
215+ --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}:latest \
216+ --tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}:${{ github.sha }} \
217+ --file Containerfile .
218+
219+ - name : Push backend image
220+ run : |
221+ podman push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}:latest
222+ podman push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}:${{ github.sha }}
223+
224+ - name : Push frontend image
225+ run : |
226+ podman push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}:latest
227+ podman push ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}:${{ github.sha }}
228+
229+ e2e-tests :
230+ name : E2E Tests
231+ runs-on : ubuntu-latest
232+ needs : [build-images]
233+ if : github.event_name == 'push' && github.ref == 'refs/heads/main'
234+
235+ steps :
236+ - name : Checkout code
237+ uses : actions/checkout@v4
238+
239+ - name : Set up Podman
240+ run : |
241+ sudo apt-get update
242+ sudo apt-get install -y podman
243+
244+ - name : Set up Node.js
245+ uses : actions/setup-node@v3
246+ with :
247+ node-version : ' 18'
248+ cache : ' npm'
249+ cache-dependency-path : ./frontend/package-lock.json
250+
251+ - name : Install frontend dependencies
252+ working-directory : ./frontend
253+ run : npm ci
254+
255+ - name : Install Playwright
256+ working-directory : ./frontend
257+ run : npx playwright install --with-deps
258+
259+ - name : Pull container images
260+ run : |
261+ podman pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}:${{ github.sha }}
262+ podman pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}:${{ github.sha }}
263+ podman pull docker.io/postgres:15-alpine
264+ podman pull docker.io/ollama/ollama:latest
265+
266+ - name : Tag images for local use
267+ run : |
268+ podman tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_BACKEND }}:${{ github.sha }} localhost/redhat-learning-paths-backend:latest
269+ podman tag ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_FRONTEND }}:${{ github.sha }} localhost/redhat-learning-paths-frontend:latest
270+
271+ - name : Start application with Podman
272+ run : |
273+ # Create volumes
274+ podman volume create postgres-data || true
275+ podman volume create ollama-data || true
276+
277+ # Start the pod
278+ podman play kube podman-pod.yaml
279+
280+ # Wait for services to be ready
281+ sleep 30
282+
283+ # Check health
284+ timeout 60 bash -c 'until curl -f http://localhost:30000/health; do sleep 5; done'
285+ timeout 60 bash -c 'until curl -f http://localhost:30001/health; do sleep 5; done'
286+
287+ - name : Run E2E tests
288+ working-directory : ./frontend
289+ env :
290+ PLAYWRIGHT_BASE_URL : http://localhost:30000
291+ run : npx playwright test
292+
293+ - name : Upload Playwright report
294+ uses : actions/upload-artifact@v3
295+ if : always()
296+ with :
297+ name : playwright-report
298+ path : frontend/playwright-report/
299+ retention-days : 30
300+
301+ - name : Stop application
302+ if : always()
303+ run : |
304+ podman pod stop redhat-learning-paths || true
305+ podman pod rm redhat-learning-paths || true
306+
307+ deploy-staging :
308+ name : Deploy to Staging
309+ runs-on : ubuntu-latest
310+ needs : [e2e-tests]
311+ if : github.event_name == 'push' && github.ref == 'refs/heads/main'
312+ environment :
313+ name : staging
314+ url : https://staging.redhat-learning-paths.example.com
315+
316+ steps :
317+ - name : Checkout code
318+ uses : actions/checkout@v4
319+
320+ - name : Deploy to staging
321+ run : |
322+ echo "Deploying to staging environment..."
323+ echo "Image tags: ${{ github.sha }}"
324+ # Add your staging deployment steps here
325+ # This could include updating Kubernetes manifests,
326+ # triggering deployment pipelines, etc.
327+
328+ notification :
329+ name : Notification
330+ runs-on : ubuntu-latest
331+ needs : [test-backend, test-frontend, lint-and-format, security-scan]
332+ if : always()
333+
334+ steps :
335+ - name : Notify on success
336+ if : ${{ needs.test-backend.result == 'success' && needs.test-frontend.result == 'success' && needs.lint-and-format.result == 'success' }}
337+ run : |
338+ echo "✅ All checks passed successfully!"
339+
340+ - name : Notify on failure
341+ if : ${{ needs.test-backend.result == 'failure' || needs.test-frontend.result == 'failure' || needs.lint-and-format.result == 'failure' || needs.security-scan.result == 'failure' }}
342+ run : |
343+ echo "❌ Some checks failed. Please review the logs."
344+ exit 1
0 commit comments