name: build-and-promote # Build Once → Promote → Deploy (modelo da stack — ver Documentos-Unicos/deploy): # • push na main → job BUILD: builda 1x e publica por COMMIT (: + :latest). NÃO deploya. # • tag vX.Y.Z → job PROMOTE: re-tagueia a imagem do commit como :vX.Y.Z (SEM rebuild), # valida digest e deploya na VPS1 (pull + up --no-build). # A versão semântica NÃO entra no build: nasce da tag e é injetada em runtime (docker-compose.prod.yml). # O React (Vite) é buildado como step ANTES do docker build (o Dockerfile atual espera o dist/ pronto). on: push: branches: [main] tags: ['v*'] jobs: # ───────────────────────── BUILD (só em push de branch) ───────────────────────── build: if: startsWith(github.ref, 'refs/heads/') runs-on: self-hosted steps: - name: Checkout uses: actions/checkout@v4 - name: Vars (commit + data) id: vars run: | echo "commit=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" echo "build_time=$(date -u +'%Y-%m-%d %H:%M UTC')" >> "$GITHUB_OUTPUT" - name: Login no registry run: | if [ -n "${{ secrets.REGISTRY_TOKEN }}" ]; then echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.clube67.com -u ruicesar --password-stdin else echo "REGISTRY_TOKEN ausente — usando a credencial já presente no host." fi - name: Build do React (Vite) — gera dental-client/dist/ antes do docker build run: | set -e cp dental-server/version.txt dental-server/dental-client/public/version.txt cd dental-server/dental-client NODE_ENV=development npm install --include=dev --prefer-offline npm run build ls dist/index.html >/dev/null && echo "OK: dist/ pronto" - name: Build da imagem (inclui dental-client/dist/) env: COMPOSE_PROJECT_NAME: rxscoreodontocom run: docker compose -f docker-compose.yml build app - name: Publicar por COMMIT (: + :latest), com retry p/ 499 run: | set -e REG=git.clube67.com/ruicesar C="${{ steps.vars.outputs.commit }}" SRC="rxscoreodontocom-app:latest" DST="${REG}/rx-scoreodonto" docker tag "$SRC" "$DST:$C" docker tag "$SRC" "$DST:latest" for tag in "$C" "latest"; do n=0 until docker push "$DST:$tag"; do n=$((n+1)); [ $n -ge 4 ] && { echo "push falhou: $DST:$tag"; exit 1; } echo "retry $n (499 transitório) em $DST:$tag"; sleep 3 done done echo "Publicado: rx-scoreodonto:$C (+ :latest). Push NÃO deploya." # ─────────────────────── PROMOTE (só em tag vX.Y.Z) ─────────────────────── promote: if: startsWith(github.ref, 'refs/tags/v') runs-on: self-hosted steps: - name: Checkout (na tag) uses: actions/checkout@v4 - name: Vars (tag + commit) id: vars run: | echo "version=${GITHUB_REF_NAME}" >> "$GITHUB_OUTPUT" echo "commit=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT" - name: Login no registry run: | if [ -n "${{ secrets.REGISTRY_TOKEN }}" ]; then echo "${{ secrets.REGISTRY_TOKEN }}" | docker login git.clube67.com -u ruicesar --password-stdin fi - name: Integridade — a imagem do commit existe? (nunca buildar na tag) run: | set -e REG=git.clube67.com/ruicesar C="${{ steps.vars.outputs.commit }}" if ! docker buildx imagetools inspect "${REG}/rx-scoreodonto:$C" >/dev/null 2>&1; then echo "ERRO: ${REG}/rx-scoreodonto:$C não existe no registry." echo " Faça 'git push origin main' (que builda o commit $C) ANTES de criar a tag." exit 1 fi echo "OK: rx-scoreodonto:$C presente no registry." - name: Promover — re-tag commit → versão (SEM rebuild) + conferir digest run: | set -e REG=git.clube67.com/ruicesar C="${{ steps.vars.outputs.commit }}"; V="${{ steps.vars.outputs.version }}" DST="${REG}/rx-scoreodonto" docker buildx imagetools create -t "$DST:$V" "$DST:$C" dC=$(docker buildx imagetools inspect "$DST:$C" --format '{{.Manifest.Digest}}') dV=$(docker buildx imagetools inspect "$DST:$V" --format '{{.Manifest.Digest}}') [ "$dC" = "$dV" ] || { echo "ERRO: digest divergiu ($V=$dV != $C=$dC)"; exit 1; } echo "Promovido sem rebuild: :$V e :$C apontam para o mesmo artefato (digest $dV)." - name: Deploy na VPS1 (pull :versao + up --no-build; versao/commit injetados em runtime) run: | set -e V="${{ steps.vars.outputs.version }}"; C="${{ steps.vars.outputs.commit }}" scp -o StrictHostKeyChecking=accept-new \ docker-compose.yml docker-compose.prod.yml deploy-prod.sh \ deploy@10.99.0.1:/home/deploy/stack/rx.scoreodonto.com/ ssh -o StrictHostKeyChecking=accept-new deploy@10.99.0.1 \ "/home/deploy/stack/rx.scoreodonto.com/deploy-prod.sh $V $C"