fix(ci): tira o deploy da VPS deste fork do PR

A cerca de gatilhos reprova job que nao esta no mapa. Esse workflow e customizacao do fork e o proprio arquivo pede para nao ir ao upstream.
This commit is contained in:
Ian Couto
2026-09-20 12:12:16 -03:00
parent 4a12a366d3
commit b90c641ff4
3 changed files with 0 additions and 367 deletions
-121
View File
@@ -1,121 +0,0 @@
#!/usr/bin/env bash
# Atualiza ESTA VPS para o commit que o GitHub Actions acabou de publicar
# em ghcr.io/<dono>/…:develop. Não builda nada aqui — só puxa imagem pronta.
#
# Variáveis (vêm do job, não ficam no disco):
# GH_TOKEN GITHUB_TOKEN do job (login no GHCR + fetch do fork, se privado)
# GH_USER github.actor
# SHA commit que acabou de construir
# DONO dono do GHCR em minúsculas (ex.: iancouto)
#
# NÃO chame gravar_imagens: ela pinaria o namespace do upstream, que
# não é o registro deste fork.
set -euo pipefail
PROJECT_DIR="${PROJECT_DIR:-/root/deskcommcrm}"
SHA="${SHA:?falta SHA}"
DONO="${DONO:?falta DONO}"
GH_USER="${GH_USER:?falta GH_USER}"
GH_TOKEN="${GH_TOKEN:?falta GH_TOKEN}"
cleanup() {
docker logout ghcr.io >/dev/null 2>&1 || true
}
trap cleanup EXIT
cd "$PROJECT_DIR"
# Uma atualização por vez. O mesmo arquivo que o agent.sh usa: se alguém
# clicar em "Atualizar agora" no meio, o segundo espera ou recusa.
exec 9> "${PROJECT_DIR}/.update.lock"
if ! flock -n 9; then
echo "outro update já está rodando neste servidor — tente de novo em alguns minutos"
exit 1
fi
# shellcheck source=../../hostgator-setup-kit/_common.sh
source "${PROJECT_DIR}/hostgator-setup-kit/_common.sh"
enter_project
recusar_projeto_de_outra_arvore \
|| die "Atualização interrompida para não quebrar a instalação que está no ar."
step "Backup de segurança (antes de mexer no banco)"
if bash "${PROJECT_DIR}/hostgator-setup-kit/backup.sh"; then
c_grn "✓ backup feito"
else
c_ylw "⚠ o backup falhou — sigo, mas o ideal é ter um. Continuo em 5s."
sleep 5
fi
step "Login no registro de imagens"
printf '%s' "$GH_TOKEN" | docker login ghcr.io -u "$GH_USER" --password-stdin
step "Código deste commit"
# Repo público: fetch pela URL, sem token. Bearer no extraHeader faz o git
# cair no prompt de usuário na VPS (exit 128, "No such device or address").
GIT_TERMINAL_PROMPT=0 git fetch --depth 1 \
"https://github.com/${DONO}/DeskcommCRM.git" "$SHA"
git reset --hard FETCH_HEAD
# Relê o kit DEPOIS do reset: o _common.sh deste commit é o que vale.
# shellcheck source=../../hostgator-setup-kit/_common.sh
source "${PROJECT_DIR}/hostgator-setup-kit/_common.sh"
enter_project
step "Apontar o app para as imagens deste fork"
set_env_var .env APP_IMAGE "ghcr.io/${DONO}/deskcommcrm:develop"
set_env_var .env WORKER_IMAGE "ghcr.io/${DONO}/deskcomm-worker:develop"
set_env_var .env SCHEDULER_IMAGE "ghcr.io/${DONO}/deskcomm-scheduler:develop"
# Tag móvel: tem que puxar. Depois do pull, voltamos para missing — senão um
# `up -d` à mão, sem login no GHCR, morre quando o pacote ainda é privado.
set_env_var .env APP_PULL_POLICY always
set_env_var .env WORKER_PULL_POLICY always
set_env_var .env SCHEDULER_PULL_POLICY always
load_env .env
step "Atualizando o banco de dados"
if [ -f supabase/baseline.sql ]; then
docker run --rm postgres:17-alpine psql "$(url_do_schema)" -c \
"create extension if not exists vector with schema public; create extension if not exists citext with schema public; create extension if not exists pg_trgm with schema public;" \
>/dev/null 2>&1 || true
raw="$(docker run --rm -i -v "$PROJECT_DIR/supabase/baseline.sql:/b.sql:ro" \
postgres:17-alpine psql "$(url_do_schema)" -f /b.sql 2>&1 || true)"
benign='already exists|multiple primary keys|multiple default values|is already a member|already a partition'
unexpected="$(printf '%s\n' "$raw" | grep -iE 'ERROR|FATAL' | grep -viE "$benign" || true)"
if [ -n "$unexpected" ]; then
c_ylw "⚠ avisos inesperados no banco:"
printf '%s\n' "$unexpected" | head -20
else
c_grn "✓ banco atualizado"
fi
else
c_ylw "⚠ supabase/baseline.sql não encontrado — pulei a parte do banco."
fi
step "Baixando a imagem nova e reiniciando"
if ! dc pull; then
die "Não consegui puxar as imagens ghcr.io/${DONO}/*:develop. O job publicou?"
fi
garantir_rede_do_proxy
dc up -d
if [ "${REVERSE_PROXY:-caddy}" = "traefik" ]; then
c_grn "✓ proxy externo (Traefik): o Caddy não é usado aqui"
else
dc up -d --force-recreate --no-deps caddy >/dev/null 2>&1 \
&& c_grn "✓ proxy recarregado" \
|| c_ylw "⚠ não consegui recriar o proxy"
fi
# Já está no disco desta VPS. Sem always, um up -d posterior não depende do GHCR.
set_env_var .env APP_PULL_POLICY missing
set_env_var .env WORKER_PULL_POLICY missing
set_env_var .env SCHEDULER_PULL_POLICY missing
step "Conferindo se o app voltou no ar"
if wait_app_healthy 20 3 >/dev/null; then
c_grn "✓ deploy do ${SHA:0:7} no ar e saudável"
else
c_ylw "⚠ atualizei, mas o app não respondeu ok. Veja: docker compose $(dc_files) logs --tail=50 app"
exit 1
fi
-218
View File
@@ -1,218 +0,0 @@
name: Deploy da develop na VPS
# Customização DESTE fork (IanCouto/DeskcommCRM). Não abra PR disto para o
# upstream: o `publish-image.yml` de lá só publica `main` e tags `v*`, e é
# assim de propósito — `develop` aqui é um canal móvel da instalação desta VPS,
# não do parque inteiro.
#
# Doutrina: a VPS NÃO builda. Os runners do GitHub constroem as três imagens,
# publicam em ghcr.io/<dono>/…:develop, e o servidor só faz `docker compose pull`.
#
# Secrets (Settings → Secrets and variables → Actions), neste repositório:
# VPS_HOST IP da VPS
# VPS_PORT porta do SSH (nesta HostGator não é 22)
# VPS_USER usuário SSH (root)
# VPS_SSH_KEY chave privada ed25519 só para este job (não a chave pessoal)
on:
push:
branches: [develop]
workflow_dispatch:
concurrency:
group: deploy-vps-develop
cancel-in-progress: false
env:
REGISTRY: ghcr.io
jobs:
build-and-push:
if: github.repository == 'IanCouto/DeskcommCRM' && github.ref == 'refs/heads/develop'
runs-on: ubuntu-latest
timeout-minutes: 45
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- name: deskcommcrm
dockerfile: Dockerfile
title: DeskcommCRM
- name: deskcomm-worker
dockerfile: Dockerfile.worker
title: DeskcommCRM worker
- name: deskcomm-scheduler
dockerfile: Dockerfile.scheduler
title: DeskcommCRM scheduler
steps:
- uses: actions/checkout@v7
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Resolver APP_VERSION
id: ver
run: echo "value=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
- name: Docker metadata (tags/labels)
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ matrix.name }}
tags: |
type=raw,value=develop
type=raw,value=${{ github.sha }}
labels: |
org.opencontainers.image.title=${{ matrix.title }}
- name: Set up Buildx
uses: docker/setup-buildx-action@v4
- name: Build e push
uses: docker/build-push-action@v7
with:
context: .
file: ${{ matrix.dockerfile }}
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
APP_VERSION=${{ steps.ver.outputs.value }}
cache-from: type=gha,scope=develop-${{ matrix.name }}
cache-to: type=gha,mode=max,scope=develop-${{ matrix.name }}
- name: Tornar o pacote público (a VPS precisa puxar)
continue-on-error: true
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PKG: ${{ matrix.name }}
run: |
set -euo pipefail
gh api --method PUT \
"/user/packages/container/${PKG}/visibility" \
-f visibility=public \
|| echo "::warning::não consegui tornar ${PKG} público — o deploy faz login com o token do job"
imagem-do-app-sobe:
if: github.repository == 'IanCouto/DeskcommCRM' && github.ref == 'refs/heads/develop'
needs: [build-and-push]
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
packages: read
steps:
- name: Log in to GHCR
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Puxar a imagem que acabou de publicar
run: |
set -euo pipefail
dono=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')
docker pull "${REGISTRY}/${dono}/deskcommcrm:${GITHUB_SHA}"
docker tag "${REGISTRY}/${dono}/deskcommcrm:${GITHUB_SHA}" deskcomm-smoke:develop
- name: O container chega a servir?
run: |
set -euo pipefail
docker run -d --name smoke -p 3000:3000 \
-e NEXT_PUBLIC_SUPABASE_URL=https://exemplo.supabase.co \
-e NEXT_PUBLIC_SUPABASE_ANON_KEY=chave-de-mentira \
-e SUPABASE_SERVICE_ROLE_KEY=chave-de-mentira \
-e SUPABASE_DB_URL=postgres://u:p@127.0.0.1:5432/postgres \
-e SENTRY_DSN=off \
deskcomm-smoke:develop
pronto=nao
for _ in $(seq 1 40); do
if ! docker ps --filter name=smoke --filter status=running -q | grep -q .; then
echo "::error::o container do app MORREU durante o boot"
docker logs smoke 2>&1 | tail -40
exit 1
fi
if docker logs smoke 2>&1 | grep -qE "Ready in|started server on"; then
pronto=sim
break
fi
sleep 3
done
if [ "$pronto" != "sim" ]; then
echo "::error::o app não chegou a servir em 120s"
docker logs smoke 2>&1 | tail -40
exit 1
fi
if docker logs smoke 2>&1 | grep -q "MODULE_NOT_FOUND"; then
echo "::error::falta módulo no standalone"
docker logs smoke 2>&1 | grep -A5 MODULE_NOT_FOUND | head -20
exit 1
fi
echo "o app chegou a servir:"
docker logs smoke 2>&1 | grep -E "Ready in|Next.js" | head -3
- name: Encerrar
if: always()
run: docker rm -f smoke 2>/dev/null || true
deploy-vps:
if: github.repository == 'IanCouto/DeskcommCRM' && github.ref == 'refs/heads/develop'
needs: [build-and-push, imagem-do-app-sobe]
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
packages: read
steps:
- uses: actions/checkout@v7
- name: SSH na VPS e atualizar
env:
VPS_HOST: ${{ secrets.VPS_HOST }}
VPS_PORT: ${{ secrets.VPS_PORT }}
VPS_USER: ${{ secrets.VPS_USER }}
VPS_SSH_KEY: ${{ secrets.VPS_SSH_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_USER: ${{ github.actor }}
SHA: ${{ github.sha }}
DONO: ${{ github.repository_owner }}
run: |
set -euo pipefail
for v in VPS_HOST VPS_PORT VPS_USER VPS_SSH_KEY; do
eval "val=\${$v:-}"
if [ -z "$val" ]; then
echo "::error::falta o secret $v (Settings → Secrets and variables → Actions)"
exit 1
fi
done
mkdir -p ~/.ssh
chmod 700 ~/.ssh
umask 077
printf '%s\n' "$VPS_SSH_KEY" > ~/.ssh/id_ed25519
chmod 600 ~/.ssh/id_ed25519
ssh-keyscan -p "$VPS_PORT" "$VPS_HOST" >> ~/.ssh/known_hosts 2>/dev/null
# scp usa -P (maiúsculo) para a porta; ssh usa -p. Misturar os dois
# numa array só faz o scp ler `-p` como "preservar timestamp".
ident=(-o IdentitiesOnly=yes -o StrictHostKeyChecking=yes -i ~/.ssh/id_ed25519)
scp -P "$VPS_PORT" "${ident[@]}" .github/scripts/deploy-vps-develop.sh \
"${VPS_USER}@${VPS_HOST}:/tmp/deploy-vps-develop.sh"
dono=$(printf '%s' "$DONO" | tr '[:upper:]' '[:lower:]')
# Token vai por stdin (uma linha), não na linha de comando do ssh.
printf '%s\n' "$GH_TOKEN" | ssh -p "$VPS_PORT" "${ident[@]}" "${VPS_USER}@${VPS_HOST}" \
"read GH_TOKEN; export GH_TOKEN GH_USER=$(printf '%q' "$GH_USER") SHA=$(printf '%q' "$SHA") DONO=$(printf '%q' "$dono"); bash /tmp/deploy-vps-develop.sh"
-28
View File
@@ -1,28 +0,0 @@
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
const RAIZ = process.cwd();
const SCRIPT = readFileSync(join(RAIZ, ".github/scripts/deploy-vps-develop.sh"), "utf8");
describe("deploy da develop na VPS não puxa o registro do upstream", () => {
const semComentario = SCRIPT.split("\n")
.filter((l) => !l.trimStart().startsWith("#"))
.join("\n");
it("não chama gravar_imagens — aquilo pinaria o namespace do upstream, que este fork não publica", () => {
expect(semComentario).not.toMatch(/\bgravar_imagens\b/);
});
it("grava as três imagens a partir do DONO do job, não de um literal", () => {
expect(SCRIPT).toContain("ghcr.io/${DONO}/deskcommcrm:develop");
expect(SCRIPT).toContain("ghcr.io/${DONO}/deskcomm-worker:develop");
expect(SCRIPT).toContain("ghcr.io/${DONO}/deskcomm-scheduler:develop");
});
it("puxa o código pela URL pública — Bearer no extraHeader faz o git da VPS pedir usuário", () => {
expect(semComentario).toContain("GIT_TERMINAL_PROMPT=0");
expect(semComentario).not.toMatch(/http\.extraHeader/);
});
});