diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 21d9a1e..7520acf 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -1,10 +1,14 @@ 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: pull_request: + paths-ignore: ['**.md', 'LICENSE', '.claude/**', '.superset/**'] push: - branches: [main] - # O release.yml roda esta mesma suíte antes de publicar a imagem. + branches-ignore: [main] + paths-ignore: ['**.md', 'LICENSE', '.claude/**', '.superset/**'] workflow_call: permissions: diff --git a/.gitea/workflows/release.yml b/.gitea/workflows/release.yml index d9e8718..d2e99b8 100644 --- a/.gitea/workflows/release.yml +++ b/.gitea/workflows/release.yml @@ -17,24 +17,57 @@ env: REGISTRY: git.lucasrguerra.dev.br 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: + needs: plano + if: ${{ needs.plano.outputs.reuse != 'true' }} uses: ./.gitea/workflows/ci.yml publicar: 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 # imagem é construída nativamente, sem emulação. runs-on: ubuntu-24.04-arm steps: - uses: actions/checkout@v4 - - id: nome - run: | - repo='${{ gitea.repository }}' - echo "image=${{ env.REGISTRY }}/${repo,,}" >> "$GITHUB_OUTPUT" - - uses: docker/setup-buildx-action@v4 - name: Autentica no registro @@ -48,7 +81,7 @@ jobs: id: meta uses: docker/metadata-action@v6 with: - images: ${{ steps.nome.outputs.image }} + images: ${{ needs.plano.outputs.image }} tags: | type=semver,pattern={{version}} type=semver,pattern={{major}}.{{minor}} @@ -56,12 +89,22 @@ jobs: type=sha,format=long - name: Build e push + if: ${{ needs.plano.outputs.reuse != 'true' }} uses: docker/build-push-action@v7 with: context: . platforms: linux/arm64 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 }} - cache-from: type=registry,ref=${{ steps.nome.outputs.image }}:buildcache - cache-to: type=registry,ref=${{ steps.nome.outputs.image }}:buildcache,mode=max + cache-from: type=registry,ref=${{ needs.plano.outputs.image }}:buildcache + 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 }}"