## Pipeline Stages A typical Django pipeline has three stages: **test → build → deploy**. ```yaml stages: - test - build - deploy ``` ## Test Stage ```yaml test: stage: test image: python:3.12-slim services: - postgres:16-alpine variables: POSTGRES_DB: test_db POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres DB_HOST: postgres script: - pip install -r requirements.txt - python manage.py migrate - python manage.py test ``` ## Build Stage ```yaml build: stage: build image: docker:24 services: - docker:24-dind script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA ``` ## Deploy Stage (Runner on Server) ```yaml deploy: stage: deploy tags: - production script: - docker pull $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA - docker compose up -d --no-deps web ``` Using a self-hosted runner on the production server means no SSH credentials needed in CI.