diff --git a/.gitea/workflows/docker-builder.yml b/.gitea/workflows/docker-builder.yml index 563f3d0..3b8e8c6 100644 --- a/.gitea/workflows/docker-builder.yml +++ b/.gitea/workflows/docker-builder.yml @@ -3,9 +3,12 @@ name: Docker Build Smart Logic on: push: branches: - - '**' + - main + tags: + - 'v*' workflow_dispatch: + env: REGISTRY_HOST: git.pi-farm.de IMAGE_BASE: ${{ gitea.repository }} @@ -16,10 +19,21 @@ jobs: runs-on: buildx-multiarch steps: + - name: Checkout repository uses: http://git.pi-farm.de/pi-farm/checkout@v4 with: fetch-depth: 0 + fetch-tags: true + + - name: Dump context + run: env | sort + + - name: Show ref info + run: | + echo "REF=$GITHUB_REF" + echo "REF_TYPE=$GITHUB_REF_TYPE" + echo "REF_NAME=$GITHUB_REF_NAME" - name: Dynamic Template Fix id: template_fix @@ -49,6 +63,31 @@ jobs: echo "Platzhalter bereits ersetzt." fi + - name: Detect version + id: detect_version + run: | + echo "== Detect version ==" + # Prüfen, ob wir auf einem Tag oder main-Branch sind + if [ "$GITHUB_REF_TYPE" = "tag" ]; then + VERSION="$GITHUB_REF_NAME" + CLEAN_VERSION="${VERSION#v}" # entfernt führendes 'v' + IS_TAG=true + else + VERSION="main" + CLEAN_VERSION="main" + IS_TAG=false + fi + + echo "VERSION=$VERSION" + echo "CLEAN_VERSION=$CLEAN_VERSION" + echo "IS_TAG=$IS_TAG" + + # Env für alle weiteren Steps exportieren + echo "VERSION=$VERSION" >> $GITHUB_ENV + echo "CLEAN_VERSION=$CLEAN_VERSION" >> $GITHUB_ENV + echo "IS_TAG=$IS_TAG" >> $GITHUB_ENV + + - name: Set dynamic variables and check Dockerfiles id: check_files run: | @@ -69,7 +108,6 @@ jobs: ARM64_FILE="Dockerfile" fi - echo "VERSION=${{ gitea.ref_name }}" >> $GITEA_ENV echo "IMAGE_NAME=${{ env.REGISTRY_HOST }}/${{ env.IMAGE_BASE }}" >> $GITEA_ENV echo "CACHE_IMAGE_NAME=${{ env.REGISTRY_HOST }}/${{ env.IMAGE_BASE }}-cache" >> $GITEA_ENV echo "AMD64_DOCKERFILE=$AMD64_FILE" >> $GITEA_ENV @@ -89,39 +127,124 @@ jobs: docker buildx create --name multiarch --driver docker-container --use docker buildx inspect --bootstrap - - name: Build & push amd64 (Cache) - if: steps.check_files.outputs.should_build == 'true' + - name: Compute Docker tags run: | - docker buildx build --platform linux/amd64 -f ${AMD64_DOCKERFILE} \ - --build-arg BUILD_DATE=${BUILD_DATE} --build-arg VERSION=${VERSION} \ - -t ${CACHE_IMAGE_NAME}:${VERSION}-amd64 --push . + if [[ "$IS_TAG" == "true" ]]; then + DOCKER_TAGS="${IMAGE_NAME}:${VERSION},${IMAGE_NAME}:latest" + else + DOCKER_TAGS="${IMAGE_NAME}:main" + fi - - name: Build & push arm64 (Cache) - if: steps.check_files.outputs.should_build == 'true' - run: | - docker buildx build --platform linux/arm64 -f ${ARM64_DOCKERFILE} \ - --build-arg BUILD_DATE=${BUILD_DATE} --build-arg VERSION=${VERSION} \ - -t ${CACHE_IMAGE_NAME}:${VERSION}-arm64 --push . + echo "DOCKER_TAGS=$DOCKER_TAGS" >> $GITEA_ENV - - name: Create and push manifest to Prod - if: steps.check_files.outputs.should_build == 'true' + - name: Load versions.env safely + shell: bash run: | - docker buildx imagetools create -t ${IMAGE_NAME}:${VERSION} \ - ${CACHE_IMAGE_NAME}:${VERSION}-amd64 \ - ${CACHE_IMAGE_NAME}:${VERSION}-arm64 + echo "== Load versions.env ==" - - name: Cleanup Cache Images + # Funktion zum sauberen Parsen + parse_env() { + grep -v '^#' versions.env | grep -v '^$' | while IFS='=' read -r key value; do + # Entferne mögliche Whitespaces + key=$(echo $key | xargs) + value=$(echo $value | xargs) + export $key="$value" + done + } + + parse_env + + # Fixen von Workflow-Variablen + CLEAN_VERSION="${VERSION#v}" + BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) + + # Write to Gitea env + echo "BASE_IMAGE=$BASE_IMAGE" >> $GITEA_ENV + echo "APP_VERSION=$APP_VERSION" >> $GITEA_ENV + echo "TARGET_PLATFORMS=$TARGET_PLATFORMS" >> $GITEA_ENV + echo "IMAGE_NAME=${REGISTRY_HOST}/$IMAGE_BASE" >> $GITEA_ENV + echo "CACHE_IMAGE_NAME=${REGISTRY_HOST}/$IMAGE_BASE-cache" >> $GITEA_ENV + echo "VERSION=$VERSION" >> $GITEA_ENV + echo "CLEAN_VERSION=$CLEAN_VERSION" >> $GITEA_ENV + echo "BUILD_DATE=$BUILD_DATE" >> $GITEA_ENV + + + - name: Build & push multiarch if: steps.check_files.outputs.should_build == 'true' + shell: bash run: | - # Wir nutzen die Gitea API, um die temporären Cache-Tags zu löschen - REPO_NAME=$(echo "${{ gitea.repository }}" | cut -d'/' -f2) - OWNER_NAME=$(echo "${{ gitea.repository }}" | cut -d'/' -f1) - - echo "Bereinige Cache-Images für ${REPO_NAME}-cache..." - - for TAG in "${VERSION}-amd64" "${VERSION}-arm64"; do - echo "Lösche Tag: ${TAG}" - curl -X DELETE \ - -H "Authorization: token ${{ secrets.REGISTRY_TOKEN }}" \ - "https://${{ env.REGISTRY_HOST }}/api/v1/packages/${OWNER_NAME}/container/${REPO_NAME}-cache/${TAG}" || echo "Tag ${TAG} konnte nicht gelöscht werden oder existierte nicht." - done \ No newline at end of file + echo "== Multiarch Build Start ==" + + # versions.env direkt hier laden + BASE_IMAGE=$(grep ^BASE_IMAGE= versions.env | cut -d '=' -f2-) + APP_VERSION=$(grep ^APP_VERSION= versions.env | cut -d '=' -f2-) + + echo "BASE_IMAGE=$BASE_IMAGE" + echo "APP_VERSION=$APP_VERSION" + + if [ -z "$BASE_IMAGE" ]; then + echo "BASE_IMAGE is empty → abort" + exit 1 + fi + + # Cache-Definitionen für bessere Übersicht + CACHE_REF="${REGISTRY_HOST}/${IMAGE_BASE}-cache" + + # amd64 build mit Registry-Cache (mode=min für weniger Fragmente) + docker buildx build \ + --platform linux/amd64 \ + -f ${AMD64_DOCKERFILE} \ + --build-arg BASE_IMAGE="$BASE_IMAGE" \ + --build-arg APP_VERSION="$APP_VERSION" \ + --label org.opencontainers.image.version="$APP_VERSION" \ + --label org.opencontainers.image.created="$BUILD_DATE" \ + --cache-from type=registry,ref=${CACHE_REF}:amd64 \ + --cache-to type=registry,ref=${CACHE_REF}:amd64,mode=min \ + -t ${CACHE_IMAGE_NAME}:${VERSION}-amd64 \ + --push . + + # arm64 build mit Registry-Cache (mode=min für weniger Fragmente) + docker buildx build \ + --platform linux/arm64 \ + -f ${ARM64_DOCKERFILE} \ + --build-arg BASE_IMAGE="$BASE_IMAGE" \ + --build-arg APP_VERSION="$APP_VERSION" \ + --label org.opencontainers.image.version="$APP_VERSION" \ + --label org.opencontainers.image.created="$BUILD_DATE" \ + --cache-from type=registry,ref=${CACHE_REF}:arm64 \ + --cache-to type=registry,ref=${CACHE_REF}:arm64,mode=min \ + -t ${CACHE_IMAGE_NAME}:${VERSION}-arm64 \ + --push . + + # Manifest-Erstellung (verbindet die Architekturen zu den finalen Tags) + for TAG in $(echo $DOCKER_TAGS | tr ',' ' '); do + echo "Creating manifest for tag: $TAG" + docker buildx imagetools create -t $TAG \ + ${CACHE_IMAGE_NAME}:${VERSION}-amd64 \ + ${CACHE_IMAGE_NAME}:${VERSION}-arm64 + done + + echo "== Multiarch Build Complete ==" + + - name: Install syft + run: | + curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh \ + | sh -s -- -b /usr/local/bin + + - name: Generate SBOM + run: | + # Benutze die Build-Variable DOCKER_TAGS oder IMAGE_NAME + VERSION + if [[ "$IS_TAG" == "true" ]]; then + TARGET_IMAGE="${IMAGE_NAME}:${VERSION}" + else + TARGET_IMAGE="${IMAGE_NAME}:main" + fi + + echo "Generating SBOM for $TARGET_IMAGE" + syft $TARGET_IMAGE -o spdx-json > sbom.spdx.json || true + + - name: Upload SBOM + uses: actions/upload-artifact@v3 + with: + name: sbom + path: sbom.spdx.json \ No newline at end of file