ci(release): deploy automático no Coolify quando o latest muda
Release / Plano (reaproveitar a imagem?) (push) Successful in 6s
CI / Lint e auditorias (push) Successful in 54s
CI / Trivy (dependências e segredos) (push) Successful in 13s
CI / Imagem Docker (linux/arm64) (push) Successful in 4m13s
Release / ci (push) Successful in 5m22s
Release / Publica a imagem (linux/arm64) (push) Successful in 19s
Release / Cria a release no Gitea (push) Skipped
Release / Deploy no Coolify (push) Failing after 1s
Release / Plano (reaproveitar a imagem?) (push) Successful in 6s
CI / Lint e auditorias (push) Successful in 54s
CI / Trivy (dependências e segredos) (push) Successful in 13s
CI / Imagem Docker (linux/arm64) (push) Successful in 4m13s
Release / ci (push) Successful in 5m22s
Release / Publica a imagem (linux/arm64) (push) Successful in 19s
Release / Cria a release no Gitea (push) Skipped
Release / Deploy no Coolify (push) Failing after 1s
O job deploy roda depois de publicar a imagem: pede o deploy pela API do Coolify e acompanha até terminar, falhando o workflow se o deploy falhar. O digest do latest é comparado antes e depois de publicar, então merge só de documentação ou tag (que reapontam o latest para o mesmo manifesto) não reiniciam o container. workflow_dispatch força o deploy. O script do digest fica em .gitea/scripts para não entrar no hash da imagem e não provocar rebuild. Precisa dos secrets COOLIFY_URL e COOLIFY_TOKEN no repositório. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
1860e34cbb
commit
b6fb230328
3 files changed
+76
-1
No files matched your search
Executable
+17
@@ -0,0 +1,17 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Uso: .gitea/scripts/digest-latest.sh <registro> <repositório>
|
||||||
|
# Imprime o digest do manifesto de <repositório>:latest, ou nada se a tag ainda
|
||||||
|
# não existe. Fica em .gitea/ para não entrar no hash da imagem (plano-imagem.sh).
|
||||||
|
# O release.yml compara o valor antes e depois de publicar para
|
||||||
|
# decidir se há o que implantar. Com o pacote privado, passe REGISTRY_USER e
|
||||||
|
# REGISTRY_PASSWORD (token com read:package).
|
||||||
|
set -euo pipefail
|
||||||
|
registry=$1; ns=${2,,}
|
||||||
|
|
||||||
|
auth=(); [ -n "${REGISTRY_PASSWORD:-}" ] && auth=(-u "${REGISTRY_USER:?}:$REGISTRY_PASSWORD")
|
||||||
|
token=$(curl -fsS "${auth[@]}" "https://$registry/v2/token?service=container_registry&scope=repository:$ns:pull" | jq -r .token)
|
||||||
|
curl -sSI \
|
||||||
|
-H "Authorization: Bearer $token" \
|
||||||
|
-H 'Accept: application/vnd.oci.image.index.v1+json,application/vnd.docker.distribution.manifest.list.v2+json,application/vnd.oci.image.manifest.v1+json,application/vnd.docker.distribution.manifest.v2+json' \
|
||||||
|
"https://$registry/v2/$ns/manifests/latest" \
|
||||||
|
| tr -d '\r' | awk -F': ' 'tolower($1) == "docker-content-digest" { print $2 }'
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
name: Release
|
name: Release
|
||||||
|
|
||||||
# Publica a imagem no registro de containers do Gitea depois de um merge em main,
|
# Publica a imagem no registro de containers do Gitea depois de um merge em main,
|
||||||
# e de novo com tag semver quando uma tag v* é enviada. O servidor só faz pull.
|
# e de novo com tag semver quando uma tag v* é enviada. Quando o latest passa a
|
||||||
|
# apontar para outra imagem, o job deploy pede ao Coolify para implantá-la.
|
||||||
|
# Precisa também dos secrets COOLIFY_URL e COOLIFY_TOKEN no repositório.
|
||||||
# Precisa do secret de usuário REGISTRY_TOKEN (token do Gitea com write:package).
|
# Precisa do secret de usuário REGISTRY_TOKEN (token do Gitea com write:package).
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
@@ -52,6 +54,8 @@ jobs:
|
|||||||
# O único runner é arm64 e o servidor de destino (Oracle) também, então a
|
# O único runner é arm64 e o servidor de destino (Oracle) também, então a
|
||||||
# imagem é construída nativamente, sem emulação.
|
# imagem é construída nativamente, sem emulação.
|
||||||
runs-on: ubuntu-24.04-arm
|
runs-on: ubuntu-24.04-arm
|
||||||
|
outputs:
|
||||||
|
mudou: ${{ steps.depois.outputs.mudou }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
@@ -69,6 +73,13 @@ jobs:
|
|||||||
username: ${{ gitea.actor }}
|
username: ${{ gitea.actor }}
|
||||||
password: ${{ secrets.REGISTRY_TOKEN }}
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
||||||
|
|
||||||
|
# O deploy só acontece se o latest passar a apontar para outra imagem.
|
||||||
|
# Um merge só de docs ou uma tag reaponta o latest para o mesmo manifesto,
|
||||||
|
# e reiniciar o container nesse caso seria trabalho repetido.
|
||||||
|
- name: Digest do latest antes
|
||||||
|
id: antes
|
||||||
|
run: echo "digest=$(.gitea/scripts/digest-latest.sh "$REGISTRY" "${{ gitea.repository }}")" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Metadados
|
- name: Metadados
|
||||||
id: meta
|
id: meta
|
||||||
uses: docker/metadata-action@v6
|
uses: docker/metadata-action@v6
|
||||||
@@ -101,6 +112,15 @@ jobs:
|
|||||||
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}')
|
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}')
|
||||||
docker buildx imagetools create $tags "${{ needs.plano.outputs.image }}:inputs-${{ needs.plano.outputs.inputs }}"
|
docker buildx imagetools create $tags "${{ needs.plano.outputs.image }}:inputs-${{ needs.plano.outputs.inputs }}"
|
||||||
|
|
||||||
|
- name: Digest do latest depois
|
||||||
|
id: depois
|
||||||
|
run: |
|
||||||
|
antes="${{ steps.antes.outputs.digest }}"
|
||||||
|
depois=$(.gitea/scripts/digest-latest.sh "$REGISTRY" "${{ gitea.repository }}")
|
||||||
|
echo "latest: ${antes:-nenhum} -> $depois"
|
||||||
|
[ -n "$depois" ] && [ "$depois" != "$antes" ] && mudou=true || mudou=false
|
||||||
|
echo "mudou=$mudou" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
# Cria a entrada em "Releases" quando a execução é de uma tag v*. Roda depois
|
# Cria a entrada em "Releases" quando a execução é de uma tag v*. Roda depois
|
||||||
# de publicar a imagem, com as notas da seção do CHANGELOG.md.
|
# de publicar a imagem, com as notas da seção do CHANGELOG.md.
|
||||||
release:
|
release:
|
||||||
@@ -127,3 +147,38 @@ jobs:
|
|||||||
'{tag_name:$tag, name:$name, body:$body, prerelease:$pre}' > release.json
|
'{tag_name:$tag, name:$name, body:$body, prerelease:$pre}' > release.json
|
||||||
curl -fsS -X POST "$API/releases" -H "Authorization: token $TOKEN" \
|
curl -fsS -X POST "$API/releases" -H "Authorization: token $TOKEN" \
|
||||||
-H 'Content-Type: application/json' -d @release.json
|
-H 'Content-Type: application/json' -d @release.json
|
||||||
|
|
||||||
|
# Avisa o Coolify para puxar o latest novo e espera o deploy terminar, para
|
||||||
|
# que uma falha apareça aqui, e não só no painel do Coolify. Roda só quando o
|
||||||
|
# latest mudou, ou num disparo manual (que força o deploy).
|
||||||
|
# Precisa dos secrets COOLIFY_URL e COOLIFY_TOKEN no repositório.
|
||||||
|
deploy:
|
||||||
|
name: Deploy no Coolify
|
||||||
|
needs: publicar
|
||||||
|
if: ${{ !cancelled() && needs.publicar.result == 'success' && (needs.publicar.outputs.mudou == 'true' || gitea.event_name == 'workflow_dispatch') }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Deploy de ESPDocs
|
||||||
|
env:
|
||||||
|
COOLIFY_URL: ${{ secrets.COOLIFY_URL }}
|
||||||
|
COOLIFY_TOKEN: ${{ secrets.COOLIFY_TOKEN }}
|
||||||
|
APP: 62wmq51cgbcz9nyfwizmytku
|
||||||
|
run: |
|
||||||
|
if [ -z "$COOLIFY_URL" ] || [ -z "$COOLIFY_TOKEN" ]; then
|
||||||
|
echo "faltam os secrets COOLIFY_URL e COOLIFY_TOKEN no repositório"; exit 1
|
||||||
|
fi
|
||||||
|
auth="Authorization: Bearer $COOLIFY_TOKEN"
|
||||||
|
dep=$(curl -fsS -H "$auth" "$COOLIFY_URL/api/v1/deploy?uuid=$APP&force=false" | jq -r '.deployments[0].deployment_uuid')
|
||||||
|
[ -n "$dep" ] && [ "$dep" != null ] || { echo "o Coolify não devolveu um deployment"; exit 1; }
|
||||||
|
echo "deployment $dep"
|
||||||
|
# Até 15 minutos: o pull da imagem arm64 e o healthcheck cabem com folga.
|
||||||
|
for _ in $(seq 1 90); do
|
||||||
|
st=$(curl -fsS -H "$auth" "$COOLIFY_URL/api/v1/deployments/$dep" | jq -r '.status')
|
||||||
|
echo "status: $st"
|
||||||
|
case "$st" in
|
||||||
|
finished) exit 0 ;;
|
||||||
|
failed|cancelled*) exit 1 ;;
|
||||||
|
esac
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
echo "o deploy não terminou em 15 minutos"; exit 1
|
||||||
@@ -8,6 +8,9 @@ Tudo o que muda de relevante no ESPDocs está aqui. O formato segue o
|
|||||||
|
|
||||||
### Adicionado
|
### Adicionado
|
||||||
|
|
||||||
|
- Deploy automático no Coolify: depois de publicar a imagem, o `release.yml` pede o deploy e
|
||||||
|
espera o resultado. Só implanta quando o `latest` muda, então merge só de documentação ou
|
||||||
|
tag não reiniciam o container. Um disparo manual do workflow força o deploy.
|
||||||
- Formação 2 da LASER em `/formacoes/2`: estação de temperatura e umidade com DHT22, LCD 16x2
|
- Formação 2 da LASER em `/formacoes/2`: estação de temperatura e umidade com DHT22, LCD 16x2
|
||||||
I2C e ESP32-S3, simulada no Wokwi com o framework Arduino. Slides, apostila, projeto do
|
I2C e ESP32-S3, simulada no Wokwi com o framework Arduino. Slides, apostila, projeto do
|
||||||
Wokwi e programa de scanner I2C, tudo validado no simulador.
|
Wokwi e programa de scanner I2C, tudo validado no simulador.
|
||||||
|
|||||||
Reference in new issue
Block a user