Build
2 jobs · 2 min 18 s
build:app
node:20-alpine
1 min 04 s
build:docker
docker:24 + docker:24-dind
1 min 14 s
Test
2 jobs · 1 min 53 s
test:unit
node:20-alpine
1 min 12 s
test:lint
node:20-alpine
41 s
Security
3 jobs · 1 min 07 s
security:trivy-image
aquasec/trivy:0.58.0
28 s
security:sast
template: Security/SAST.gitlab-ci.yml
22 s
security:dependency-scan
template: Security/Dependency-Scanning.gitlab-ci.yml
17 s
Infra (Terraform)
3 jobs · 1 min 34 s
infra:validate
hashicorp/terraform:1.6.0
18 s
infra:plan
hashicorp/terraform:1.6.0
52 s
infra:apply
hashicorp/terraform:1.6.0
24 s
Deploy
2 jobs · 1 min 40 s
deploy:staging
bitnami/kubectl:1.31
48 s
deploy:production
bitnami/kubectl:1.31
52 s
Notify
1 job · 4 s
notify:slack
alpine/curl:latest
4 s
.gitlab-ci.yml — NutriFlow Backend
📋 Copiar
# .gitlab-ci.yml · NutriFlow SaaS — generado por CULTIVA IA stages: - build - test - security - infra - deploy - notify # ── Variables globales ───────────────────────────────────────── variables: DOCKER_DRIVER: overlay2 DOCKER_TLS_CERTDIR: "/certs" TF_ROOT: $CI_PROJECT_DIR/terraform TF_VERSION: "1.6.0" KUBE_NAMESPACE_STG: nutriflow-stg KUBE_NAMESPACE_PROD: nutriflow-prod # ── Template base Kubernetes ──────────────────────────────────── .kube_template: &kube_template image: bitnami/kubectl:1.31 before_script: - kubectl config set-cluster k8s --server="$KUBE_URL" --insecure-skip-tls-verify=true - kubectl config set-credentials admin --token="$KUBE_TOKEN" - kubectl config set-context default --cluster=k8s --user=admin - kubectl config use-context default # ── STAGE: BUILD ─────────────────────────────────────────────── build:app: stage: build image: node:20-alpine script: - npm ci - npm run build artifacts: paths: [dist/] expire_in: 1 hour cache: key: $CI_COMMIT_REF_SLUG paths: [node_modules/] policy: pull-push build:docker: stage: build image: docker:24 services: [docker:24-dind] before_script: - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA - docker tag $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA $CI_REGISTRY_IMAGE:latest - docker push $CI_REGISTRY_IMAGE:latest only: [main, develop] # ── STAGE: TEST ──────────────────────────────────────────────── test:unit: stage: test image: node:20-alpine script: - npm ci - npm test -- --coverage coverage: '/Lines\s*:\s*(\d+\.\d+)%/' artifacts: reports: coverage_report: coverage_format: cobertura path: coverage/cobertura-coverage.xml test:lint: stage: test image: node:20-alpine script: - npm ci - npm run lint - npm run format:check # ── STAGE: SECURITY ──────────────────────────────────────────── include: - template: Security/SAST.gitlab-ci.yml - template: Security/Dependency-Scanning.gitlab-ci.yml security:trivy-image: stage: security image: aquasec/trivy:0.58.0 script: - trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA allow_failure: false # ── STAGE: INFRA (Terraform) ──────────────────────────────────── infra:validate: stage: infra image: hashicorp/terraform:$TF_VERSION script: - cd $TF_ROOT - terraform init -backend=false - terraform validate - terraform fmt -check infra:plan: stage: infra image: hashicorp/terraform:$TF_VERSION script: - cd $TF_ROOT - terraform init - terraform plan -out=tfplan artifacts: paths: ["$TF_ROOT/tfplan"] expire_in: 1 day infra:apply: stage: infra image: hashicorp/terraform:$TF_VERSION script: - cd $TF_ROOT - terraform init - terraform apply -auto-approve tfplan dependencies: [infra:plan] when: manual only: [main] # ── STAGE: DEPLOY ────────────────────────────────────────────── deploy:staging: <<: *kube_template stage: deploy script: - kubectl apply -f k8s/ -n $KUBE_NAMESPACE_STG - kubectl rollout status deployment/nutriflow-backend -n $KUBE_NAMESPACE_STG --timeout=120s environment: name: staging url: https://staging.nutriflow.app only: [develop] deploy:production: <<: *kube_template stage: deploy script: - kubectl apply -f k8s/ -n $KUBE_NAMESPACE_PROD - kubectl rollout status deployment/nutriflow-backend -n $KUBE_NAMESPACE_PROD --timeout=180s environment: name: production url: https://app.nutriflow.app when: manual only: [main] # ── STAGE: NOTIFY ────────────────────────────────────────────── notify:slack: stage: notify image: alpine/curl:latest script: - | STATUS="✅ Pipeline #$CI_PIPELINE_ID passed" curl -X POST -H 'Content-type: application/json' --data "{\"text\":\"$STATUS · $CI_COMMIT_TITLE\"}" $SLACK_WEBHOOK when: always only: [main, develop]