Drop the pull_request trigger (the branch push already validates the commit), drop the second npm run build from the lint job (the image build compiles it), and build the image on arm64 after the cheap checks pass. The CI publishes it as inputs-<hash>, so the merge to main only re-tags it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
128 lines
4.7 KiB
YAML
128 lines
4.7 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/setup-buildx-action@v4
|
|
|
|
- if: ${{ steps.plano.outputs.reuse != 'true' }}
|
|
uses: docker/login-action@v4
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ gitea.actor }}
|
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
|
|
|
- name: Build
|
|
if: ${{ steps.plano.outputs.reuse != 'true' }}
|
|
uses: docker/build-push-action@v7
|
|
with:
|
|
context: .
|
|
platforms: linux/arm64
|
|
load: true
|
|
tags: espdocs:ci
|
|
cache-from: type=registry,ref=${{ steps.plano.outputs.image }}:buildcache
|
|
cache-to: type=registry,ref=${{ steps.plano.outputs.image }}:buildcache,mode=max
|
|
|
|
- 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
|
|
|
|
- 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
|
|
for i in $(seq 1 30); do
|
|
curl -fsS http://127.0.0.1:3999/ >/dev/null && ok=1 && break
|
|
sleep 2
|
|
done
|
|
docker logs espdocs-ci | tail -5
|
|
docker rm -f espdocs-ci >/dev/null
|
|
test "${ok:-0}" = 1
|
|
|
|
# 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"
|