Integração Contínua (CI/CD)

Como funcionam os pipelines no GitLab para lint, testes, build, release, imagens e documentação.

Integração Contínua (CI/CD)

Este guia explica o pipeline do GitLab: lint → test → build → release → image_create → create-pages. Também lista as variáveis necessárias e como acionar cada etapa.


1) Estrutura geral do pipeline

cache:
  paths:
    - node_modules

stages:
  - lint
  - test
  - build
  - release
  - image_create
  - create-pages

lint-job:
  image: $CI_REGISTRY/ademir/node-custom:latest
  stage: lint
  script:
    - ln -s /ci-modules/backend_node_modules backend/node_modules
    - cd backend
    - pnpm lint
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

test-job:
  image: $CI_REGISTRY/ademir/node-custom:latest
  stage: test
  script:
    - ln -s /ci-modules/backend_node_modules backend/node_modules
    - cd backend
    - pnpm exec tsc && pnpm exec jest --ci --forceExit --detectOpenHandles --runInBand --silent --verbose=false
  variables:
    NODE_ENV: testing
    DB_SGBD: ${DB_SGBD}
    DB_USER: ${DB_USER}
    DB_PASSWORD:  ${DB_PASSWORD}
    DB_HOST: ${DB_HOST}
    DB_PORT: ${DB_PORT}
    DB_NAME: ${DB_NAME}
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

build-job:
  image: $CI_REGISTRY/ademir/node-custom:latest
  stage: build
  script:
    - ln -s /ci-modules/frontend_node_modules frontend/node_modules
    - cd frontend
    - pnpm run build
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'

create_release:
  stage: release
  image: $CI_REGISTRY/ademir/release-cli
  script:
    - |
      LAST_TAG=$(git tag --sort=-creatordate | sed -n 2p)
      if [ -z "$LAST_TAG" ]; then
        git log --pretty=format:"%s (%an)" | grep -v "^Merge branch" | sed 's/^/- /' > release_notes.md
      else
        git log "${LAST_TAG}"..HEAD --pretty=format:"%s (%an)" | grep -v "^Merge branch" | sed 's/^/- /' > release_notes.md
      fi
      echo "Versão: $CI_COMMIT_TAG" > full_release.md
      echo "" >> full_release.md
      echo "Mudanças:" >> full_release.md
      cat release_notes.md >> full_release.md
  release:
    tag_name: $CI_COMMIT_TAG
    name: "Release $CI_COMMIT_TAG"
    description: full_release.md
  rules:
    - if: '$CI_COMMIT_TAG'

image_create:
  stage: image_create
  image:
    name: $CI_REGISTRY/ademir/buildah
  script:
    - buildah login -u "$HARBOR_LOGIN" -p "$HARBOR_PASSWORD" "$CI_REGISTRY"
    - buildah build --layers --build-arg NEXT_PUBLIC_API_BASE_URL="$NEXT_PUBLIC_API_BASE_URL" --file frontend/Containerfile --tag $CI_REGISTRY/ademir/frontend:$CI_COMMIT_TAG --cache-from=$CI_REGISTRY/ademir/frontend --cache-to=$CI_REGISTRY/ademir/frontend frontend
    - buildah push harbor.c3sl.ufpr.br/ademir/frontend:$CI_COMMIT_TAG
    - buildah build --layers --file backend/Containerfile --tag harbor.c3sl.ufpr.br/ademir/backend:$CI_COMMIT_TAG --cache-from=$CI_REGISTRY/ademir/backend --cache-to=$CI_REGISTRY/ademir/backend backend
    - buildah push harbor.c3sl.ufpr.br/ademir/backend:$CI_COMMIT_TAG
  rules:
    - if: '$CI_COMMIT_TAG'

# deploy (k8s) — desativado
#deploy:
#  stage: deploy
#  image: bitnami/kubectl:latest
#  script:
#    - kubectl --kubeconfig $KUBECONFIG rollout restart deploy ademir -n ademir
#  rules:
#    - if: '$CI_COMMIT_TAG'

create-pages:
  image: hugomods/hugo:ci
  variables:
    GIT_SUBMODULE_STRATEGY: recursive
  before_script:
    - cd docs
    - npm i -D postcss postcss-cli autoprefixer
  script:
    - hugo --minify -D -d public
    - mv public ..
  pages: true
  artifacts:
    paths:
      - public
  rules:
    - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
      changes:
        - docs/**/*  
  environment: production

Observação: os blocos estão sem linguagem para manter compatibilidade com a diretriz de apenas blocos de código Markdown.


2) Quando cada estágio roda

  • lint, test, build → executam em Merge Requests (rules: if: $CI_PIPELINE_SOURCE == "merge_request_event").
  • release e image_create → executam somente em tag (rules: if: $CI_COMMIT_TAG).
  • create-pages (Hugo) → executa na branch padrão (ex.: develop) quando houver mudanças em docs/.

Disparo prático

  • Abrir MR → roda lint, test, build.
  • Criar tag (ex.: v1.2.3) → roda create_release e image_create (gera release e imagens e faz push no registry).
  • Commits em docs/ na branch padrão → roda create-pages e publica a documentação.

3) Variáveis de ambiente (CI/CD) necessárias

Crie/atualize em Settings → CI/CD → Variables no GitLab:

Backend / Testes

  • DB_SGBD
  • DB_USER
  • DB_PASSWORD
  • DB_HOST
  • DB_PORT
  • DB_NAME

Release / Imagens

  • HARBOR_LOGIN — login no registry
  • HARBOR_PASSWORD — senha/token do registry
  • NEXT_PUBLIC_API_BASE_URL — base URL injetada no build do frontend
  • (opcional) CI_REGISTRY, CI_REGISTRY_USER, CI_REGISTRY_PASSWORD se o runner exigir login explícito

Outras

  • CI_DEFAULT_BRANCH (já fornecida pelo GitLab)
  • KUBECONFIG (se reativar o job de deploy)

Boas práticas: marque variáveis sensíveis como masked e protected; ligue Protect para usar apenas em branches/tags protegidas.


4) Detalhes de cada job

lint-job

  • Usa imagem Node custom.
  • Cria symlink para backend/node_modules apontando para /ci-modules/backend_node_modules (cache aquecido da imagem).
  • Roda pnpm lint no diretório backend.

test-job

  • Mesmo setup de node_modules do lint-job.
  • Compila TypeScript (pnpm exec tsc) e executa testes com Jest/Supertest.
  • Injeta variáveis de banco para testes.

build-job

  • Prepara frontend/node_modules via symlink.
  • Executa pnpm run build em frontend (Next.js + Tailwind + shadcn).

create_release

  • Gera release notes a partir do git log (desde a última tag) e cria um Release associado à tag atual ($CI_COMMIT_TAG).

image_create

  • Autentica no registry (buildah login).
  • Frontend: build da imagem passando NEXT_PUBLIC_API_BASE_URL por --build-arg; faz push para harbor.c3sl.ufpr.br/ademir/frontend:$CI_COMMIT_TAG.
  • Backend: build e push da imagem harbor.c3sl.ufpr.br/ademir/backend:$CI_COMMIT_TAG.
  • Usa camadas em cache (--layers, --cache-from/--cache-to).

create-pages

  • Usa imagem do Hugo.
  • Instala postcss, postcss-cli e autoprefixer para o tema.
  • Gera site (hugo --minify -D) e publica artefatos para Pages.

5) Fluxos típicos

A) Verificação de MR

  1. Abrir MR → pipeline executa lint, test, build.
  2. Corrigir problemas (se houver) → push para a mesma branch reexecuta as etapas.

B) Criar release e imagens

  1. Marcar uma tag (ex.: v1.2.3).
  2. Pipeline executa create_release e image_create.
  3. Conferir release no GitLab e imagens no registry Harbor.

C) Publicar documentação

  1. Subir commits na branch padrão alterando docs/.
  2. Pipeline executa create-pages e publica o site (GitLab Pages).

6) Troubleshooting

  • lint/test falhando: rode localmente pnpm lint e pnpm exec jest no diretório correspondente e verifique versões do Node.
  • Falha no build do frontend: cheque dependências (pnpm install) e teste pnpm build localmente.
  • Erro no image_create: valide HARBOR_LOGIN/HARBOR_PASSWORD e permissão de push no registry. Confirme o nome das imagens e tags.
  • create-pages não dispara: confirme a branch padrão e se houve mudanças dentro de docs/.
  • Variáveis ausentes: adicione em CI/CD Variables (acessível apenas pra mantainers) e proteja-as quando necessário.

7) Boas práticas

  • Mantenha o pipeline rápido (cache eficiente, jobs paralelos quando possível).
  • Use tags semânticas (ex.: vX.Y.Z) para releases.
  • Centralize secrets apenas no CI/CD; não versionar .env reais.
Última modificação September 15, 2025: Issue #358: FIX input cleanups after submition (b78e42a)