Files
docker-baseimage-alpine/.gitea/workflows/build-and-push.yaml
pi-farm bccd8aa596
All checks were successful
/ release-and-build (push) Successful in 1m32s
add fix for latest-tag in workflow
2026-02-19 23:01:13 +01:00

452 lines
19 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: Prepare Environment and Read Config
id: prep
run: |
export TZ=Europe/Berlin
set -a
source <(grep -v '^#' buildargs.env | sed 's/\r$//')
set +a
echo "push_targets=$PUSH" >> $GITHUB_OUTPUT
LATEST_FLAG="${BUILD_TAG_LATEST:-n}"
LATEST_FLAG_LOWER=$(echo "$LATEST_FLAG" | tr '[:upper:]' '[:lower:]')
echo "tag_latest=$LATEST_FLAG_LOWER" >> $GITHUB_OUTPUT
ARGS_HASH=$(grep "^BUILD_" buildargs.env | sha256sum | cut -d' ' -f1)
echo "build_args_hash=$ARGS_HASH" >> $GITHUB_OUTPUT
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:-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 "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 "🔍 Check Remote-Registry..."
if [[ "${{ steps.prep.outputs.event_name }}" != "schedule" ]]; then
echo "🚀 Start: Build forced."
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 not readable. Build process started."
else
RAW_INDEX=$(docker buildx imagetools inspect "$IMAGE:$TAG" --raw 2>/dev/null || echo "")
if [ -z "$RAW_INDEX" ]; then
echo "🆕 Image doesn't exist. Build required."
else
USED_BASE_SHA=$(echo "$RAW_INDEX" | grep "\"pi_farm.base_digest\":" | sed -E 's/.*: "([^"]+)".*/\1/' || echo "none")
USED_ARGS_HASH=$(echo "$RAW_INDEX" | grep "\"pi_farm.args_hash\":" | sed -E 's/.*: "([^"]+)".*/\1/' || echo "none")
if [ "$REMOTE_BASE_SHA" == "$USED_BASE_SHA" ] && [ "$LOCAL_ARGS_HASH" == "$USED_ARGS_HASH" ]; then
echo "😴 All identic. Build not neccessary."
SHOULD_BUILD="false"
else
echo "✅ Build neccessary."
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: Login to Docker Hub
if: contains(steps.prep.outputs.push_targets, 'dockerhub')
uses: https://github.com/docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and Push Docker Image
if: steps.check_changes.outputs.should_build == 'true'
run: |
IMAGE_GITEA=${{ steps.prep.outputs.image_name }}
TAG=${{ steps.prep.outputs.docker_tag }}
ARGS_HASH=${{ steps.prep.outputs.build_args_hash }}
BASE=${{ steps.prep.outputs.base_image }}
REPO_PURE=${{ steps.prep.outputs.repo_pure }}
# NEU: Wir laden unser Flag rein
TAG_LATEST="${{ steps.prep.outputs.tag_latest }}"
set -a
source <(grep -v '^#' buildargs.env | sed 's/\r$//')
set +a
DOCKER_ARGS=()
keys=$(grep -v '^#' buildargs.env | cut -d'=' -f1 | tr -d '\r')
for k in $keys; do
DOCKER_ARGS+=("--build-arg" "$k=${!k}")
done
BASE_SHA=$(docker buildx imagetools inspect $BASE --format '{{json .Manifest.Digest}}' 2>/dev/null | tr -d '"' || echo "unknown")
AMD_TAGS=("-t" "$IMAGE_GITEA:tmp-amd64")
ARM_TAGS=("-t" "$IMAGE_GITEA:tmp-arm64")
if [[ "$PUSH" == *"dockerhub"* ]]; then
DOCKERHUB_REPO="${{ secrets.DOCKERHUB_USERNAME }}/$REPO_PURE"
AMD_TAGS+=("-t" "$DOCKERHUB_REPO:tmp-amd64")
ARM_TAGS+=("-t" "$DOCKERHUB_REPO:tmp-arm64")
fi
docker buildx build "${DOCKER_ARGS[@]}" "${AMD_TAGS[@]}" \
--pull --platform linux/amd64 -f Dockerfile \
--label "pi_farm.base_digest=$BASE_SHA" --label "pi_farm.args_hash=$ARGS_HASH" --push .
docker buildx build "${DOCKER_ARGS[@]}" "${ARM_TAGS[@]}" \
--pull --platform linux/arm64 -f Dockerfile.aarch64 \
--label "pi_farm.base_digest=$BASE_SHA" --label "pi_farm.args_hash=$ARGS_HASH" --push .
# --- NEU: Dynamische Tags für Gitea ---
GITEA_TAGS=("-t" "$IMAGE_GITEA:$TAG")
if [ "$TAG_LATEST" == "y" ]; then
GITEA_TAGS+=("-t" "$IMAGE_GITEA:latest")
echo "🏷️ Gitea: 'latest' tag will be set."
else
echo " Gitea: 'latest' tag will not be set."
fi
docker buildx imagetools create \
--annotation "index:pi_farm.base_digest=$BASE_SHA" --annotation "index:pi_farm.args_hash=$ARGS_HASH" \
"${GITEA_TAGS[@]}" $IMAGE_GITEA:tmp-amd64 $IMAGE_GITEA:tmp-arm64
if [[ "$PUSH" == *"dockerhub"* ]]; then
DOCKERHUB_REPO="${{ secrets.DOCKERHUB_USERNAME }}/$REPO_PURE"
DH_TAGS=("-t" "$DOCKERHUB_REPO:$TAG")
if [ "$TAG_LATEST" == "y" ]; then
DH_TAGS+=("-t" "$DOCKERHUB_REPO:latest")
echo "🏷️ Docker Hub: 'latest' tag will be set."
else
echo " Docker Hub: 'latest' tag will not be set."
fi
docker buildx imagetools create \
--annotation "index:pi_farm.base_digest=$BASE_SHA" --annotation "index:pi_farm.args_hash=$ARGS_HASH" \
"${DH_TAGS[@]}" $IMAGE_GITEA:tmp-amd64 $IMAGE_GITEA:tmp-arm64
fi
- name: Update Documentation and Compose
id: update_doc
if: steps.check_changes.outputs.should_build == 'true'
run: |
set -x
# --- 1. VARIABLEN VORBEREITEN ---
export TZ=Europe/Berlin
CURRENT_TIME=$(date '+%d.%m.%Y %H:%M')
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 }}"
if [ ! -f "buildargs.env" ]; then echo "❌ buildargs.env missing!"; exit 1; fi
grep -v '^#' buildargs.env | sed 's/\r$//' > cleaned_env.sh
set -a
source ./cleaned_env.sh
set +a
if [ -f "Dockerfile.aarch64" ]; then ARM_STATUS="✅ Active"; else ARM_STATUS="❌ Not supported"; fi
cat << 'EOF' > commit_msg.txt
${{ gitea.event.head_commit.message }}
EOF
COMMIT_MSG=$(sed 's/\[skip ci\]//g' commit_msg.txt | xargs)
# --- 2. TEMPLATES LADEN ---
wget -q https://git.pi-farm.de/pi-farm/templates/raw/branch/main/README.template -O README.template || echo "Warnung: README Template fehlt"
wget -q https://git.pi-farm.de/pi-farm/templates/raw/branch/main/docker-compose.template -O docker-compose.template || echo "Warnung: Compose Template fehlt"
# --- 3. VERSION HISTORY ---
NEW_ROW="| **$BUILD_TAG** | $CURRENT_TIME | $COMMIT_MSG ✅ |"
if [ -f "VERSION.history" ]; then
grep -v "| **$BUILD_TAG** |" VERSION.history > VERSION.history.tmp || true
echo "$NEW_ROW" > VERSION.history
cat VERSION.history.tmp >> VERSION.history
rm VERSION.history.tmp
else
echo "$NEW_ROW" > VERSION.history
fi
HISTORY_CONTENT=$(cat VERSION.history)
ENV_BLOCK_CONTENT=""
env_vars=$(grep '^ENV_' buildargs.env | grep -v '^#' | tr -d '\r' || true)
if [ -n "$env_vars" ]; then
ENV_BLOCK_CONTENT=" environment:\n"
while read -r line; do
[ -z "$line" ] && continue
key=$(echo "$line" | cut -d= -f1); val=$(echo "$line" | cut -d= -f2-); clean_key=${key#ENV_}
ENV_BLOCK_CONTENT="${ENV_BLOCK_CONTENT} - ${clean_key}=${val}\n"
done <<< "$env_vars"
fi
PORTS_BLOCK_CONTENT=""
port_vars=$(grep '^PORT_' buildargs.env | grep -v '^#' | tr -d '\r' || true)
if [ -n "$port_vars" ]; then
PORTS_BLOCK_CONTENT=" ports:\n"
while read -r line; do
[ -z "$line" ] && continue
val=$(echo "$line" | cut -d= -f2-); PORTS_BLOCK_CONTENT="${PORTS_BLOCK_CONTENT} - ${val}\n"
done <<< "$port_vars"
fi
VOL_BLOCK_CONTENT=""
vol_vars=$(grep '^VOL_' buildargs.env | grep -v '^#' | tr -d '\r' || true)
if [ -n "$vol_vars" ]; then
VOL_BLOCK_CONTENT=" volumes:\n"
while read -r line; do
[ -z "$line" ] && continue
val=$(echo "$line" | cut -d= -f2-); VOL_BLOCK_CONTENT="${VOL_BLOCK_CONTENT} - ${val}\n"
done <<< "$vol_vars"
fi
# --- 5. DOCKER RUN BEFEHL (NEU: Als Datei schreiben) ---
# Wir schreiben direkt in eine Datei. Da gibt es keine Interpretationsfehler.
# Wichtig: " \\" am Ende der Zeilen explizit hinschreiben.
{
echo "docker run -d \\"
echo " --name $REPO_PURE \\"
echo " --restart unless-stopped \\"
all_params=$(grep -E '^(PORT_|ENV_|VOL_)' buildargs.env | grep -v '^#' | sed 's/\r$//' || true)
if [ -n "$all_params" ]; then
while read -r line; do
[ -z "$line" ] && continue
if [[ "$line" =~ ^PORT_ ]]; then
val=$(echo "$line" | cut -d= -f2-)
echo " -p ${val} \\"
elif [[ "$line" =~ ^ENV_ ]]; then
key=$(echo "$line" | cut -d= -f1); clean_key=${key#ENV_}; val=$(echo "$line" | cut -d= -f2-)
echo " -e ${clean_key}=${val} \\"
elif [[ "$line" =~ ^VOL_ ]]; then
val=$(echo "$line" | cut -d= -f2-)
echo " -v ${val} \\"
fi
done <<< "$all_params"
fi
# Letzte Zeile OHNE Backslash
echo " $FULL_URL:$BUILD_TAG"
} > docker_run_block.txt
# --- 6. DOCKER HUB LINK ---
DOCKERHUB_LINK_CONTENT=""
if [[ "${{ steps.prep.outputs.push_targets }}" == *"dockerhub"* ]]; then
DH_USER="${{ secrets.DOCKERHUB_USERNAME }}"
DOCKERHUB_LINK_CONTENT="[![Docker Hub](https://img.shields.io/badge/docker-hub-blue?logo=docker&logoColor=white)](https://hub.docker.com/r/${DH_USER}/${REPO_PURE})"
fi
# --- 7. TEMPLATE ENGINE (Optimiert für File-Injection) ---
process_template() {
local template=$1; local output=$2
[ ! -f "$template" ] && return
cp "$template" "$output"
# Simple Ersetzungen
sed -i "s|__REPO_NAME__|$REPO_PURE|g" "$output"
sed -i "s|__FULL_URL__|$FULL_URL|g" "$output"
sed -i "s|__BUILD_TAG__|$BUILD_TAG|g" "$output"
sed -i "s|__BASE_IMAGE__|$BASE_IMAGE|g" "$output"
sed -i "s|__ARM_STATUS__|$ARM_STATUS|g" "$output"
sed -i "s|__CURRENT_DATE__|$CURRENT_TIME|g" "$output"
# Komplexe Blöcke: AWK für Strings, SED für Files
awk -v r="$HISTORY_CONTENT" '{gsub(/__HISTORY_CONTENT__/, r)}1' "$output" > "$output.tmp" && mv "$output.tmp" "$output"
awk -v r="$DOCKERHUB_LINK_CONTENT" '{gsub(/__DOCKERHUB_LINK__/, r)}1' "$output" > "$output.tmp" && mv "$output.tmp" "$output"
# NEU: Docker Run Block via File einfügen (sicherste Methode)
if grep -q "__DOCKER_RUN__" "$output" && [ -f "docker_run_block.txt" ]; then
sed -e '/__DOCKER_RUN__/{r docker_run_block.txt' -e 'd;}' "$output" > "$output.tmp" && mv "$output.tmp" "$output"
fi
# Compose Block via File einfügen
if grep -q "__COMPOSE_BLOCK__" "$output" && [ -f "docker-compose.yml" ]; then
sed -e '/__COMPOSE_BLOCK__/{r docker-compose.yml' -e 'd;}' "$output" > "$output.tmp" && mv "$output.tmp" "$output"
fi
# ENV/PORTS/VOL Blöcke
if grep -q "__ENV_BLOCK__" "$output"; then
awk -v r="$(echo -e "$ENV_BLOCK_CONTENT")" '{gsub(/__ENV_BLOCK__/, r)}1' "$output" > "$output.tmp" && mv "$output.tmp" "$output"
fi
awk -v r="$(echo -e "$PORTS_BLOCK_CONTENT")" '{gsub(/__PORTS_BLOCK__/, r)}1' "$output" > "$output.tmp" && mv "$output.tmp" "$output"
awk -v r="$(echo -e "$VOL_BLOCK_CONTENT")" '{gsub(/__VOL_BLOCK__/, r)}1' "$output" > "$output.tmp" && mv "$output.tmp" "$output"
# Description als letztes
if grep -q "__DESCRIPTION__" "$output"; then
awk -v r="$(echo -e "${DESCRIPTION:-Keine Beschreibung.}")" '{gsub(/__DESCRIPTION__/, r)}1' "$output" > "$output.tmp" && mv "$output.tmp" "$output"
fi
}
process_template "docker-compose.template" "docker-compose.yml"
process_template "README.template" "README.md"
# --- 8. EXPORTS ---
echo "FINAL_MSG=$COMMIT_MSG" >> $GITHUB_ENV
echo "DESCRIPTION<<EOF" >> $GITHUB_ENV
echo -e "$DESCRIPTION" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Push README to Docker Hub
if: steps.check_changes.outputs.should_build == 'true' && contains(steps.prep.outputs.push_targets, 'dockerhub')
run: |
if ! command -v jq &> /dev/null; then
apt-get update && apt-get install -y jq || apk add --no-cache jq || true
fi
echo "🚀 Starting update README on Docker Hub..."
TOKEN=$(curl -s -X POST "https://hub.docker.com/v2/users/login/" \
-H "Content-Type: application/json" \
-d "{\"username\": \"${{ secrets.DOCKERHUB_USERNAME }}\", \"password\": \"${{ secrets.DOCKERHUB_TOKEN }}\"}" | jq -r .token)
if [ "$TOKEN" == "null" ] || [ -z "$TOKEN" ]; then
echo "❌ Error: No login-token available. Check your credentials!"
exit 1
fi
REPO_PURE="${{ steps.prep.outputs.repo_pure }}"
DH_USER="${{ secrets.DOCKERHUB_USERNAME }}"
SHORT_DESC=$(echo -e "${{ env.DESCRIPTION }}" | head -n 1 | cut -c 1-100)
[ -z "$SHORT_DESC" ] && SHORT_DESC="Docker Image for $REPO_PURE"
echo "📦 Processing README.md (${REPO_PURE})..."
jq -n \
--arg desc "$SHORT_DESC" \
--rawfile full_desc README.md \
'{description: $desc, full_description: $full_desc}' > payload.json
echo "📤 Sending data to Docker Hub API..."
RESPONSE=$(curl -s -w "\n%{http_code}" -X PATCH \
"https://hub.docker.com/v2/repositories/${DH_USER}/${REPO_PURE}/" \
-H "Authorization: JWT ${TOKEN}" \
-H "Content-Type: application/json" \
-d @payload.json)
HTTP_STATUS=$(echo "$RESPONSE" | tail -n 1)
BODY=$(echo "$RESPONSE" | head -n -1)
if [ "$HTTP_STATUS" -eq 200 ]; then
echo "✅ README update successfull (HTTP 200)."
else
echo "❌ Error on update! HTTP Status: $HTTP_STATUS"
echo "Answer from Docker Hub: $BODY"
exit 1
fi
- 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 Temporary Tags on Docker Hub
if: steps.check_changes.outputs.should_build == 'true' && contains(steps.prep.outputs.push_targets, 'dockerhub')
run: |
if ! command -v jq &> /dev/null; then
(apt-get update && apt-get install -y jq) || (apk add --no-cache jq) || true
fi
echo "🧹 Cleanup temp. Docker Hub tags..."
TOKEN=$(curl -s -X POST "https://hub.docker.com/v2/users/login/" \
-H "Content-Type: application/json" \
-d "{\"username\": \"${{ secrets.DOCKERHUB_USERNAME }}\", \"password\": \"${{ secrets.DOCKERHUB_TOKEN }}\"}" | jq -r .token)
if [ "$TOKEN" != "null" ] && [ -n "$TOKEN" ]; then
REPO_PURE=${{ steps.prep.outputs.repo_pure }}
DH_USER="${{ secrets.DOCKERHUB_USERNAME }}"
for t in tmp-amd64 tmp-arm64; do
echo "Deleting tag $t..."
STATUS=$(curl -s -o /dev/null -w "%{http_code}" -X DELETE \
"https://hub.docker.com/v2/repositories/${DH_USER}/${REPO_PURE}/tags/$t/" \
-H "Authorization: JWT ${TOKEN}")
echo "Status: $STATUS"
done
echo "✅ Temp. tags deleted."
fi
- name: Cleanup Temporary Registry Tags (Gitea)
if: steps.check_changes.outputs.should_build == 'true'
run: |
TOKEN="${{ secrets.GIT_TOKEN }}"
ORG_NAME=$(echo "${{ gitea.repository }}" | cut -d'/' -f1)
REPO_NAME=$(echo "${{ gitea.repository }}" | cut -d'/' -f2)
for t in tmp-amd64 tmp-arm64; do
curl -s -X DELETE "https://git.pi-farm.de/api/v1/packages/$ORG_NAME/container/$REPO_NAME/$t" -H "Authorization: token $TOKEN"
curl -s -X DELETE "https://git.pi-farm.de/api/v1/packages/${ORG_NAME,,}/container/${REPO_NAME,,}/$t" -H "Authorization: token $TOKEN"
done
- 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 }}"