feat: dockerize and auto-deploy on push
Build and Push Docker Image / build (push) Successful in 55s

Multi-stage image (bun build, nginx serving the SPA with history
fallback and a runtime-resolved /api proxy to the schdlr service) and
a Gitea Actions workflow that pushes to the registry and triggers the
vemmarcar deploy webhook on kauai, mirroring the up-track pipeline.
This commit is contained in:
Alexandre Possebom
2026-07-28 19:40:09 -03:00
parent 1d093d2d57
commit ddd01a461f
4 changed files with 150 additions and 0 deletions
+5
View File
@@ -0,0 +1,5 @@
node_modules
dist
.env
*.log
.DS_Store
+98
View File
@@ -0,0 +1,98 @@
name: Build and Push Docker Image
on:
push:
branches:
- master
tags:
- '*'
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Record start time
run: echo "BUILD_START=$(date +%s)" >> $GITHUB_ENV
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to Gitea Container Registry
uses: docker/login-action@v3
with:
registry: git.possebom.com
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: git.possebom.com/${{ gitea.repository }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=raw,value=latest,enable=${{ gitea.ref == 'refs/heads/master' }}
- name: Build and push
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
- name: Trigger deploy webhook
run: |
echo "Calling webhook at http://10.2.0.100:9024/hooks/deploy-vemmarcar"
HTTP_CODE=$(curl -sv -o /tmp/webhook-response.txt -w "%{http_code}" \
-X POST \
-H "X-Webhook-Token: 1c3312f18fb477f609c3f2d1e1837026260c04f57d64299a3d4a4f411eec5ceb" \
http://10.2.0.100:9024/hooks/deploy-vemmarcar 2>&1 | tee /tmp/webhook-debug.txt | tail -1)
echo "--- Response body ---"
cat /tmp/webhook-response.txt || true
echo ""
echo "--- HTTP code: $HTTP_CODE ---"
if [ "$HTTP_CODE" != "200" ]; then
echo "--- Debug output ---"
cat /tmp/webhook-debug.txt || true
exit 1
fi
- name: Notify Telegram
if: always()
run: |
STATUS="${{ job.status }}"
if [ "$STATUS" = "success" ]; then
EMOJI="✅"
else
EMOJI="❌"
fi
BUILD_END=$(date +%s)
DURATION=$((BUILD_END - BUILD_START))
MINUTES=$((DURATION / 60))
SECONDS=$((DURATION % 60))
if [ $MINUTES -gt 0 ]; then
TIME_STR="${MINUTES}m ${SECONDS}s"
else
TIME_STR="${SECONDS}s"
fi
SHORT_SHA="${{ gitea.sha }}"
SHORT_SHA="${SHORT_SHA:0:7}"
MESSAGE="${EMOJI} *Build ${STATUS}*
📦 *Repo:* ${{ gitea.repository }}
🔀 *Branch:* ${{ gitea.ref_name }}
👤 *Author:* ${{ gitea.actor }}
📝 *Commit:* \`${SHORT_SHA}\`
⏱️ *Tempo:* ${TIME_STR}"
curl -s -X POST "https://api.telegram.org/bot${{ secrets.TELEGRAM_TOKEN }}/sendMessage" \
-d chat_id="${{ secrets.TELEGRAM_CHAT_ID }}" \
-d parse_mode="Markdown" \
-d text="$MESSAGE"
+11
View File
@@ -0,0 +1,11 @@
FROM oven/bun:1 AS build
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
COPY . .
RUN bun run build
FROM nginx:alpine
COPY nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
+36
View File
@@ -0,0 +1,36 @@
# Serve a SPA e encaminha /api pro backend (serviço "schdlr" na rede do
# compose). O fallback pro index.html é o que faz /agendar/x e /painel
# funcionarem em acesso direto/refresh.
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.html;
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;
location /api/ {
# proxy_pass via variável: o nome "schdlr" é resolvido em runtime pelo
# DNS do Docker (127.0.0.11), então o nginx sobe e sobrevive mesmo com
# o backend fora do ar; hostname fixo aqui derruba o container inteiro
# na inicialização se o nome ainda não resolver.
resolver 127.0.0.11 valid=30s;
set $backend http://schdlr:3000;
proxy_pass $backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Assets do Vite têm hash no nome: cache longo é seguro.
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location / {
try_files $uri /index.html;
}
}