From 3a1a095e97841f24d904895987b90ebe47c9fce9 Mon Sep 17 00:00:00 2001 From: Lucas Rayan Date: Sun, 1 Nov 2026 10:33:40 -0300 Subject: [PATCH] ci: a real smoke test for the localized routes, and a single redirect from the root Co-Authored-By: Claude Sonnet 5.5 --- .gitea/workflows/ci.yml | 15 ++++++----- CHANGELOG.md | 11 ++++++++ middleware.js | 2 +- scripts/smoke-imagem.sh | 57 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 7 deletions(-) create mode 100755 scripts/smoke-imagem.sh diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 723abc3..1480eee 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -99,17 +99,20 @@ jobs: 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 - 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 + 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 - test "${ok:-0}" = 1 + exit "$status" # Passou em tudo: publica a mesma imagem que foi testada, sem reconstruir. - name: Publica inputs- diff --git a/CHANGELOG.md b/CHANGELOG.md index e7cd10d..1afb7df 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,17 @@ Tudo o que muda de relevante no ESPDocs está aqui. O formato segue o - Conjunto de dados canônicos em `data/pt/` (`series.json`, `frameworks.json`, `conexoes/*.json`) e módulos em `lib/data/pt/` (`glossario.js`, `diagnostico.js`, `componentes.js`, `topicos.js`) com carregadores por locale em `lib/data/index.js`. - Script automatizado de validação `check:i18n` integrado ao `npm run check`, verificando paridade de chaves, ausência de valores vazios e garantia estrita de ausência de referências ao livro fora do português. +### Alterado + +- O teste de subida da imagem na CI virou `scripts/smoke-imagem.sh`: confere as + rotas de cada idioma, a negociação de `Accept-Language`, os redirects 308 das + URLs antigas, o 404 do livro fora do português e a metadata no ``, e + falha se o servidor registrar erro de render. O `curl` só na raiz deixou passar + uma home quebrada. +- A metadata (título, `canonical`, Open Graph) sempre sai no `` do HTML + inicial, para qualquer cliente, como já era antes do i18n. +- A raiz `/` redireciona direto para `/`, em um salto só. + ## [1.1.0] - 2026-11-01 ### Adicionado diff --git a/middleware.js b/middleware.js index cf26897..4609dd3 100644 --- a/middleware.js +++ b/middleware.js @@ -67,7 +67,7 @@ export default function middleware(request) { // 1. Raiz: negociação de idioma (307) if (pathname === "/") { const targetLocale = resolveRootLocale(request); - const url = new URL(`/${targetLocale}/`, request.url); + const url = new URL(`/${targetLocale}`, request.url); url.search = search; const response = NextResponse.redirect(url, 307); response.headers.set("Vary", "Accept-Language, Cookie"); diff --git a/scripts/smoke-imagem.sh b/scripts/smoke-imagem.sh new file mode 100755 index 0000000..58b7436 --- /dev/null +++ b/scripts/smoke-imagem.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# Teste de fumaça do servidor: rotas por idioma, redirects e regras do livro. +# +# scripts/smoke-imagem.sh http://127.0.0.1:3999 +# +# Cada falha é impressa e o script sai com 1 no fim, para mostrar tudo de uma vez. +set -uo pipefail + +base=${1:?uso: smoke-imagem.sh } +falhas=0 + +# status [cabeçalho] +status() { + local got + got=$(curl -s -o /dev/null -w '%{http_code}' ${3:+-H "$3"} "$base$2") + [ "$got" = "$1" ] || { echo "FALHOU $2 ${3:-}: esperado $1, veio $got"; falhas=$((falhas + 1)); } +} + +# destino [cabeçalho] +destino() { + local out + out=$(curl -s -o /dev/null -w '%{http_code} %{redirect_url}' ${4:+-H "$4"} "$base$2") + [ "$out" = "$1 $base$3" ] || { echo "FALHOU $2 ${4:-}: esperado '$1 $3', veio '${out#* }'" ; falhas=$((falhas + 1)); } +} + +# O servidor leva alguns segundos para subir. +for _ in $(seq 1 30); do curl -fsS -o /dev/null "$base/pt" && break; sleep 2; done + +# Páginas que existem em todos os idiomas ativos (a home é a que mais depende do render no servidor). +for l in pt en es fr de zh-CN; do status 200 "/$l"; done +for p in /series /sobre /livro; do status 200 "/pt$p"; done + +# Negociação de idioma na raiz. +destino 307 / /pt 'Accept-Language: pt-BR,pt;q=0.9' +destino 307 / /es 'Accept-Language: es-MX,es;q=0.9,en;q=0.5' +destino 307 / /fr 'Accept-Language: fr-CA,fr;q=0.9' +destino 307 / /de 'Accept-Language: de-AT,de;q=0.8' +destino 307 / /zh-CN 'Accept-Language: zh-CN,zh;q=0.9' +destino 307 / /en 'Accept-Language: it-IT' +destino 307 / /pt 'Accept-Language: en;q=0.5,pt;q=0.9' +destino 307 / /es 'Cookie: NEXT_LOCALE=es' + +# URLs antigas (sem prefixo) eram em português. +destino 308 /series/ESP32-S3 /pt/series/ESP32-S3 'Accept-Language: en-US' +destino 308 /livro /pt/livro 'Accept-Language: en-US' + +# O livro existe só em português. +for l in en es fr de zh-CN; do status 404 "/$l/livro"; done + +# Metadata no inicial (title, canonical, hreflang), para qualquer cliente. +html=$(curl -s -A 'Mozilla/5.0 Chrome/130' "$base/pt/sobre") +head=${html%%*} +for marca in '' 'rel="canonical"'; do + case "$head" in *"$marca"*) ;; *) echo "FALHOU /pt/sobre: $marca fora do <head>"; falhas=$((falhas + 1));; esac +done + +exit $((falhas > 0))