Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
name: CRMS CD Pipeline

on:
push:
branches: [ main ]

jobs:

push-to-registry:
name: Push images to GHCR
runs-on: ubuntu-latest

permissions:
contents: read
packages: write

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push backend
uses: docker/build-push-action@v5
with:
context: ./backend
push: true
tags: |
ghcr.io/crms-devops/crms-backend:latest
ghcr.io/crms-devops/crms-backend:${{ github.sha }}

- name: Build and push frontend
uses: docker/build-push-action@v5
with:
context: ./frontend
push: true
tags: |
ghcr.io/crms-devops/crms-frontend:latest
ghcr.io/crms-devops/crms-frontend:${{ github.sha }}

- name: Summary
run: |
echo "## Deployment Summary" >> $GITHUB_STEP_SUMMARY
echo "Backend: ghcr.io/crms-devops/crms-backend:${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
echo "Frontend: ghcr.io/crms-devops/crms-frontend:${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
130 changes: 130 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
name: CRMS CI Pipeline

on:
push:
branches: [ "**" ]
pull_request:
branches: [ develop, main ]

jobs:

backend-test:
name: Backend — pytest
runs-on: ubuntu-latest

services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: crms_test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: testpassword
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 5432:5432

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Python 3.13
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Cache pip packages
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('backend/requirements.txt') }}

- name: Install dependencies
run: |
cd backend
pip install -r requirements.txt
pip install pytest pytest-asyncio httpx

- name: Run pytest
env:
DATABASE_URL: postgresql://postgres:testpassword@localhost:5432/crms_test
SECRET_KEY: test-secret-key
ALGORITHM: HS256
ACCESS_TOKEN_EXPIRE_MINUTES: 60
run: |
cd backend
pytest tests/ -v --tb=short

frontend-lint:
name: Frontend — ESLint
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node 20
uses: actions/setup-node@v4
with:
node-version: "20"
cache: "npm"
cache-dependency-path: frontend/package-lock.json

- name: Install dependencies
run: |
cd frontend
npm ci

- name: Run ESLint
run: |
cd frontend
npm run lint

docker-build-scan:
name: Docker — build + Trivy scan
runs-on: ubuntu-latest
needs: [ backend-test, frontend-lint ]

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Build backend image
uses: docker/build-push-action@v5
with:
context: ./backend
push: false
tags: crms-backend:${{ github.sha }}
load: true

- name: Build frontend image
uses: docker/build-push-action@v5
with:
context: ./frontend
push: false
tags: crms-frontend:${{ github.sha }}
load: true

- name: Trivy scan — backend
uses: aquasecurity/trivy-action@master
with:
image-ref: crms-backend:${{ github.sha }}
format: table
exit-code: 1
severity: CRITICAL
ignore-unfixed: true

- name: Trivy scan — frontend
uses: aquasecurity/trivy-action@master
with:
image-ref: crms-frontend:${{ github.sha }}
format: table
exit-code: 1
severity: CRITICAL
ignore-unfixed: true
7 changes: 7 additions & 0 deletions backend/tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import pytest
from fastapi.testclient import TestClient
from app.main import app

@pytest.fixture
def client():
return TestClient(app)
15 changes: 15 additions & 0 deletions backend/tests/test_health.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
def test_health(client):
response = client.get("/health")
assert response.status_code == 200
assert response.json()["status"] == "ok"

def test_login_missing_fields(client):
response = client.post("/auth/student/login", json={})
assert response.status_code == 422

def test_login_invalid_credentials(client):
response = client.post("/auth/student/login", json={
"register_number": "000000000000",
"date_of_birth": "2000-01-01"
})
assert response.status_code == 401
Loading