Files
acaua/.gitea/workflows/release.yml
T
Lucas RayanandClaude Sonnet 5 673b11c88c
Release / Publish tags (push) Successful in 13s
Release / Plan (reuse the published image?) (push) Successful in 4s
Release / ci (push) Successful in 32s
Release / Build image (amd64) (push) Successful in 20s
Release / Build image (arm64) (push) Successful in 19s
CI / Format and clippy (push) Successful in 16s
CI / Tests (Linux) (push) Successful in 31s
CI / Dependency audit (push) Successful in 16s
CI / Docker image (build and smoke test) (push) Skipped
Release / Gitea release (push) Successful in 3s
ci: replace docker/build-push-action with plain docker buildx build
docker/build-push-action's upstream repo has ~260MB of git history, which
reliably hangs the act runner's Go-based git clone on the linux-amd64
(Hostinger) runner — confirmed it's not a network or cache issue: curl to
codeload.github.com and a plain `git clone` of the same repo both complete
in seconds from the host and from inside the exact job container. Only
act's own clone of this specific action hangs, every time.

A raw `docker buildx build` with the same flags does the same job without
cloning anything.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
2026-11-01 10:18:18 -03:00

168 lines
7.3 KiB
YAML

name: Release
# Publishes the multi-arch Acauã image (linux/amd64 + linux/arm64) to the Gitea
# container registry. A merge into main publishes `edge`; a v* tag re-points the
# image already built for the same inputs to X.Y.Z, X.Y and latest (no rebuild)
# and creates the Gitea Release. Needs the secret REGISTRY_TOKEN (Gitea token
# with write:package) visible to this repository.
on:
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
concurrency:
group: release-${{ gitea.ref }}
cancel-in-progress: false
env:
REGISTRY: git.lucasrguerra.dev.br
jobs:
# The image is built only from these paths, so their tree hashes identify it.
# When inputs-<hash> already exists (docs-only merge, workflow change, or a tag
# on a commit main already published), nothing is built or tested again.
plan:
name: Plan (reuse the published image?)
runs-on: linux-arm64
outputs:
inputs: ${{ steps.plan.outputs.inputs }}
reuse: ${{ steps.plan.outputs.reuse }}
image: ${{ steps.plan.outputs.image }}
steps:
- uses: actions/checkout@v7
- id: plan
env:
REPO: ${{ gitea.repository }}
run: |
inputs=$(git rev-parse HEAD:Dockerfile HEAD:.dockerignore HEAD:Cargo.toml HEAD:Cargo.lock \
HEAD:crates HEAD:apps/gui/ui HEAD:logo.png HEAD:scripts/fetch-libduckdb.sh | 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' \
"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"
ci:
needs: plan
if: ${{ needs.plan.outputs.reuse != 'true' }}
uses: ./.gitea/workflows/ci.yml
# Each architecture is built on a native runner (no QEMU) and pushed under a
# per-architecture tag; publish joins them into one manifest list.
build:
name: Build image (${{ matrix.arch }})
needs: [plan, ci]
if: ${{ needs.plan.outputs.reuse != 'true' }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- { arch: amd64, platform: linux/amd64, runner: linux-amd64 }
- { arch: arm64, platform: linux/arm64, runner: linux-arm64 }
steps:
- uses: actions/checkout@v7
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
# Plain `docker buildx build` instead of docker/build-push-action: that
# action's upstream repo (~260MB of git history) reliably hangs the
# act runner's Go-based clone on the Hostinger host, even when curl/git
# to github.com are both fast. Same end result, no action to clone.
- name: Build and push (per architecture)
run: |
docker buildx build \
--platform "${{ matrix.platform }}" \
--push \
-t "${{ needs.plan.outputs.image }}:build-${{ gitea.sha }}-${{ matrix.arch }}" \
--cache-from "type=registry,ref=${{ needs.plan.outputs.image }}:buildcache-${{ matrix.arch }}" \
--cache-to "type=registry,ref=${{ needs.plan.outputs.image }}:buildcache-${{ matrix.arch }},mode=max" \
.
# Runs the image that was just pushed, on its own architecture.
- name: Smoke test
run: scripts/smoke-image.sh "${{ needs.plan.outputs.image }}:build-${{ gitea.sha }}-${{ matrix.arch }}"
publish:
name: Publish tags
needs: [plan, build]
# build is skipped, not successful, when the image is reused.
if: ${{ !cancelled() && needs.plan.result == 'success' && (needs.build.result == 'success' || needs.plan.outputs.reuse == 'true') }}
runs-on: linux-arm64
steps:
- uses: docker/setup-buildx-action@v4
- uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ gitea.actor }}
password: ${{ secrets.REGISTRY_TOKEN }}
- name: Tags
id: meta
uses: docker/metadata-action@v6
with:
images: ${{ needs.plan.outputs.image }}
flavor: latest=false
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable=${{ startsWith(gitea.ref, 'refs/tags/v') && !contains(gitea.ref_name, '-') }}
type=raw,value=edge,enable=${{ gitea.ref == 'refs/heads/main' }}
type=sha,format=long
- name: Apply tags
run: |
image='${{ needs.plan.outputs.image }}'
tags=$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< '${{ steps.meta.outputs.json }}')
inputs='${{ needs.plan.outputs.inputs }}'
if [ '${{ needs.plan.outputs.reuse }}' = true ]; then
docker buildx imagetools create $tags "$image:inputs-$inputs"
else
docker buildx imagetools create $tags -t "$image:inputs-$inputs" \
"$image:build-${{ gitea.sha }}-amd64" "$image:build-${{ gitea.sha }}-arm64"
fi
- name: Check architectures
run: |
docker buildx imagetools inspect "${{ needs.plan.outputs.image }}:inputs-${{ needs.plan.outputs.inputs }}" \
--format '{{json .Manifest}}' \
| jq -r '.manifests[] | select(.platform.os == "linux") | "\(.platform.os)/\(.platform.architecture)"' \
| tee platforms.txt
grep -qx linux/amd64 platforms.txt && grep -qx linux/arm64 platforms.txt
- name: Summary
run: |
{ echo "### Acauã image published (linux/amd64, linux/arm64)"; echo; echo '```'
echo "${{ steps.meta.outputs.tags }}"; echo '```'; } >> "$GITHUB_STEP_SUMMARY"
gitea-release:
name: Gitea release
needs: [plan, publish]
if: ${{ !cancelled() && needs.publish.result == 'success' && startsWith(gitea.ref, 'refs/tags/v') }}
runs-on: linux-arm64
steps:
- uses: actions/checkout@v7
with:
fetch-depth: 0
- name: Release
env:
TAG: ${{ gitea.ref_name }}
TOKEN: ${{ gitea.token }}
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
IMAGE: ${{ needs.plan.outputs.image }}
run: |
if curl -fsS -H "Authorization: token $TOKEN" "$API/releases/tags/$TAG" >/dev/null 2>&1; then
echo "release $TAG already exists"; exit 0
fi
{ scripts/release-notes.sh "$TAG"; echo; echo '```bash'; echo "docker pull $IMAGE:${TAG#v}"; echo '```'; } > notes.md
pre=false; case "$TAG" in *-*) pre=true ;; esac
jq -n --arg tag "$TAG" --arg name "Acauã ${TAG#v}" --rawfile body notes.md --argjson pre "$pre" \
'{tag_name:$tag, name:$name, body:$body, prerelease:$pre}' > release.json
curl -fsS -X POST "$API/releases" -H "Authorization: token $TOKEN" \
-H 'Content-Type: application/json' -d @release.json >/dev/null