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
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
168 lines
7.3 KiB
YAML
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
|