diff --git a/.github/scripts/setup-docker-prune-cron.sh b/.github/scripts/setup-docker-prune-cron.sh
new file mode 100644
index 0000000..24f5e46
--- /dev/null
+++ b/.github/scripts/setup-docker-prune-cron.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+set -e
+
+CRON_CMD="0 3 * * 0 docker system prune -af --volumes > /var/log/docker-prune.log 2>&1"
+
+echo "[INFO] Configurando limpeza semanal do Docker via cron..."
+
+# Verifica se já existe a regra no cron do root
+if sudo crontab -l 2>/dev/null | grep -q "docker system prune -af --volumes"; then
+ echo "[INFO] Já existe uma regra de prune configurada no cron. Nada a fazer."
+else
+ # Adiciona a regra ao cron do root
+ (sudo crontab -l 2>/dev/null; echo "$CRON_CMD") | sudo crontab -
+ echo "[INFO] Cron configurado: limpeza semanal todo domingo às 03h."
+fi
+
+echo "[INFO] Você pode verificar o log em /var/log/docker-prune.log"
diff --git a/.github/scripts/start-preview.sh b/.github/scripts/start-preview.sh
index e3a577f..fc35d7d 100644
--- a/.github/scripts/start-preview.sh
+++ b/.github/scripts/start-preview.sh
@@ -2,30 +2,46 @@
set -e
PR_NUMBER=$1
-PORT=$((8000 + PR_NUMBER % 1000)) # porta única para cada PR
APP_NAME="simple-project-pr${PR_NUMBER}"
NGROK_NAME="ngrok-pr${PR_NUMBER}"
+HOST_PORT=$((8000 + PR_NUMBER))
+API_PORT=$((4040 + PR_NUMBER))
-echo "[INFO] Iniciando preview para PR #${PR_NUMBER} na porta ${PORT}"
+echo "[INFO] Iniciando preview para PR #${PR_NUMBER} na porta ${HOST_PORT}"
-# Se container já existe, remover para atualizar
-docker rm -f ${APP_NAME} || true
+# Garantir que não há containers anteriores
+docker rm -f ${APP_NAME} 2>/dev/null || true
+docker rm -f ${NGROK_NAME} 2>/dev/null || true
-# Build imagem docker
+# Build da imagem sem cache
+echo "[INFO] Build da imagem Docker..."
docker build -t ${APP_NAME}:latest .
-# Rodar container da app
-docker run -d --name ${APP_NAME} -p ${PORT}:8080 ${APP_NAME}:latest
-
-# Matar ngrok anterior se existir
-pkill -f "${NGROK_NAME}" || true
-
-# Rodar ngrok apontando para porta do container
-nohup ngrok http ${PORT} --name ${NGROK_NAME} > /tmp/${NGROK_NAME}.log 2>&1 &
-
-# Esperar ngrok subir e pegar URL
-sleep 5
-URL=$(curl --silent http://127.0.0.1:4040/api/tunnels | jq -r ".tunnels[] | select(.config.addr==\"http://localhost:${PORT}\") | .public_url")
-
-echo "[INFO] Preview URL: ${URL}"
-echo "${URL}"
+# Rodar o container da aplicação
+echo "[INFO] Subindo container da aplicação ${APP_NAME}..."
+docker run -d --name ${APP_NAME} -p ${HOST_PORT}:8080 ${APP_NAME}:latest
+
+# Rodar o container do ngrok expondo API na porta 4040+PR_NUMBER
+echo "[INFO] Subindo container do ngrok ${NGROK_NAME}..."
+docker run -d --name ${NGROK_NAME} \
+ -e NGROK_AUTHTOKEN="${NGROK_AUTHTOKEN}" \
+ -p ${API_PORT}:4040 \
+ ngrok/ngrok:latest http host.docker.internal:${HOST_PORT} > /tmp/${NGROK_NAME}.log 2>&1
+
+# Aguardar o ngrok iniciar e capturar a URL pela API
+echo "[INFO] Aguardando ngrok inicializar na porta ${API_PORT}..."
+for i in {1..10}; do
+ sleep 2
+ URL=$(curl -s http://127.0.0.1:${API_PORT}/api/tunnels | grep -o 'https://[0-9a-z]*\.ngrok-free\.app' | head -n 1 || true)
+ if [ -n "$URL" ]; then
+ break
+ fi
+done
+
+if [ -z "$URL" ]; then
+ echo "[ERRO] Não foi possível capturar a URL do Ngrok. Veja os logs em /tmp/${NGROK_NAME}.log"
+ exit 1
+fi
+
+echo "[INFO] URL pública gerada: $URL"
+echo "$URL"
diff --git a/.github/scripts/stop-preview.sh b/.github/scripts/stop-preview.sh
index 66e2e2b..861567a 100644
--- a/.github/scripts/stop-preview.sh
+++ b/.github/scripts/stop-preview.sh
@@ -7,8 +7,28 @@ NGROK_NAME="ngrok-pr${PR_NUMBER}"
echo "[INFO] Removendo preview para PR #${PR_NUMBER}"
-# Parar container e remover
-docker rm -f ${APP_NAME} || true
+# Se o container da aplicação existir mas estiver em estado de falha, mostrar logs antes de remover
+if docker ps -a --format '{{.Names}} {{.Status}}' | grep -q "${APP_NAME}"; then
+ STATUS=$(docker inspect -f '{{.State.Status}}' ${APP_NAME} || echo "desconhecido")
+ if [ "$STATUS" != "running" ]; then
+ echo "[WARN] Container ${APP_NAME} não está rodando (status: $STATUS). Exibindo últimos logs:"
+ docker logs --tail=100 ${APP_NAME} || true
+ fi
+fi
-# Matar ngrok correspondente
-pkill -f "${NGROK_NAME}" || true
+# Parar e remover container da aplicação
+docker rm -f ${APP_NAME} >/dev/null 2>&1 || true
+
+# Remover imagem associada ao PR (se existir)
+docker rmi -f ${APP_NAME}:latest >/dev/null 2>&1 || true
+
+# Parar e remover container do ngrok
+docker rm -f ${NGROK_NAME} >/dev/null 2>&1 || true
+
+# Extra: limpar eventuais containers órfãos do mesmo PR
+docker ps -a --format '{{.Names}}' | grep -E "${APP_NAME}|${NGROK_NAME}" | xargs -r docker rm -f || true
+
+# Extra: limpar eventuais imagens órfãs
+docker image prune -f >/dev/null 2>&1 || true
+
+echo "[INFO] Preview do PR #${PR_NUMBER} removido com sucesso."
diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml
index 0673b88..105465a 100644
--- a/.github/workflows/pr-preview.yml
+++ b/.github/workflows/pr-preview.yml
@@ -4,6 +4,10 @@ on:
pull_request:
types: [opened, synchronize, reopened, closed]
+permissions:
+ pull-requests: write
+ contents: read
+
jobs:
preview:
runs-on: self-hosted
@@ -12,23 +16,30 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- - name: Set up JDK 25
+ - name: Set up JDK 21
uses: actions/setup-java@v4
with:
- java-version: '25'
+ java-version: '21'
distribution: 'temurin'
- name: Build simple-project app
if: github.event.action != 'closed'
- run: ./mvnw clean package -DskipTests
+ run: |
+ chmod +x ./mvnw
+ ./mvnw clean package -DskipTests
- name: Start Preview (container + ngrok)
if: github.event.action != 'closed'
id: preview
+ env:
+ NGROK_AUTHTOKEN: ${{ secrets.NGROK_AUTHTOKEN }}
run: |
chmod +x .github/scripts/start-preview.sh
- URL=$(.github/scripts/start-preview.sh ${{ github.event.number }})
+ RAW_OUTPUT=$(.github/scripts/start-preview.sh ${{ github.event.number }})
+ URL=$(echo "$RAW_OUTPUT" | tail -n 1)
+ HOST_PORT=$((8000 + ${{ github.event.number }}))
echo "preview_url=$URL" >> $GITHUB_OUTPUT
+ echo "host_port=$HOST_PORT" >> $GITHUB_OUTPUT
- name: Comment PR with Preview URL
if: github.event.action != 'closed'
@@ -36,7 +47,8 @@ jobs:
with:
message: |
🚀 Preview da aplicação *simple-project* para este PR:
- ${{ steps.preview.outputs.preview_url }}
+ 🌐 URL pública (Ngrok): ${{ steps.preview.outputs.preview_url }}
+ 🖥️ Porta local usada no host: `${{ steps.preview.outputs.host_port }}`
_(Permanece ativo até o PR ser fechado ou manualmente removido)_
- name: Stop Preview on PR close
diff --git a/Dockerfile b/Dockerfile
index 695afa8..19a4621 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,5 +1,5 @@
-# Imagem base com JDK 25 (Temurin)
-FROM eclipse-temurin:25-jdk-alpine
+# Imagem base com JDK 21 (LTS estável)
+FROM eclipse-temurin:21-jdk-alpine
WORKDIR /app
diff --git a/pom.xml b/pom.xml
index 300b995..c130963 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
- 25
+ 21
@@ -62,3 +62,4 @@
+
diff --git a/src/main/java/com/trandreluis/simple_project/HomeController.java b/src/main/java/com/trandreluis/simple_project/HomeController.java
index c49c4e5..f1d87c6 100644
--- a/src/main/java/com/trandreluis/simple_project/HomeController.java
+++ b/src/main/java/com/trandreluis/simple_project/HomeController.java
@@ -9,7 +9,7 @@ public class HomeController {
@GetMapping({"/", "/home"})
public String home(Model model) {
- model.addAttribute("message", "Hello, World!");
+ model.addAttribute("message", "Hello, World! Now you see the Ngrok magic!");
return "home";
}
}
\ No newline at end of file
diff --git a/src/main/resources/templates/home.html b/src/main/resources/templates/home.html
index d16f6e3..8d81624 100644
--- a/src/main/resources/templates/home.html
+++ b/src/main/resources/templates/home.html
@@ -5,6 +5,6 @@
Home
-Hello, World!
+