stages: - build - test - deploy # Builds the Docker image and pushes it to the GitLab container registry on # port 443 (not 5050). Uses Docker-in-Docker (dind); the runner must have # privileged = true and no host docker.sock mounted into services. TLS must # stay off (DOCKER_TLS_CERTDIR: "") or the daemon listens on 2376 only. # Tagged with the commit SHA; :latest is also pushed on the default branch. # Registry auth (CI_REGISTRY_USER / CI_REGISTRY_PASSWORD) comes from GitLab's # own predefined CI/CD variables, scoped to this job's token — never hardcode # registry credentials here. Real, long-lived secrets belong in # Settings > CI/CD > Variables (Masked + Protected; File type for keys/certs), # never committed to this file. build: stage: build image: docker:29.8.1 services: - docker:29.8.1-dind variables: DOCKER_HOST: tcp://docker:2375 DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "" REGISTRY_HOST: registry.gitlab.winsoo.org IMAGE: $REGISTRY_HOST/$CI_PROJECT_PATH rules: - if: $CI_PIPELINE_SOURCE == "push" script: - | echo "Waiting for dind daemon..." for i in $(seq 1 60); do if docker info >/dev/null 2>&1; then echo "dind daemon is up" break fi sleep 1 done - docker info - echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$REGISTRY_HOST" - docker build --pull -t "$IMAGE:$CI_COMMIT_SHORT_SHA" . - docker push "$IMAGE:$CI_COMMIT_SHORT_SHA" - | if [ "$CI_COMMIT_BRANCH" = "$CI_DEFAULT_BRANCH" ]; then docker tag "$IMAGE:$CI_COMMIT_SHORT_SHA" "$IMAGE:latest" docker push "$IMAGE:latest" fi after_script: - docker rmi "$IMAGE:$CI_COMMIT_SHORT_SHA" 2>/dev/null || true test: stage: test image: debian:13 services: # no PostGIS needed: the settings use the plain postgresql backend # (django.contrib.gis is only used for GDAL/GEOS-backed fields, not a # postgis-flavoured DB engine) - name: postgres:17 alias: chat_db - name: redis:7 rules: - if: $CI_PIPELINE_SOURCE == "push" cache: key: pip paths: - .cache/pip variables: PIP_CACHE_DIR: $CI_PROJECT_DIR/.cache/pip # Service containers are configured from these; the app settings below # reference them so the two sides can't drift apart. # Dummy, throwaway values that only ever talk to the job's own service # containers — safe to keep in the repo. Real secrets never belong in a # test job; put them in Settings > CI/CD > Variables instead. # postgres service POSTGRES_USER: ci POSTGRES_PASSWORD: ci-password POSTGRES_DB: chat_db # app settings, derived from the service config above DEBUG: "true" DB_NAME: $POSTGRES_DB DB_USER: $POSTGRES_USER DB_PASSWORD: $POSTGRES_PASSWORD DB_HOST: chat_db DB_PORT: "5432" REDIS_BASE_URL: redis://redis:6379/2 # ACCOUNTS_BASE_PUBLIC_URL, OAUTH2_PROVIDER_BASE_PUBLIC_URL, # OAUTH2_PROVIDER_BASE_PRIVATE_URL, OAUTH2_PROVIDER_CLIENT_ID and # OAUTH2_PROVIDER_CLIENT_SECRET are required by main/settings.py (no # default) but are NOT set here — set them in # Settings > CI/CD > Variables so they come from the environment instead # of being hardcoded in this file. # MinIO/Mattermost settings all have Python-side defaults and are only # touched lazily inside services the test suite mocks out, so no live # minio/mattermost service is needed here (unlike accounts, which checks # its buckets on startup). before_script: # keep in sync with the Dockerfile - apt-get update - apt-get install -y python3 python3-pip binutils libproj-dev gdal-bin - pip3 install --break-system-packages --ignore-installed -r requirements.txt - pip3 install --break-system-packages setuptools script: - python3 manage.py check - python3 manage.py makemigrations --check --dry-run # the suite is pytest-style; `manage.py test` would silently run 0 tests - python3 -m pytest -q --junitxml=report.xml artifacts: when: always reports: junit: report.xml # Runs on the staging host through a shell runner tagged `staging` that can use # the docker CLI. The compose stack keeps a git checkout of this repo (mounted # at /app), so this updates that checkout and restarts the service. # Set DEPLOY_DIR in Settings > CI/CD > Variables (the directory that holds # docker-compose.yml and the ./chat checkout). deploy_staging: stage: deploy tags: - staging rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: manual allow_failure: true # otherwise the pipeline shows "blocked" until someone deploys variables: DEPLOY_SERVICE: chat environment: name: staging script: - cd "$DEPLOY_DIR" - git -C "$DEPLOY_SERVICE" pull --ff-only origin "$CI_DEFAULT_BRANCH" - docker compose up -d --build "$DEPLOY_SERVICE"