stages: - test - build - deploy variables: PYTHON_VERSION: "3.12" NODE_VERSION: "22" POSTGRES_DB: "kmtn_test" POSTGRES_USER: "postgres" POSTGRES_PASSWORD: "postgres" # ── Backend Tests ────────────────────────────────────────── backend-test: stage: test image: python:${PYTHON_VERSION}-slim before_script: - pip install --no-cache-dir -r backend/requirements.txt - pip install --no-cache-dir -r backend/requirements-test.txt script: - cd backend - python -m pytest tests/ --cov=app --cov-report=term-missing --cov-report=xml --cov-fail-under=10 artifacts: reports: coverage_report: coverage_format: cobertura path: backend/coverage.xml when: always tags: - docker # ── Frontend Tests ───────────────────────────────────────── frontend-test: stage: test image: node:${NODE_VERSION}-alpine before_script: - cd /builds/$CI_PROJECT_PATH - npm ci - npm install --save-dev vitest @vitest/coverage-v8 jsdom @angular-builders/jest script: - npx vitest run --reporter=verbose --coverage || true artifacts: reports: coverage_report: coverage_format: cobertura path: coverage/frontend/cobertura-coverage.xml when: always allow_failure: true tags: - docker # ── Backend Lint ─────────────────────────────────────────── backend-lint: stage: test image: python:${PYTHON_VERSION}-slim before_script: - pip install --no-cache-dir ruff script: - cd backend - python -m ruff check app/ --select=E,F,W --ignore=E501 || true allow_failure: true tags: - docker # ── Docker Build ─────────────────────────────────────────── docker-build: stage: build image: docker:24 services: - docker:24-dind script: - docker build -t $CI_REGISTRY_IMAGE/frontend:$CI_COMMIT_SHA . - docker build -t $CI_REGISTRY_IMAGE/api:$CI_COMMIT_SHA ./backend only: - main tags: - docker # ── Quality Gate (must pass before merge) ────────────────── quality-gate: stage: test image: alpine:latest script: - echo "Quality gate: Backend tests must pass (enforced by pipeline). Frontend tests allowed to fail for now." needs: - backend-test allow_failure: false tags: - docker