Skip to content

Merge branch 'dev'

Merge branch 'dev' #1

Workflow file for this run

name: CI/CD
on:
# Roda em PRs para master e em pushes (merge) para master
pull_request:
branches: [ "master" ]
push:
branches: [ "master" ]
workflow_dispatch:
# Permissões mínimas + permissão para publicar pacotes no GHCR
permissions:
contents: read
packages: write
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
tests:
name: Tests
runs-on: ubuntu-latest
steps:
# Baixa o código
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0 # melhor para versionamento (tags/commits)
# Configura Java 21 (Temurin) para testes
- name: Set up Java 21 (Temurin)
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
# Configura cache do Gradle automaticamente
- name: Setup Gradle (with caching)
uses: gradle/actions/setup-gradle@v3
# Garante permissão de execução para o wrapper
- name: Make Gradle wrapper executable
run: chmod +x gradlew
# Executa a suíte de testes
- name: Run unit tests
run: ./gradlew --no-daemon clean test
# Publica relatórios de testes sempre, mesmo em caso de falha
- name: Upload test reports (always)
if: always()
uses: actions/upload-artifact@v4
with:
name: test-reports
path: |
build/test-results/test
build/reports/tests/test
build_and_publish:
name: Build, Docker and Push
runs-on: ubuntu-latest
needs: tests # Só executa se os testes passarem
if: ${{ needs.tests.result == 'success' }}
env:
# Nome base das imagens (pode ajustar conforme necessidade)
APP_NAME: espacogeek-backend
DB_IMAGE_GHCR: ghcr.io/${{ github.repository_owner }}/espacogeek-db
# Variáveis do .env (use Secrets no GitHub Actions)
SPRING_DATASOURCE_URL: ${{ secrets.SPRING_DATASOURCE_URL }}
SPRING_DATASOURCE_USERNAME: ${{ secrets.SPRING_DATASOURCE_USERNAME }}
SPRING_DATASOURCE_PASSWORD: ${{ secrets.SPRING_DATASOURCE_PASSWORD }}
SPRING_MVC_CORS_ALLOWED_ORIGINS: ${{ secrets.SPRING_MVC_CORS_ALLOWED_ORIGINS }}
SECURITY_JWT_ISSUER: ${{ secrets.SECURITY_JWT_ISSUER }}
SECURITY_JWT_EXPIRATION_MS: ${{ secrets.SECURITY_JWT_EXPIRATION_MS }}
SECURITY_JWT_SECRET: ${{ secrets.SECURITY_JWT_SECRET }}
SAMESITE_WHEN_SAME_SITE: ${{ secrets.SAMESITE_WHEN_SAME_SITE }}
ALLOWED_ORIGINS: ${{ secrets.ALLOWED_ORIGINS }}
MAIL_HOST: ${{ secrets.MAIL_HOST }}
MAIL_PORT: ${{ secrets.MAIL_PORT }}
MAIL_USERNAME: ${{ secrets.MAIL_USERNAME }}
MAIL_PASSWORD: ${{ secrets.MAIL_PASSWORD }}
APP_NAME_ENV: ${{ secrets.APP_NAME }}
FRONTEND_URL: ${{ secrets.FRONTEND_URL }}
steps:
# Baixa o código (com histórico completo para gerar versões)
- name: Check out code
uses: actions/checkout@v4
with:
fetch-depth: 0
# Configura Java 21 (Temurin) para build do WAR
- name: Set up Java 21 (Temurin)
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
# Configura cache do Gradle para builds
- name: Setup Gradle (with caching)
uses: gradle/actions/setup-gradle@v3
# Garante permissão de execução para o wrapper (em runners Linux)
- name: Make Gradle wrapper executable
run: chmod +x gradlew
# Lê a versão do projeto definida no build.gradle (project.version)
- name: Read Gradle project version
id: gradle_version
shell: bash
run: |
echo "version=$(./gradlew -q properties | sed -n 's/^version: \(.*\)$/\1/p')" >> "$GITHUB_OUTPUT"
# Gera tags de versão para as imagens Docker e artefatos
# - Em PR: pr-<numero>-<sha-curta>, v<versao>-pr-<numero>
# - Em push para master: latest, sha-<sha-curta>, <yyyyMMdd>, v<versao>
- name: Compute version tags
id: vars
shell: bash
run: |
set -euo pipefail
SHORT_SHA="$(git rev-parse --short HEAD)"
DATE_TAG="$(date +%Y%m%d)"
VERSION="${{ steps.gradle_version.outputs.version }}"
if [[ "${GITHUB_EVENT_NAME}" == "pull_request" ]]; then
PR_NUMBER="${{ github.event.pull_request.number }}"
TAGS="pr-${PR_NUMBER}-${SHORT_SHA},v${VERSION}-pr-${PR_NUMBER}"
SHOULD_PUSH="false" # não faz push em PRs por padrão
else
# push para master
# Inclui tag 'last-release' (Docker não permite espaço em tags)
TAGS="latest,last-release,sha-${SHORT_SHA},${DATE_TAG},v${VERSION}"
SHOULD_PUSH="true"
fi
echo "short_sha=${SHORT_SHA}" >> "$GITHUB_OUTPUT"
echo "date_tag=${DATE_TAG}" >> "$GITHUB_OUTPUT"
echo "tags_csv=${TAGS}" >> "$GITHUB_OUTPUT"
echo "should_push=${SHOULD_PUSH}" >> "$GITHUB_OUTPUT"
# Prepara Docker Buildx e cache de camadas
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# Login no GHCR (usa GITHUB_TOKEN)
- name: Login to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Normaliza as tags calculadas em formato multilinha para o docker/buildx
- name: Prepare tag list (multiline)
id: tags
shell: bash
run: |
IFS=',' read -ra T <<< "${{ steps.vars.outputs.tags_csv }}"
printf "jvm_tags<<EOF\n" >> "$GITHUB_OUTPUT"
for tag in "${T[@]}"; do
# Usa APP_NAME como nome da imagem JVM
echo "ghcr.io/${{ github.repository_owner }}/${{ env.APP_NAME }}:$tag" >> "$GITHUB_OUTPUT"
done
printf "EOF\n" >> "$GITHUB_OUTPUT"
printf "native_tags<<EOF\n" >> "$GITHUB_OUTPUT"
for tag in "${T[@]}"; do
# Usa sufixo '-native' para diferenciar imagem native (ajuste se necessário)
echo "ghcr.io/${{ github.repository_owner }}/${{ env.APP_NAME }}-native:$tag" >> "$GITHUB_OUTPUT"
done
printf "EOF\n" >> "$GITHUB_OUTPUT"
printf "db_tags<<EOF\n" >> "$GITHUB_OUTPUT"
for tag in "${T[@]}"; do
echo "${{ env.DB_IMAGE_GHCR }}:$tag" >> "$GITHUB_OUTPUT"
done
printf "EOF\n" >> "$GITHUB_OUTPUT"
# Constrói imagem Docker da aplicação rodando na JVM usando Dockerfile existente
- name: Build JVM Docker image
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.jvm
platforms: linux/amd64
push: ${{ steps.vars.outputs.should_push == 'true' && github.event_name == 'push' }}
tags: ${{ steps.tags.outputs.jvm_tags }}
labels: |
org.opencontainers.image.version=${{ steps.gradle_version.outputs.version }}
org.opencontainers.image.revision=${{ steps.vars.outputs.short_sha }}
org.opencontainers.image.source=https://github.com/${{ github.repository }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Constrói imagem Docker da aplicação como Native Image (usa Dockerfile existente)
- name: Build Native Docker image
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.native
platforms: linux/amd64
push: ${{ steps.vars.outputs.should_push == 'true' && github.event_name == 'push' }}
tags: ${{ steps.tags.outputs.native_tags }}
labels: |
org.opencontainers.image.version=${{ steps.gradle_version.outputs.version }}
org.opencontainers.image.revision=${{ steps.vars.outputs.short_sha }}
org.opencontainers.image.source=https://github.com/${{ github.repository }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Cria um Dockerfile simples para o banco (baseado em MySQL oficial)
- name: Create DB Dockerfile (MySQL base)
run: |
mkdir -p docker
cat > docker/Dockerfile.db << 'EOF'
FROM mysql:8.0
# Ajustes opcionais de configuração poderiam ser adicionados aqui (volumes, conf, envs, etc.)
EOF
# Constrói imagem do banco de dados a partir do Dockerfile.db
- name: Build DB Docker image (MySQL)
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile.db
platforms: linux/amd64
push: ${{ steps.vars.outputs.should_push == 'true' && github.event_name == 'push' }}
tags: ${{ steps.tags.outputs.db_tags }}
labels: |
org.opencontainers.image.version=${{ steps.gradle_version.outputs.version }}
org.opencontainers.image.revision=${{ steps.vars.outputs.short_sha }}
org.opencontainers.image.source=https://github.com/${{ github.repository }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Deploy to Hostinger via SSH (expects secrets: HOSTINGER (private key), HOSTINGER_HOST, HOSTINGER_USER, optional HOSTINGER_PORT)
- name: Deploy to Hostinger via SSH
uses: appleboy/ssh-action@v0.1.9
if: ${{ needs.tests.result == 'success' && steps.vars.outputs.should_push == 'true' && github.event_name == 'push' }}
with:
host: ${{ secrets.HOSTINGER_HOST }}
username: ${{ secrets.HOSTINGER_USER }}
key: ${{ secrets.HOSTINGER }}
port: ${{ secrets.HOSTINGER_PORT }}
script: |
set -e
docker pull
MAIL_USERNAME=${{ secrets.MAIL_USERNAME }}
MAIL_PASSWORD=${{ secrets.MAIL_PASSWORD }}
APP_NAME=${{ secrets.APP_NAME }}
FRONTEND_URL=${{ secrets.FRONTEND_URL }}
EOF
docker run -d --name espacogeek \
-p 8080:8080 \
--restart unless-stopped \
--env-file .env.espacogeek \
ghcr.io/${{ github.repository_owner }}/espacogeek-backend:latest
# (Opcional) remove arquivo após subir o container (mantém apenas no container)
rm -f .env.espacogeek
# Resumo final com as tags geradas
- name: Summary
if: always()
run: |
echo "Project version: ${{ steps.gradle_version.outputs.version }}"
echo "Tags geradas: ${{ steps.vars.outputs.tags_csv }}"
echo "Push habilitado: ${{ steps.vars.outputs.should_push }}"