Files
docker-baseimage-alpine/.gitea/workflows/build-and-push.yaml
2026-02-12 12:18:11 +00:00

282 lines
12 KiB
YAML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
on:
push:
branches:
- 'main'
tags:
- '*'
schedule:
- cron: '*/60 * * * *'
workflow_dispatch:
jobs:
release-and-build:
runs-on: buildx-multiarch
if: "!contains(gitea.event.head_commit.message, '[skip ci]')"
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare Environment and Read Config
id: prep
run: |
export TZ=Europe/Berlin
# Env laden um BUILD_TAG und BASE_IMAGE zu bekommen
set -a
source <(grep -v '^#' buildargs.env | sed 's/\r$//')
set +a
echo "event_name=${{ gitea.event_name }}" >> $GITHUB_OUTPUT
if [[ "${{ gitea.ref }}" == refs/tags/* ]]; then
CLEAN_TAG=${{ gitea.ref_name }}
echo "docker_tag=${CLEAN_TAG#v}" >> $GITHUB_OUTPUT
else
echo "docker_tag=$BUILD_TAG" >> $GITHUB_OUTPUT
fi
OWNER=$(echo "${{ gitea.repository }}" | cut -d'/' -f1 | tr '[:upper:]' '[:lower:]')
REPO_NAME=$(echo "${{ gitea.repository }}" | cut -d'/' -f2 | tr '[:upper:]' '[:lower:]')
echo "image_name=git.pi-farm.de/$OWNER/$REPO_NAME" >> $GITHUB_OUTPUT
echo "owner=$OWNER" >> $GITHUB_OUTPUT
echo "repo_pure=$REPO_NAME" >> $GITHUB_OUTPUT
echo "base_image=$BASE_IMAGE" >> $GITHUB_OUTPUT
- name: Login to Gitea Registry
run: |
echo "${{ secrets.REGISTRY_PASSWORD }}" | docker login \
git.pi-farm.de -u ${{ secrets.REGISTRY_USER }} --password-stdin
- name: Check for Real Changes
id: check_changes
shell: bash
run: |
SHOULD_BUILD="true"
IMAGE="${{ steps.prep.outputs.image_name }}"
TAG="${{ steps.prep.outputs.docker_tag }}"
BASE="${{ steps.prep.outputs.base_image }}"
echo "🔍 Prüfe Remote-Registry..."
if [[ "${{ steps.prep.outputs.event_name }}" != "schedule" ]]; then
echo "🚀 Manueller Start: Build erzwungen."
else
# 1. Base Image SHA holen
REMOTE_BASE_SHA=$(docker buildx imagetools inspect "$BASE" --format '{{json .Manifest.Digest}}' 2>/dev/null | tr -d '"' || echo "")
if [ -z "$REMOTE_BASE_SHA" ]; then
echo "⚠️ Base-Image SHA nicht lesbar. Build wird gestartet."
else
echo " Base-Image SHA (Remote): $REMOTE_BASE_SHA"
# 2. Annotation aus dem Index-Manifest holen
# Wir holen das RAW JSON, da wir wissen, dass es dort im Block "annotations" steht.
# Wir nutzen grep, um "pi_farm.base_digest": "sha256:..." zu finden.
RAW_INDEX=$(docker buildx imagetools inspect "$IMAGE:$TAG" --raw 2>/dev/null || echo "")
if [ -z "$RAW_INDEX" ]; then
echo "🆕 Image existiert noch nicht. Build erforderlich."
else
# Extrahiere den Wert zwischen den Anführungszeichen nach dem Key
# Suche nach: "pi_farm.base_digest": "WERT"
USED_BASE_SHA=$(echo "$RAW_INDEX" | grep "\"pi_farm.base_digest\":" | sed -E 's/.*: "([^"]+)".*/\1/' || echo "none")
# Falls grep fehlschlägt, ist USED_BASE_SHA leer oder none
if [ -z "$USED_BASE_SHA" ]; then USED_BASE_SHA="none"; fi
echo " Gefundene Annotation im Index: $USED_BASE_SHA"
if [ "$REMOTE_BASE_SHA" == "$USED_BASE_SHA" ]; then
echo "😴 Base-Image unverändert. Kein Build nötig."
SHOULD_BUILD="false"
else
echo "✅ Update nötig: $USED_BASE_SHA -> $REMOTE_BASE_SHA"
SHOULD_BUILD="true"
fi
fi
fi
fi
echo "should_build=$SHOULD_BUILD" >> $GITHUB_OUTPUT
- name: Set up QEMU
if: steps.check_changes.outputs.should_build == 'true'
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
if: steps.check_changes.outputs.should_build == 'true'
uses: docker/setup-buildx-action@v3
- name: Build and Push Docker Image
if: steps.check_changes.outputs.should_build == 'true'
run: |
IMAGE=${{ steps.prep.outputs.image_name }}
TAG=${{ steps.prep.outputs.docker_tag }}
BASE=${{ steps.prep.outputs.base_image }}
# 1. Variablen aus der Datei in die Shell laden, damit sie aufgelöst werden
set -a
source <(grep -v '^#' buildargs.env | sed 's/\r$//')
set +a
# 2. Argumente für Docker vorbereiten (Variablen werden hier aufgelöst!)
DOCKER_ARGS=""
# Wir extrahieren alle Keys aus der Datei
keys=$(grep -v '^#' buildargs.env | cut -d'=' -f1 | tr -d '\r')
for k in $keys; do
# Hier passiert die Magie: ${!k} holt den bereits aufgelösten Wert aus der Shell
val="${!k}"
DOCKER_ARGS="$DOCKER_ARGS --build-arg $k=$val"
done
# 3. Base SHA für das Label holen (wichtig für den nächsten Check)
# Da BASE selbst Variablen enthalten kann, nutzen wir auch hier den aufgelösten Wert
RESOLVED_BASE=$(echo $BASE)
BASE_SHA=$(docker buildx imagetools inspect $RESOLVED_BASE --format '{{json .Manifest.Digest}}' 2>/dev/null | tr -d '"' || echo "unknown")
echo "🚀 Starte Multi-Arch Build für $IMAGE:$TAG..."
echo "📦 Basis-Image aufgelöst: $RESOLVED_BASE"
# AMD64 Build
docker buildx build $DOCKER_ARGS --pull --platform linux/amd64 -f Dockerfile \
--label "pi_farm.base_digest=$BASE_SHA" -t $IMAGE:tmp-amd64 --push .
# ARM64 Build
docker buildx build $DOCKER_ARGS --pull --platform linux/arm64 -f Dockerfile.aarch64 \
--label "pi_farm.base_digest=$BASE_SHA" -t $IMAGE:tmp-arm64 --push .
# Manifeste zusammenführen und Annotation hinzufügen
# Das macht das Label "sichtbar", ohne dass man in die Child-Images schauen muss
docker buildx imagetools create \
--annotation "index:pi_farm.base_digest=$BASE_SHA" \
-t $IMAGE:$TAG $IMAGE:tmp-amd64 $IMAGE:tmp-arm64
docker buildx imagetools create \
--annotation "index:pi_farm.base_digest=$BASE_SHA" \
-t $IMAGE:latest $IMAGE:tmp-amd64 $IMAGE:tmp-arm64
- name: Cleanup Temporary Registry Tags
if: steps.check_changes.outputs.should_build == 'true'
run: |
TOKEN="${{ secrets.GIT_TOKEN }}"
# Wir extrahieren den Original-Owner und Namen direkt aus dem Repo-Pfad
# Gitea ist bei der API oft empfindlich, was Groß/Kleinschreibung angeht
ORG_NAME=$(echo "${{ gitea.repository }}" | cut -d'/' -f1)
REPO_NAME=$(echo "${{ gitea.repository }}" | cut -d'/' -f2)
echo "🗑️ Bereinige temporäre Tags für $ORG_NAME/$REPO_NAME..."
for t in tmp-amd64 tmp-arm64; do
echo "Versuche Löschung von Tag: $t"
# Versuch 1: Original-Schreibweise
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X 'DELETE' \
"https://git.pi-farm.de/api/v1/packages/$ORG_NAME/container/$REPO_NAME/$t" \
-H "Authorization: token $TOKEN")
if [ "$STATUS" -eq 204 ]; then
echo "✅ Tag $t gelöscht (Original-Schreibweise)."
else
# Versuch 2: Kleingeschriebene Version (falls Gitea das intern umwandelt)
ORG_LOWER=$(echo "$ORG_NAME" | tr '[:upper:]' '[:lower:]')
REPO_LOWER=$(echo "$REPO_NAME" | tr '[:upper:]' '[:lower:]')
STATUS_LOWER=$(curl -s -o /dev/null -w "%{http_code}" -X 'DELETE' \
"https://git.pi-farm.de/api/v1/packages/$ORG_LOWER/container/$REPO_LOWER/$t" \
-H "Authorization: token $TOKEN")
if [ "$STATUS_LOWER" -eq 204 ]; then
echo "✅ Tag $t gelöscht (Kleinschreibung)."
else
echo "⚠️ Tag $t konnte nicht gelöscht werden (HTTP $STATUS / $STATUS_LOWER)."
echo "Prüfe bitte: Hat der Token 'write:package' Rechte und ist der User in der Org?"
fi
fi
done
- name: Update Documentation and Compose
if: steps.check_changes.outputs.should_build == 'true'
run: |
export TZ=Europe/Berlin
CURRENT_TIME=$(date +'%d.%m.%Y %H:%M')
BUILD_DATE_ONLY=$(date +'%d.%m.%Y')
BUILD_TAG="${{ steps.prep.outputs.docker_tag }}"
REPO_NAME=$(echo "${{ gitea.repository }}" | cut -d'/' -f2)
REPO_LOWER=$(echo "${{ gitea.repository }}" | tr '[:upper:]' '[:lower:]')
FULL_URL="git.pi-farm.de/${REPO_LOWER}"
[ -f "Dockerfile.aarch64" ] && ARM_STATUS="✅ Aktiv (eigenes Dockerfile)" || ARM_STATUS="✅ Aktiv (via Standard Dockerfile)"
set -a
source <(grep -v '^#' buildargs.env | sed 's/\r$//')
set +a
if [[ "${{ steps.prep.outputs.event_name }}" == "schedule" ]]; then
COMMIT_MSG="Automatischer Security-Rebuild (Base Image Update)"
else
COMMIT_MSG=$(git log -1 --pretty=%s --no-merges 2>/dev/null || echo "Manual build")
COMMIT_MSG=$(echo "$COMMIT_MSG" | sed 's/\[skip ci\]//g' | xargs)
fi
wget -q https://git.pi-farm.de/pi-farm/templates/raw/branch/main/README.template -O README.template || exit 1
wget -q https://git.pi-farm.de/pi-farm/templates/raw/branch/main/docker-compose.template -O docker-compose.template || true
NEW_ROW="| **v${BUILD_TAG}** | ${CURRENT_TIME} | ${COMMIT_MSG} ✅ |"
if [ -f "VERSION.history" ]; then
grep -v "| **v${BUILD_TAG}** |" VERSION.history > VERSION.history.tmp || true
echo -e "${NEW_ROW}\n$(cat VERSION.history.tmp)" > VERSION.history
rm VERSION.history.tmp
else
echo -e "${NEW_ROW}" > VERSION.history
fi
HISTORY_CONTENT=$(cat VERSION.history)
process_template() {
local template=$1; local output=$2
if [ -f "$template" ]; then
> "$output"
while IFS= read -r line || [ -n "$line" ]; do
line="${line//__REPO_NAME__/$REPO_NAME}"
line="${line//__FULL_URL__/$FULL_URL}"
line="${line//__BUILD_TAG__/$BUILD_TAG}"
line="${line//__CURRENT_DATE__/$CURRENT_TIME}"
line="${line//__BUILD_DATE__/$BUILD_DATE_ONLY}"
line="${line//__HISTORY_CONTENT__/$HISTORY_CONTENT}"
line="${line//__ARM_STATUS__/$ARM_STATUS}"
keys=$(grep -v '^#' buildargs.env | cut -d'=' -f1)
for k in $keys; do
clean_key="__$(echo $k | tr -d '\r')__"
clean_val="${!k}"
line="${line//$clean_key/$clean_val}"
done
echo "$line" >> "$output"
done < "$template"
fi
}
process_template "README.template" "README.md"
process_template "docker-compose.template" "docker-compose.yml"
echo "FINAL_MSG=$COMMIT_MSG" >> $GITHUB_ENV
- name: Commit, Tag and Push Changes
if: steps.check_changes.outputs.should_build == 'true'
run: |
git config --local user.email "action@github.com"
git config --local user.name "GitHub Action"
git add VERSION.history README.md docker-compose.yml
git diff --quiet && git diff --staged --quiet || git commit -m "${{ env.FINAL_MSG }} [skip ci]"
git tag -f "v${{ steps.prep.outputs.docker_tag }}"
git push origin main
git push -f origin "v${{ steps.prep.outputs.docker_tag }}"
- name: Cleanup Docker Artifacts
if: always()
run: docker image prune -f
- name: Workflow Summary
if: always()
run: |
echo "Check completed. Build was: ${{ steps.check_changes.outputs.should_build }}"