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>
111 lines
4.4 KiB
YAML
111 lines
4.4 KiB
YAML
name: Release
|
|
|
|
# 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.
|
|
# Precisa do secret de usuário REGISTRY_TOKEN (token do Gitea com write:package).
|
|
on:
|
|
push:
|
|
branches: [main]
|
|
tags: ['v*']
|
|
workflow_dispatch:
|
|
|
|
concurrency:
|
|
group: release
|
|
cancel-in-progress: false
|
|
|
|
env:
|
|
REGISTRY: git.lucasrguerra.dev.br
|
|
|
|
jobs:
|
|
# 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: [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
|
|
|
|
- uses: docker/setup-buildx-action@v4
|
|
|
|
- name: Autentica no registro
|
|
uses: docker/login-action@v4
|
|
with:
|
|
registry: ${{ env.REGISTRY }}
|
|
username: ${{ gitea.actor }}
|
|
password: ${{ secrets.REGISTRY_TOKEN }}
|
|
|
|
- name: Metadados
|
|
id: meta
|
|
uses: docker/metadata-action@v6
|
|
with:
|
|
images: ${{ needs.plano.outputs.image }}
|
|
tags: |
|
|
type=semver,pattern={{version}}
|
|
type=semver,pattern={{major}}.{{minor}}
|
|
type=raw,value=latest
|
|
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 }}
|
|
${{ needs.plano.outputs.image }}:inputs-${{ needs.plano.outputs.inputs }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
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 }}"
|