Files
carmanagement/.gitlab-ci.yml
T
2026-05-21 12:35:49 -04:00

142 lines
4.2 KiB
YAML

stages:
- test
- build
- deploy
variables:
DOCKER_IMAGE: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA
DOCKER_IMAGE_LATEST: $CI_REGISTRY_IMAGE:latest
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 == "main"
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 == "main"
# ====================================
# BUILD STAGE
# ====================================
build_image:
stage: build
image: docker:24
services:
- name: docker:24-dind
alias: docker
before_script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
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:
- if: $CI_COMMIT_BRANCH == "main"
# ====================================
# DEPLOY STAGE
# ====================================
deploy_to_vps:
stage: deploy
image: alpine:latest
needs:
- build_image
before_script:
- 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 --'
docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
echo '-- Pulling pre-built image --'
docker pull $DOCKER_IMAGE
echo '-- Restarting services --'
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:
- if: $CI_COMMIT_BRANCH == "main"