Files
docker-baseimage-alpine/.gitea/workflows/build-and-push.yaml
pi-farm c9a33df57f
Some checks failed
/ release-and-build (push) Failing after 20s
fix HISTORY_CONTENT in README.md
2026-02-13 01:41:09 +01:00

356 lines
15 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: '0 5 * * 0'
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: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Prepare Environment and Read Config
id: prep
run: |
export TZ=Europe/Berlin
# 1. Env laden
set -a
source <(grep -v '^#' buildargs.env | sed 's/\r$//')
set +a
# 2. Hash der BUILD_ Variablen berechnen (für Change-Detection)
# Wir nehmen nur Zeilen, die mit BUILD_ beginnen
ARGS_HASH=$(grep "^BUILD_" buildargs.env | sha256sum | cut -d' ' -f1)
echo "build_args_hash=$ARGS_HASH" >> $GITHUB_OUTPUT
# ... (Rest deiner Logik für Tags, Owner etc. bleibt gleich) ...
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
# Fallback falls BUILD_TAG nicht gesetzt ist
echo "docker_tag=${BUILD_TAG:-latest}" >> $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 "repo_pure=$REPO_NAME" >> $GITHUB_OUTPUT
echo "docker_tag=$BUILD_TAG" >> $GITHUB_OUTPUT
echo "image_name=git.pi-farm.de/$OWNER/$REPO_NAME" >> $GITHUB_OUTPUT
echo "base_image=$BUILD_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 }}"
LOCAL_ARGS_HASH="${{ steps.prep.outputs.build_args_hash }}"
echo "🔍 Prüfe Remote-Registry..."
echo " Lokaler Args-Hash: $LOCAL_ARGS_HASH"
if [[ "${{ steps.prep.outputs.event_name }}" != "schedule" ]]; then
echo "🚀 Manueller Start: Build erzwungen."
else
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"
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
# 1. Base Digest aus Annotation holen
USED_BASE_SHA=$(echo "$RAW_INDEX" | grep "\"pi_farm.base_digest\":" | sed -E 's/.*: "([^"]+)".*/\1/' || echo "none")
# 2. Args Hash aus Annotation holen (NEU!)
USED_ARGS_HASH=$(echo "$RAW_INDEX" | grep "\"pi_farm.args_hash\":" | sed -E 's/.*: "([^"]+)".*/\1/' || echo "none")
echo " Remote Base SHA: $USED_BASE_SHA"
echo " Remote Args Hash: $USED_ARGS_HASH"
# Logik: Build wenn Base anders ODER Args anders
if [ "$REMOTE_BASE_SHA" == "$USED_BASE_SHA" ] && [ "$LOCAL_ARGS_HASH" == "$USED_ARGS_HASH" ]; then
echo "😴 Alles identisch. Kein Build nötig."
SHOULD_BUILD="false"
else
echo "✅ Update nötig (Base oder Args geändert)."
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 }}
ARGS_HASH=${{ steps.prep.outputs.build_args_hash }}
set -a
source <(grep -v '^#' buildargs.env | sed 's/\r$//')
set +a
# Wir übergeben trotzdem ALLE Variablen als Build-Arg.
# Docker ist schlau genug, nicht genutzte Args zu ignorieren.
DOCKER_ARGS=""
keys=$(grep -v '^#' buildargs.env | cut -d'=' -f1 | tr -d '\r')
for k in $keys; do
val="${!k}"
DOCKER_ARGS="$DOCKER_ARGS --build-arg $k=$val"
done
RESOLVED_BASE=$(echo $BASE)
BASE_SHA=$(docker buildx imagetools inspect $RESOLVED_BASE --format '{{json .Manifest.Digest}}' 2>/dev/null | tr -d '"' || echo "unknown")
# WICHTIG: Wir speichern jetzt ZWEI Informationen im Label/Annotation
# AMD64 Build
docker buildx build $DOCKER_ARGS --pull --platform linux/amd64 -f Dockerfile \
--label "pi_farm.base_digest=$BASE_SHA" \
--label "pi_farm.args_hash=$ARGS_HASH" \
-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" \
--label "pi_farm.args_hash=$ARGS_HASH" \
-t $IMAGE:tmp-arm64 --push .
# Manifest Create (mit Annotationen im Index)
docker buildx imagetools create \
--annotation "index:pi_farm.base_digest=$BASE_SHA" \
--annotation "index:pi_farm.args_hash=$ARGS_HASH" \
-t $IMAGE:$TAG $IMAGE:tmp-amd64 $IMAGE:tmp-arm64
docker buildx imagetools create \
--annotation "index:pi_farm.base_digest=$BASE_SHA" \
--annotation "index:pi_farm.args_hash=$ARGS_HASH" \
-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
# Dieser Step läuft, wenn gebaut wurde ODER wenn manuell gepusht wurde (für Env-Änderungen)
if: steps.check_changes.outputs.should_build == 'true' || gitea.event_name == 'push'
run: |
set -x # <--- AKTIVIERT DAS TRACING
export TZ=Europe/Berlin
CURRENT_TIME=$(date +'%d.%m.%Y %H:%M')
BUILD_DATE_ONLY=$(date +'%d.%m.%Y')
# --- HIER IST DIE BRÜCKE: Outputs in Shell-Variablen laden ---
# Wir nutzen die Namen, die du im 'prep' Step definiert hast
BUILD_TAG="${{ steps.prep.outputs.docker_tag }}"
FULL_URL="${{ steps.prep.outputs.image_name }}"
REPO_PURE="${{ steps.prep.outputs.repo_pure }}"
BASE_IMAGE="${{ steps.prep.outputs.base_image }}"
# Zusätzliche Info für ARM Status
[ -f "Dockerfile.aarch64" ] && ARM_STATUS="✅ Aktiv (eigenes Dockerfile)" || ARM_STATUS="✅ Aktiv (via Standard Dockerfile)"
# Env laden für die Werteeretzung (z.B. für die Generatoren)
set -a
source <(grep -v '^#' buildargs.env | sed 's/\r$//')
set +a
# Commit Message Logik
if [[ "${{ steps.prep.outputs.event_name }}" == "schedule" ]]; then
COMMIT_MSG="Automatischer Security-Rebuild"
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
# Templates laden
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
# History Update
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)
# --- GENERATOREN (Block-Bau) ---
# 1. Environment Block
ENV_BLOCK_CONTENT=""
env_vars=$(grep '^ENV_' buildargs.env | grep -v '^#' | tr -d '\r' || true)
if [ ! -z "$env_vars" ]; then
ENV_BLOCK_CONTENT=" environment:\\n" # Header nur wenn Variablen da sind
for line in $env_vars; do
key=$(echo "$line" | cut -d'=' -f1)
val="${!key}"
clean_key=${key#ENV_}
ENV_BLOCK_CONTENT="${ENV_BLOCK_CONTENT} - ${clean_key}=${val}\\n"
done
fi
# 2. Ports Block
PORTS_BLOCK_CONTENT=""
port_vars=$(grep '^PORT_' buildargs.env | grep -v '^#' | tr -d '\r' || true)
if [ ! -z "$port_vars" ]; then
PORTS_BLOCK_CONTENT=" ports:\\n"
for line in $port_vars; do
key=$(echo "$line" | cut -d'=' -f1)
val="${!key}"
PORTS_BLOCK_CONTENT="${PORTS_BLOCK_CONTENT} - \"${val}\"\\n"
done
fi
# 3. Volumes Block
VOL_BLOCK_CONTENT=""
vol_vars=$(grep '^VOL_' buildargs.env | grep -v '^#' | tr -d '\r' || true)
if [ ! -z "$vol_vars" ]; then
VOL_BLOCK_CONTENT=" volumes:\\n"
for line in $vol_vars; do
key=$(echo "$line" | cut -d'=' -f1)
val="${!key}"
VOL_BLOCK_CONTENT="${VOL_BLOCK_CONTENT} - ${val}\\n"
done
fi
# DOCKER RUN GENERATOR
RUN_CMD="docker run -d \\ \n --name ${REPO_PURE} \\ \n --restart unless-stopped"
# Variablen aus buildargs.env für RUN-Befehl sammeln
# Wir nutzen hier direkt die exportierten Werte
while read -r line; do
[[ $line =~ ^PORT_ ]] && val="${line#*=}" && RUN_CMD="${RUN_CMD} \\ \n -p ${val}"
if [[ $line =~ ^ENV_ ]]; then
key="${line%%=*}"; clean_key="${key#ENV_}"; val="${!key}"
RUN_CMD="${RUN_CMD} \\ \n -e ${clean_key}=${val}"
fi
[[ $line =~ ^VOL_ ]] && val="${line#*=}" && RUN_CMD="${RUN_CMD} \\ \n -v ${val}"
done < <(grep -E '^(PORT_|ENV_|VOL_)' buildargs.env | grep -v '^#' | sed 's/\r$//')
RUN_CMD="${RUN_CMD} \\ \n ${FULL_URL}:${BUILD_TAG}"
DOCKER_RUN_FINAL=$(echo -e "$RUN_CMD")
# TEMPLATE ENGINE
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_PURE}"
line="${line//__FULL_URL__/$FULL_URL}"
line="${line//__BUILD_TAG__/$BUILD_TAG}"
line="${line//__BASE_IMAGE__/$BASE_IMAGE}"
line="${line//__CURRENT_DATE__/$CURRENT_TIME}"
line="${line//__HISTORY_CONTENT__/$HISTORY_CONTENT}"
line="${line//__DOCKER_RUN__/$DOCKER_RUN_FINAL}" # <--- NEU
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@pi-farm.de"
git config --local user.name "Gitea 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 }}"