feat(ci): deploy automático via Gitea Actions + rename branch para main
Some checks failed
Deploy / deploy (push) Failing after 1s

- .gitea/workflows/deploy.yml: push na main (paths do app/infra) ou
  disparo manual -> SSH no host -> make deploy + health check /api/health
- Makefile: alvo `deploy` (git reset --hard + up-wedding com build), BRANCH=main
- CLAUDE.md: documenta o fluxo de deploy e o setup de secrets

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Leandro Ronetto 2026-06-09 06:19:31 -03:00
parent 69ef304562
commit 98dcafdf26
3 changed files with 108 additions and 2 deletions

View File

@ -0,0 +1,69 @@
# Deploy automático do app wedding.
#
# A cada push na branch principal (ou disparo manual), conecta por SSH no host
# de produção e roda `make deploy`, que faz git reset --hard na branch + rebuild
# do app wedding (docker compose up -d --build).
#
# Por que SSH (e não rodar docker direto no runner):
# os arquivos .env (segredos do app) ficam só no host, fora do git. O host já
# tem o repo configurado, então o deploy é só atualizar o código e subir.
#
# Segredos necessários (Gitea: repo > Settings > Actions > Secrets):
# DEPLOY_HOST IP ou hostname do host de produção
# DEPLOY_USER usuário SSH (precisa rodar docker + ter o repo clonado)
# DEPLOY_SSH_KEY chave PRIVADA SSH (conteúdo completo, incl. cabeçalhos)
# DEPLOY_PATH caminho absoluto do repo no host (ex.: /opt/wedding-app)
# Variáveis opcionais (Gitea: ... > Variables):
# DEPLOY_PORT porta SSH (default 22)
name: Deploy
on:
push:
branches:
- main
paths:
# Só dispara quando algo que afeta o app/infra muda. Edição de docs
# (CLAUDE.md, README) não redeploya.
- "infra/wedding_photo/**"
- "Makefile"
- ".gitea/workflows/deploy.yml"
workflow_dispatch: {}
# Cancela um deploy em andamento se um novo push chegar.
concurrency:
group: deploy-wedding
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Configura chave SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
PORT="${{ vars.DEPLOY_PORT }}"
ssh-keyscan -p "${PORT:-22}" -H "${{ secrets.DEPLOY_HOST }}" >> ~/.ssh/known_hosts 2>/dev/null
- name: Deploy via SSH
run: |
PORT="${{ vars.DEPLOY_PORT }}"
ssh -i ~/.ssh/deploy_key -p "${PORT:-22}" \
"${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}" \
"set -e; cd '${{ secrets.DEPLOY_PATH }}'; make deploy BRANCH=main"
- name: Health check
run: |
PORT="${{ vars.DEPLOY_PORT }}"
# Espera o container ficar saudável e confere /health internamente.
ssh -i ~/.ssh/deploy_key -p "${PORT:-22}" \
"${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }}" \
"for i in \$(seq 1 15); do \
if docker exec wedding_app sh -c 'wget -qO- http://localhost:3000/api/health' >/dev/null 2>&1; then \
echo 'app OK'; exit 0; \
fi; \
echo \"aguardando app... (\$i/15)\"; sleep 4; \
done; \
echo 'app NAO respondeu'; docker logs --tail 50 wedding_app; exit 1"

View File

@ -274,6 +274,31 @@ docker exec -u git -it gitea gitea admin user change-password \
--username lronetto --password "$NEWPW"
```
### Deploy automático (CI/CD)
Workflow `.gitea/workflows/deploy.yml`. A cada push na branch principal
(`main`) que toque `infra/wedding_photo/**`, `Makefile` ou o
próprio workflow — ou disparo manual (`workflow_dispatch`) — o runner conecta
por **SSH no host** e roda `make deploy` (git reset --hard + `up-wedding` com
build), seguido de um health check em `/api/health`.
**Por que SSH e não docker direto no runner**: os `.env` (segredos do app)
ficam só no host, fora do git. O host já tem o repo configurado; o deploy só
atualiza o código e sobe.
Setup (1ª vez):
1. No host, garanta o repo clonado (ex.: `/opt/wedding-app`) e um usuário SSH
que rode docker e tenha acesso ao repo.
2. Gere um par de chaves SSH e adicione a **pública** no `~/.ssh/authorized_keys`
desse usuário.
3. Em Gitea → repo → **Settings → Actions → Secrets**, crie:
- `DEPLOY_HOST` — IP/hostname do host
- `DEPLOY_USER` — usuário SSH
- `DEPLOY_SSH_KEY` — a chave **privada** (conteúdo completo)
- `DEPLOY_PATH` — caminho do repo no host (ex.: `/opt/wedding-app`)
4. (Opcional) **Variables**: `DEPLOY_PORT` se o SSH não for 22.
`make deploy` aceita `BRANCH=` pra sobrescrever a branch deployada.
---
## 9. Gotchas conhecidos
@ -352,7 +377,7 @@ O `extra_hosts: host-gateway` pra `media.{DOMAIN_BASE}` faz o container resolver
Branches relevantes:
- `claude/wedding-qrcode-photos-C0PQt` (Cloudflare original)
- `claude/docker-vps-migration` (1ª migração Docker Node)
- `claude/python-backend` (atual; Python + restructure 3 stacks)
- `main` (atual; Python + restructure 3 stacks — renomeada de `claude/python-backend`)
---

View File

@ -3,9 +3,10 @@
down-main down-gitea down-wedding \
logs-main logs-gitea logs-wedding \
pull-main pull-gitea pull-wedding \
rebuild-wedding
rebuild-wedding deploy
NET := infra-net
BRANCH ?= main
DC_MAIN := docker compose -f infra/main/docker-compose.yml --env-file infra/main/.env
DC_GITEA := docker compose -f infra/gitea/docker-compose.yml --env-file infra/gitea/.env
DC_WEDDING := docker compose -f infra/wedding_photo/docker-compose.yml --env-file infra/wedding_photo/.env
@ -22,6 +23,7 @@ help:
@echo " make up-gitea Sobe só o gitea"
@echo " make up-wedding Build + up do app wedding"
@echo " make rebuild-wedding Force rebuild do app wedding"
@echo " make deploy git reset --hard + up-wedding (usado pelo CI)"
@echo " make down-{main,gitea,wedding}"
@echo " make logs-{main,gitea,wedding}"
@echo " make pull-{main,gitea,wedding}"
@ -54,6 +56,16 @@ rebuild-wedding: network
$(DC_WEDDING) build --no-cache
$(DC_WEDDING) up -d
# Deploy automático: atualiza o código e sobe só o app wedding com build.
# Chamado pelo workflow .gitea/workflows/deploy.yml via SSH no host.
# BRANCH pode ser sobrescrito: `make deploy BRANCH=main`
deploy: network
git fetch --all --prune
git checkout $(BRANCH)
git reset --hard origin/$(BRANCH)
$(DC_WEDDING) up -d --build
$(DC_WEDDING) ps
down-main:
$(DC_MAIN) down