ci: reuse the published image when its sources are unchanged
Release / Plano (reaproveitar a imagem?) (push) Successful in 3s
Release / ci (push) Skipped
Release / Publica a imagem (linux/arm64) (push) Successful in 16s

The release workflow hashes everything that goes into the image build and skips
CI and the build when the registry already has an image for that hash, so a docs
or tooling change, or a version tag, only re-points the tags. ci.yml no longer
runs on main by push: release.yml calls it when a build is needed, and running
both repeated the same suite on the same commit.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Lucas RayanandClaude Sonnet 5.5 committed 2026-10-30 12:22:46 -03:00
1 parent a5c587155b
commit 111a81776c
2 files changed
+60 -13

No files matched your search

+6 -2
View File
@@ -1,10 +1,14 @@
name: CI name: CI
# Documentação e configuração de ferramenta não mudam nada que a suíte teste.
# Na main não roda por push: o release.yml é quem a chama, e só quando a imagem
# precisa ser reconstruída; rodar nos dois repetiria a mesma suíte no mesmo commit.
on: on:
pull_request: pull_request:
paths-ignore: ['**.md', 'LICENSE', '.claude/**', '.superset/**']
push: push:
branches: [main] branches-ignore: [main]
# O release.yml roda esta mesma suíte antes de publicar a imagem. paths-ignore: ['**.md', 'LICENSE', '.claude/**', '.superset/**']
workflow_call: workflow_call:
permissions: permissions:
+54 -11
View File
@@ -17,24 +17,57 @@ env:
REGISTRY: git.lucasrguerra.dev.br REGISTRY: git.lucasrguerra.dev.br
jobs: jobs:
# Nada é publicado sem a suíte completa passar antes. # A imagem só depende dos arquivos que entram no build, não da documentação nem
# da configuração de ferramentas. Quando já existe no registro uma imagem para
# o mesmo conteúdo (um merge só de docs, uma mudança de workflow, uma tag num
# commit que acabou de ser publicado), não há o que construir: as tags novas
# apontam para o manifesto existente.
plano:
name: Plano (reaproveitar a imagem?)
runs-on: ubuntu-latest
outputs:
inputs: ${{ steps.plano.outputs.inputs }}
reuse: ${{ steps.plano.outputs.reuse }}
image: ${{ steps.plano.outputs.image }}
steps:
- uses: actions/checkout@v4
- id: plano
env:
REPO: ${{ gitea.repository }}
run: |
inputs=$(git ls-tree -r HEAD \
| awk -F'\t' '$2 !~ /^(\.gitea|\.github|\.claude|\.superset|docs)\// && $2 !~ /^(README.*|CLAUDE\.md|DESIGN\.md|LICENSE|\.gitignore)$/' \
| sha256sum | cut -c1-16)
ns="${REPO,,}"
token=$(curl -fsS "https://$REGISTRY/v2/token?service=container_registry&scope=repository:$ns:pull" | jq -r .token)
code=$(curl -s -o /dev/null -w '%{http_code}' -I \
-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' \
"https://$REGISTRY/v2/$ns/manifests/inputs-$inputs")
echo "inputs-$inputs -> HTTP $code"
reuse=false; [ "$code" = 200 ] && reuse=true
echo "inputs=$inputs" >> "$GITHUB_OUTPUT"
echo "reuse=$reuse" >> "$GITHUB_OUTPUT"
echo "image=$REGISTRY/$ns" >> "$GITHUB_OUTPUT"
# Nada é publicado sem a suíte completa passar antes. Pulada quando a imagem é
# reaproveitada: o mesmo conteúdo já passou por ela.
ci: ci:
needs: plano
if: ${{ needs.plano.outputs.reuse != 'true' }}
uses: ./.gitea/workflows/ci.yml uses: ./.gitea/workflows/ci.yml
publicar: publicar:
name: Publica a imagem (linux/arm64) name: Publica a imagem (linux/arm64)
needs: ci needs: [plano, ci]
# ci é pulado, e não bem-sucedido, quando a imagem é reaproveitada.
if: ${{ !cancelled() && needs.plano.result == 'success' && (needs.ci.result == 'success' || needs.plano.outputs.reuse == 'true') }}
# 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
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- id: nome
run: |
repo='${{ gitea.repository }}'
echo "image=${{ env.REGISTRY }}/${repo,,}" >> "$GITHUB_OUTPUT"
- uses: docker/setup-buildx-action@v4 - uses: docker/setup-buildx-action@v4
- name: Autentica no registro - name: Autentica no registro
@@ -48,7 +81,7 @@ jobs:
id: meta id: meta
uses: docker/metadata-action@v6 uses: docker/metadata-action@v6
with: with:
images: ${{ steps.nome.outputs.image }} images: ${{ needs.plano.outputs.image }}
tags: | tags: |
type=semver,pattern={{version}} type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}} type=semver,pattern={{major}}.{{minor}}
@@ -56,12 +89,22 @@ jobs:
type=sha,format=long type=sha,format=long
- name: Build e push - name: Build e push
if: ${{ needs.plano.outputs.reuse != 'true' }}
uses: docker/build-push-action@v7 uses: docker/build-push-action@v7
with: with:
context: . context: .
platforms: linux/arm64 platforms: linux/arm64
push: true push: true
tags: ${{ steps.meta.outputs.tags }} tags: |
${{ steps.meta.outputs.tags }}
${{ needs.plano.outputs.image }}:inputs-${{ needs.plano.outputs.inputs }}
labels: ${{ steps.meta.outputs.labels }} labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ steps.nome.outputs.image }}:buildcache cache-from: type=registry,ref=${{ needs.plano.outputs.image }}:buildcache
cache-to: type=registry,ref=${{ steps.nome.outputs.image }}:buildcache,mode=max cache-to: type=registry,ref=${{ needs.plano.outputs.image }}:buildcache,mode=max
# Mesmo manifesto, nomes novos: nenhuma camada é lida nem escrita.
- name: Aplica as tags à imagem existente
if: ${{ needs.plano.outputs.reuse == 'true' }}
run: |
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 }}"