Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
124 lines
4.9 KiB
YAML
124 lines
4.9 KiB
YAML
name: CI
|
||
|
||
# Documentação e configuração de ferramenta não mudam nada que a suíte teste.
|
||
# Na main não roda por push: o release.yml é quem a chama, e só quando a imagem
|
||
# precisa ser reconstruída; rodar nos dois repetiria a mesma suíte no mesmo commit.
|
||
# Sem gatilho de pull_request: o push da branch já valida o mesmo commit, e os
|
||
# dois juntos rodariam tudo duas vezes (o repositório não recebe PR de fork).
|
||
#
|
||
# A imagem é construída aqui uma única vez, em arm64 (a arquitetura do servidor),
|
||
# testada e publicada como inputs-<hash>. Ao fazer o merge, o release encontra
|
||
# essa tag e só aplica os nomes novos, sem rodar nem construir nada de novo.
|
||
on:
|
||
push:
|
||
branches-ignore: [main]
|
||
paths-ignore: ['**.md', 'LICENSE', '.claude/**', '.superset/**', '.wolf/**', 'scripts/release-notes.sh']
|
||
workflow_call:
|
||
|
||
permissions:
|
||
contents: read
|
||
|
||
concurrency:
|
||
group: ci-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
jobs:
|
||
verificar:
|
||
name: Lint e auditorias
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 15
|
||
env:
|
||
# O Puppeteer só é usado em scripts locais (slides, capturas); não precisa do Chrome na CI.
|
||
PUPPETEER_SKIP_DOWNLOAD: "true"
|
||
NEXT_TELEMETRY_DISABLED: "1"
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
- uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 22
|
||
cache: npm
|
||
|
||
- run: npm ci
|
||
|
||
# eslint + auditoria do design system (tokens, contraste AAA) + auditoria de páginas
|
||
- run: npm run check
|
||
|
||
# Trivy roda pela imagem oficial: o trivy-action clona o repositório do Trivy
|
||
# do mesmo servidor do workflow, que aqui é o Gitea, e não o GitHub.
|
||
# O workspace do job é um volume que o daemon não enxerga, então os arquivos
|
||
# entram no container com `docker cp` em vez de `-v`.
|
||
seguranca:
|
||
name: Trivy (dependências e segredos)
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
- name: Repositório
|
||
run: |
|
||
cid=$(docker create --network host -v trivy-cache:/root/.cache/ -w /src aquasec/trivy:0.70.0 \
|
||
fs --scanners vuln,secret,misconfig --severity HIGH,CRITICAL --exit-code 1 .)
|
||
docker cp . "$cid:/src"
|
||
docker start -a "$cid"
|
||
status=$(docker inspect -f '{{.State.ExitCode}}' "$cid")
|
||
docker rm "$cid" >/dev/null
|
||
exit "$status"
|
||
|
||
# Só começa depois das verificações baratas: um lint quebrado não gasta um
|
||
# build de imagem. Roda no runner arm64, o mesmo tipo do servidor, então o
|
||
# que é escaneado e testado é a imagem que vai ao ar.
|
||
imagem:
|
||
name: Imagem Docker (linux/arm64)
|
||
needs: [verificar, seguranca]
|
||
runs-on: ubuntu-24.04-arm
|
||
env:
|
||
REGISTRY: git.lucasrguerra.dev.br
|
||
steps:
|
||
- uses: actions/checkout@v4
|
||
|
||
# Conteúdo já publicado (re-push, tag num commit já validado): nada a fazer.
|
||
- id: plano
|
||
run: scripts/plano-imagem.sh "$REGISTRY" "${{ gitea.repository }}" >> "$GITHUB_OUTPUT"
|
||
|
||
- if: ${{ steps.plano.outputs.reuse != 'true' }}
|
||
uses: docker/login-action@v4
|
||
with:
|
||
registry: ${{ env.REGISTRY }}
|
||
username: ${{ gitea.actor }}
|
||
password: ${{ secrets.REGISTRY_TOKEN }}
|
||
|
||
# `docker build` simples, no daemon persistente do runner: as camadas e os
|
||
# cache mounts do Dockerfile (npm e compilação do Next) sobrevivem entre
|
||
# execuções. Um buildx criaria um BuildKit novo, e vazio, a cada job.
|
||
- name: Build
|
||
if: ${{ steps.plano.outputs.reuse != 'true' }}
|
||
run: docker build -t espdocs:ci .
|
||
|
||
- name: Trivy na imagem
|
||
if: ${{ steps.plano.outputs.reuse != 'true' }}
|
||
run: |
|
||
docker run --rm --network host -v trivy-cache:/root/.cache/ -e DOCKER_HOST=tcp://127.0.0.1:2375 aquasec/trivy:0.70.0 \
|
||
image --severity HIGH,CRITICAL --exit-code 1 espdocs:ci
|
||
|
||
# Rotas por idioma, redirects e regras do livro (scripts/smoke-imagem.sh).
|
||
# Um curl só na raiz não basta: ela redireciona, e uma página interna
|
||
# quebrada ainda passaria.
|
||
- name: A imagem sobe e responde
|
||
if: ${{ steps.plano.outputs.reuse != 'true' }}
|
||
run: |
|
||
docker run -d --name espdocs-ci --network host -e PORT=3999 espdocs:ci
|
||
status=0
|
||
scripts/smoke-imagem.sh http://127.0.0.1:3999 || status=1
|
||
docker logs espdocs-ci | tail -15
|
||
# O Next registra falhas de render no log mesmo quando responde.
|
||
if docker logs espdocs-ci 2>&1 | grep -q '⨯'; then echo "O servidor registrou erro de render"; status=1; fi
|
||
docker rm -f espdocs-ci >/dev/null
|
||
exit "$status"
|
||
|
||
# Passou em tudo: publica a mesma imagem que foi testada, sem reconstruir.
|
||
- name: Publica inputs-<hash>
|
||
if: ${{ steps.plano.outputs.reuse != 'true' }}
|
||
run: |
|
||
tag="${{ steps.plano.outputs.image }}:inputs-${{ steps.plano.outputs.inputs }}"
|
||
docker tag espdocs:ci "$tag"
|
||
docker push "$tag"
|