- CI/CD GitLab (.gitlab-ci.yml): verify -> test -> build -> publish -> deploy cu health-gate (/api/v3/health/all) + rollback manual - Publicare pe retele sociale (LinkedIn/Facebook) din Analysis History (social.ts, linkedin.ts, facebook.ts, SocialPostModal) - Specificatii OpenAPI: agent-v3 (87 op.) si didi-framework (287 op.) - Matrice testare acceptanta beneficiar + script dovezi API - Fix nginx SSL: redirect port 3001 (error_page 497, absolute_redirect off) - Adrese interne inlocuite cu hostname-uri generice (.local)
178 lines
7.2 KiB
YAML
178 lines
7.2 KiB
YAML
# =============================================================================
|
|
# DiDi Lot 2 (Backend) — Pipeline CI/CD GitLab
|
|
# =============================================================================
|
|
# Etape: verify (typecheck) → test (unitare) → build (imagini Docker, versionate)
|
|
# → publish (registry) → deploy (cu HEALTH-GATE) → rollback (manual)
|
|
#
|
|
# Variabile așteptate în GitLab (Settings → CI/CD → Variables):
|
|
# CI_REGISTRY / CI_REGISTRY_USER / CI_REGISTRY_PASSWORD — registry-ul de imagini
|
|
# DEPLOY_HOST — host-ul de deployment (SSH)
|
|
# DEPLOY_USER — utilizatorul de deployment
|
|
# Versionare imagini: $CI_COMMIT_SHORT_SHA (+ tag "latest" doar pe branch-ul implicit).
|
|
# Rollback: job manual care re-etichetează imaginea anterioară (previous) ca latest
|
|
# și redeployează — mecanismul de revenire cerut de documentație.
|
|
# =============================================================================
|
|
|
|
stages:
|
|
- verify
|
|
- test
|
|
- build
|
|
- publish
|
|
- deploy
|
|
- rollback
|
|
|
|
default:
|
|
interruptible: true
|
|
|
|
variables:
|
|
DOCKER_TLS_CERTDIR: "/certs"
|
|
AGENT_DIR: services/orchestration-layer/agent-v3
|
|
FRAMEWORK_DIR: services/orchestration-layer/didiFramework
|
|
DASHBOARD_DIR: admin-dashboard
|
|
|
|
# ---------- șabloane reutilizabile ----------
|
|
.node:
|
|
image: node:20-alpine
|
|
before_script:
|
|
- node --version && npm --version
|
|
|
|
.docker:
|
|
image: docker:27
|
|
services: [docker:27-dind]
|
|
before_script:
|
|
- echo "$CI_REGISTRY_PASSWORD" | docker login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
|
|
|
|
# =============================================================================
|
|
# VERIFY — compilare TypeScript (fără emitere) pe toate serviciile
|
|
# =============================================================================
|
|
verify:agent-v3:
|
|
stage: verify
|
|
extends: .node
|
|
script:
|
|
- cd $AGENT_DIR && npm ci --prefer-offline
|
|
- npx tsc --noEmit
|
|
rules: [{ changes: ["services/orchestration-layer/agent-v3/**/*"] }, { when: always }]
|
|
|
|
verify:framework:
|
|
stage: verify
|
|
extends: .node
|
|
script:
|
|
- cd $FRAMEWORK_DIR && npm ci --prefer-offline
|
|
- npx tsc --noEmit
|
|
|
|
verify:dashboard:
|
|
stage: verify
|
|
extends: .node
|
|
script:
|
|
- cd $DASHBOARD_DIR && npm ci --prefer-offline
|
|
- npm run type-check
|
|
|
|
# =============================================================================
|
|
# TEST — teste unitare (vitest pe agent-v3; raport JUnit pentru GitLab)
|
|
# =============================================================================
|
|
test:agent-v3:
|
|
stage: test
|
|
extends: .node
|
|
script:
|
|
- cd $AGENT_DIR && npm ci --prefer-offline
|
|
- npx vitest run --reporter=default --reporter=junit --outputFile=vitest-junit.xml
|
|
artifacts:
|
|
when: always
|
|
reports:
|
|
junit: $AGENT_DIR/vitest-junit.xml
|
|
expire_in: 30 days
|
|
|
|
# validarea specificațiilor OpenAPI livrate (criteriul 6 — OpenAPI/Swagger)
|
|
test:openapi:
|
|
stage: test
|
|
image: python:3.12-alpine
|
|
script:
|
|
- pip install --quiet openapi-spec-validator pyyaml
|
|
- python -c "from openapi_spec_validator import validate; import yaml; validate(yaml.safe_load(open('$AGENT_DIR/openapi.yaml')))"
|
|
- python -c "from openapi_spec_validator import validate; import yaml; validate(yaml.safe_load(open('$FRAMEWORK_DIR/openapi.yaml')))"
|
|
|
|
# =============================================================================
|
|
# BUILD — imagini Docker versionate cu SHA-ul commit-ului
|
|
# =============================================================================
|
|
build:agent-v3:
|
|
stage: build
|
|
extends: .docker
|
|
script:
|
|
- docker build -t "$CI_REGISTRY_IMAGE/agent-v3:$CI_COMMIT_SHORT_SHA" $AGENT_DIR
|
|
- docker push "$CI_REGISTRY_IMAGE/agent-v3:$CI_COMMIT_SHORT_SHA"
|
|
|
|
build:framework:
|
|
stage: build
|
|
extends: .docker
|
|
script:
|
|
- docker build -t "$CI_REGISTRY_IMAGE/didi-framework:$CI_COMMIT_SHORT_SHA" $FRAMEWORK_DIR
|
|
- docker push "$CI_REGISTRY_IMAGE/didi-framework:$CI_COMMIT_SHORT_SHA"
|
|
|
|
build:dashboard:
|
|
stage: build
|
|
extends: .docker
|
|
script:
|
|
- docker build -t "$CI_REGISTRY_IMAGE/didi-admin:$CI_COMMIT_SHORT_SHA" $DASHBOARD_DIR
|
|
- docker push "$CI_REGISTRY_IMAGE/didi-admin:$CI_COMMIT_SHORT_SHA"
|
|
|
|
# =============================================================================
|
|
# PUBLISH — pe branch-ul implicit, promovăm SHA-ul la :latest și păstrăm
|
|
# :previous (ținta de rollback)
|
|
# =============================================================================
|
|
publish:latest:
|
|
stage: publish
|
|
extends: .docker
|
|
rules: [{ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' }]
|
|
script:
|
|
- |
|
|
for svc in agent-v3 didi-framework didi-admin; do
|
|
# păstrează versiunea curentă ca :previous (rollback target)
|
|
docker pull "$CI_REGISTRY_IMAGE/$svc:latest" || true
|
|
docker tag "$CI_REGISTRY_IMAGE/$svc:latest" "$CI_REGISTRY_IMAGE/$svc:previous" || true
|
|
docker push "$CI_REGISTRY_IMAGE/$svc:previous" || true
|
|
# promovează build-ul curent
|
|
docker pull "$CI_REGISTRY_IMAGE/$svc:$CI_COMMIT_SHORT_SHA"
|
|
docker tag "$CI_REGISTRY_IMAGE/$svc:$CI_COMMIT_SHORT_SHA" "$CI_REGISTRY_IMAGE/$svc:latest"
|
|
docker push "$CI_REGISTRY_IMAGE/$svc:latest"
|
|
done
|
|
|
|
# =============================================================================
|
|
# DEPLOY — cu HEALTH-GATE: deploy-ul e considerat reușit DOAR dacă
|
|
# /api/v3/health/all răspunde healthy/degraded după repornire
|
|
# =============================================================================
|
|
deploy:production:
|
|
stage: deploy
|
|
image: alpine:3.20
|
|
rules: [{ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH', when: manual }]
|
|
environment: { name: production }
|
|
before_script: [ "apk add --no-cache openssh-client curl" ]
|
|
script:
|
|
- ssh -o StrictHostKeyChecking=accept-new "$DEPLOY_USER@$DEPLOY_HOST" "
|
|
cd ~/didi/backend/services/orchestration-layer/agent-v3 && docker compose pull && docker compose up -d &&
|
|
cd ../didiFramework && docker compose pull && docker compose up -d"
|
|
# HEALTH-GATE: max 120s până când platforma raportează sănătate
|
|
- |
|
|
for i in $(seq 1 24); do
|
|
code=$(ssh "$DEPLOY_USER@$DEPLOY_HOST" "curl -sk -o /dev/null -w '%{http_code}' http://localhost:24803/api/v3/health/all" || echo 000)
|
|
echo "health-gate încercarea $i: HTTP $code"
|
|
[ "$code" = "200" ] && exit 0
|
|
sleep 5
|
|
done
|
|
echo "HEALTH-GATE EȘUAT — deploy-ul NU este sănătos"; exit 1
|
|
|
|
# =============================================================================
|
|
# ROLLBACK — manual: repune imaginile :previous și redeployează
|
|
# =============================================================================
|
|
rollback:production:
|
|
stage: rollback
|
|
extends: .docker
|
|
rules: [{ if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH', when: manual }]
|
|
environment: { name: production }
|
|
script:
|
|
- |
|
|
for svc in agent-v3 didi-framework didi-admin; do
|
|
docker pull "$CI_REGISTRY_IMAGE/$svc:previous"
|
|
docker tag "$CI_REGISTRY_IMAGE/$svc:previous" "$CI_REGISTRY_IMAGE/$svc:latest"
|
|
docker push "$CI_REGISTRY_IMAGE/$svc:latest"
|
|
done
|
|
- echo "Imaginile anterioare repromovate la :latest — rulați deploy:production pentru a le aplica."
|