Files
carmanagement/.gitlab-ci.yml
T
2026-05-22 02:58:59 -04:00

170 lines
7.0 KiB
YAML

stages:
- test
- build
- deploy
variables:
DOCKERFILE_PATH: Dockerfile.production
# Required: disable TLS so the docker client can reach the dind daemon
DOCKER_TLS_CERTDIR: ""
# ====================================
# TEST STAGE
# Runs on every push and merge request
# ====================================
unit_tests:
stage: test
image: node:20-bookworm
before_script:
- npm ci
- npm run db:generate
script:
- npm run type-check
- npm run test:api
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "develop"
integration_tests:
stage: test
image: node:20-bookworm
services:
- name: postgres:16-alpine
alias: postgres
variables:
POSTGRES_DB: rentaldrivego_test
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
- name: redis:7-alpine
alias: redis
variables:
# Used by db:deploy (Prisma migrations) and any code reading DATABASE_URL directly
DATABASE_URL: "postgresql://postgres:password@postgres:5432/rentaldrivego_test"
REDIS_URL: "redis://redis:6379"
NODE_ENV: test
before_script:
- npm ci
- npm run db:generate
# Overwrite the local .env.test so vitest integration config gets CI service hostnames
# (the file uses postgres/redis aliases, not localhost)
- |
cat > apps/api/.env.test << 'EOF'
DATABASE_URL=postgresql://postgres:password@postgres:5432/rentaldrivego_test
REDIS_URL=redis://redis:6379
JWT_SECRET=test-secret
JWT_EXPIRY=8h
NODE_ENV=test
FILE_STORAGE_ROOT=/tmp/rentaldrivego-test-storage
EOF
- npm run db:deploy
script:
- npm run test:api:integration
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
- if: $CI_COMMIT_BRANCH == "develop"
# ====================================
# BUILD STAGE
# ====================================
build_image:
stage: build
image: docker:24
services:
- name: docker:24-dind
alias: docker
before_script:
# Prefer GitLab's built-in registry variables, but allow explicit fallbacks
# so the pipeline can publish to any OCI-compatible registry.
- export REGISTRY_HOST="${CI_REGISTRY:-${REGISTRY_HOST:-}}"
- export REGISTRY_USER="${CI_REGISTRY_USER:-${REGISTRY_USER:-}}"
- export REGISTRY_PASSWORD="${CI_REGISTRY_PASSWORD:-${REGISTRY_PASSWORD:-}}"
- export IMAGE_REPOSITORY="${CI_REGISTRY_IMAGE:-${REGISTRY_IMAGE:-}}"
- test -n "$REGISTRY_HOST" || { echo "Registry host is not set. Configure CI_REGISTRY or REGISTRY_HOST."; exit 1; }
- test -n "$REGISTRY_USER" || { echo "Registry user is not set. Configure CI_REGISTRY_USER or REGISTRY_USER."; exit 1; }
- test -n "$REGISTRY_PASSWORD" || { echo "Registry password is not set. Configure CI_REGISTRY_PASSWORD or REGISTRY_PASSWORD."; exit 1; }
- test -n "$IMAGE_REPOSITORY" || { echo "Image repository is not set. Configure CI_REGISTRY_IMAGE or REGISTRY_IMAGE."; exit 1; }
- export DOCKER_IMAGE="$IMAGE_REPOSITORY:$CI_COMMIT_SHORT_SHA"
- export DOCKER_IMAGE_LATEST="$IMAGE_REPOSITORY:latest"
- echo "$REGISTRY_PASSWORD" | docker login "$REGISTRY_HOST" -u "$REGISTRY_USER" --password-stdin
script:
- echo "--- Building Docker Image ---"
# NEXT_PUBLIC_* vars are inlined into Next.js bundles at build time — must be passed as ARGs
- |
docker build \
--build-arg NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL \
--build-arg NEXT_PUBLIC_MARKETPLACE_URL=$NEXT_PUBLIC_MARKETPLACE_URL \
--build-arg NEXT_PUBLIC_DASHBOARD_URL=$NEXT_PUBLIC_DASHBOARD_URL \
--build-arg NEXT_PUBLIC_ADMIN_URL=$NEXT_PUBLIC_ADMIN_URL \
-t $DOCKER_IMAGE \
-t $DOCKER_IMAGE_LATEST \
-f $DOCKERFILE_PATH .
- echo "--- Pushing to Registry ---"
- docker push $DOCKER_IMAGE
- docker push $DOCKER_IMAGE_LATEST
rules:
# Skip the container publish step unless either the GitLab registry or an
# explicit fallback registry configuration is available.
- if: '$CI_COMMIT_BRANCH == "develop" && (($CI_REGISTRY && $CI_REGISTRY_USER && $CI_REGISTRY_PASSWORD && $CI_REGISTRY_IMAGE) || ($REGISTRY_HOST && $REGISTRY_USER && $REGISTRY_PASSWORD && $REGISTRY_IMAGE))'
- when: never
# ====================================
# DEPLOY STAGE
# ====================================
deploy_to_vps:
stage: deploy
image: alpine:latest
needs:
- build_image
before_script:
- export REGISTRY_HOST="${CI_REGISTRY:-${REGISTRY_HOST:-}}"
- export REGISTRY_USER="${CI_REGISTRY_USER:-${REGISTRY_USER:-}}"
- export REGISTRY_PASSWORD="${CI_REGISTRY_PASSWORD:-${REGISTRY_PASSWORD:-}}"
- export IMAGE_REPOSITORY="${CI_REGISTRY_IMAGE:-${REGISTRY_IMAGE:-}}"
- test -n "$REGISTRY_HOST" || { echo "Registry host is not set. Configure CI_REGISTRY or REGISTRY_HOST."; exit 1; }
- test -n "$REGISTRY_USER" || { echo "Registry user is not set. Configure CI_REGISTRY_USER or REGISTRY_USER."; exit 1; }
- test -n "$REGISTRY_PASSWORD" || { echo "Registry password is not set. Configure CI_REGISTRY_PASSWORD or REGISTRY_PASSWORD."; exit 1; }
- test -n "$IMAGE_REPOSITORY" || { echo "Image repository is not set. Configure CI_REGISTRY_IMAGE or REGISTRY_IMAGE."; exit 1; }
- export DOCKER_IMAGE="$IMAGE_REPOSITORY:$CI_COMMIT_SHORT_SHA"
- apk add --no-cache openssh-client
# Load the SSH private key stored in the CI variable SSH_PRIVATE_KEY
- eval $(ssh-agent -s)
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' | ssh-add -
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
# Scan and trust the VPS host key (avoids manual known_hosts management)
- ssh-keyscan -H $VPS_IP >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
script:
- echo "--- Deploying $DOCKER_IMAGE to VPS ---"
- |
ssh $VPS_USER@$VPS_IP "
set -e
cd /opt/rentaldrivego
echo '-- Pulling latest code --'
git pull
echo '-- Logging into registry --'
test -n '$REGISTRY_HOST' || { echo 'Registry host is not set.'; exit 1; }
test -n '$REGISTRY_USER' || { echo 'Registry user is not set.'; exit 1; }
test -n '$REGISTRY_PASSWORD' || { echo 'Registry password is not set.'; exit 1; }
echo '$REGISTRY_PASSWORD' | docker login '$REGISTRY_HOST' -u '$REGISTRY_USER' --password-stdin
echo '-- Pulling pre-built image --'
docker pull $DOCKER_IMAGE
echo '-- Restarting services --'
APP_IMAGE=$IMAGE_REPOSITORY \
APP_VERSION=$CI_COMMIT_SHORT_SHA \
docker compose -p rentaldrivego-prod \
--env-file .env.docker.production \
-f docker-compose.production.yml \
up -d --no-build
echo '-- Pruning old images --'
docker image prune -f
"
rules:
# Deploy only when both registry access and VPS credentials are available.
- if: '$CI_COMMIT_BRANCH == "develop" && ((($CI_REGISTRY && $CI_REGISTRY_USER && $CI_REGISTRY_PASSWORD && $CI_REGISTRY_IMAGE) || ($REGISTRY_HOST && $REGISTRY_USER && $REGISTRY_PASSWORD && $REGISTRY_IMAGE)) && $SSH_PRIVATE_KEY && $VPS_IP && $VPS_USER)'
- when: never