name: CI on: push: branches: [main, master] pull_request: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true env: PYTHON_VERSION: "3.12" NODE_VERSION: "22" jobs: backend: name: Backend (lint, types, tests) runs-on: ubuntu-latest services: postgres: image: postgres:16-alpine env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: linkedin_test ports: ["5432:5432"] options: >- --health-cmd "pg_isready -U postgres" --health-interval 10s --health-timeout 5s --health-retries 10 env: DJANGO_SECRET_KEY: ci-secret-key-only-used-by-the-test-suite-0123456789 DATABASE_URL: postgres://postgres:postgres@localhost:5432/linkedin_test DJANGO_SETTINGS_MODULE: config.settings.test defaults: run: working-directory: backend steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: ${{ env.PYTHON_VERSION }} cache: pip cache-dependency-path: backend/requirements/*.txt - name: Install dependencies run: pip install -r requirements/dev.txt - name: Ruff run: ruff check . - name: Black run: black --check . - name: Mypy run: mypy apps config continue-on-error: true # advisory until the codebase is fully annotated - name: Bandit (security lint) run: bandit -q -c pyproject.toml -r apps config - name: Django system checks run: python manage.py check --deploy --fail-level ERROR env: DJANGO_SETTINGS_MODULE: config.settings.prod DJANGO_SECRET_KEY: ci-secret-key-long-enough-for-the-production-guard-0123456789abcdef DJANGO_DEBUG: "false" - name: Missing migrations? run: python manage.py makemigrations --check --dry-run - name: Tests run: pytest --cov=apps --cov-report=xml --cov-report=term-missing - name: Upload coverage uses: actions/upload-artifact@v4 with: name: backend-coverage path: backend/coverage.xml if-no-files-found: ignore frontend: name: Frontend (lint, types, build) runs-on: ubuntu-latest defaults: run: working-directory: frontend steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: ${{ env.NODE_VERSION }} cache: npm cache-dependency-path: frontend/package-lock.json - name: Install dependencies run: npm ci --no-audit --no-fund - name: ESLint run: npm run lint - name: TypeScript run: npm run typecheck - name: Build run: npm run build images: name: Docker images build runs-on: ubuntu-latest needs: [backend, frontend] steps: - uses: actions/checkout@v4 - uses: docker/setup-buildx-action@v3 - name: Validate the compose files run: | cp .env.example .env docker compose config --quiet docker compose -f docker-compose.yml -f docker-compose.prod.yml config --quiet - name: Build the API image uses: docker/build-push-action@v6 with: context: . file: backend/Dockerfile push: false cache-from: type=gha cache-to: type=gha,mode=max - name: Build the SPA image uses: docker/build-push-action@v6 with: context: . file: frontend/Dockerfile push: false cache-from: type=gha cache-to: type=gha,mode=max