Docker-Image bauen / build (push) Successful in 1m31s
Der bisherige Schritt hängte das Arbeitsverzeichnis mit -v "$PWD":/app in einen Container. Läuft der Gitea-Runner selbst in einem Container, zeigt $PWD auf einen Pfad, den der Docker-Daemon des Hosts nicht kennt: der Mount wäre leer, pytest fände keine Tests und meldete Erfolg. Wieder ein Test, der nicht hätte fehlschlagen können. Jetzt über Dockerfile.test - der Code kommt über den Build-Kontext hinein, unabhängig davon, wie der Runner aufgebaut ist. tests/ bleibt dafür im Kontext; das Anwendungs-Image kopiert sie weiterhin nicht mit. Lokal genauso ausgeführt wie die CI es tun wird: 81 Tests grün. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GR4bNaj9GtRu57J4Niii8o
155 lines
6.2 KiB
YAML
155 lines
6.2 KiB
YAML
name: Docker-Image bauen
|
|
|
|
# Baut das Image, sobald ein Versions-Tag (v1.2.3) gepusht wird, und legt es
|
|
# in der eingebauten Container-Registry von Gitea ab. Bewusst NICHT bei
|
|
# jedem Push auf main: so bleibt das Zusammenführen von Branches folgenlos
|
|
# und ein Release ist ein bewusster Schritt.
|
|
on:
|
|
push:
|
|
tags:
|
|
- 'v*'
|
|
workflow_dispatch:
|
|
|
|
env:
|
|
REGISTRY: gitea.boing86.myds.me
|
|
IMAGE_NAME: docker/kleiderboerse
|
|
|
|
jobs:
|
|
build:
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
|
|
steps:
|
|
- name: Quellcode auschecken
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Tests
|
|
run: |
|
|
set -eu
|
|
# Über den Build-Kontext statt per Bind-Mount: läuft der Runner
|
|
# selbst in einem Container, zeigt $PWD auf einen Pfad, den der
|
|
# Docker-Daemon des Hosts nicht kennt - der Mount wäre leer und
|
|
# die Tests liefen ohne Fehlermeldung ins Leere.
|
|
docker build -f Dockerfile.test -t kleiderboerse-tests .
|
|
docker run --rm kleiderboerse-tests
|
|
|
|
- name: Version bestimmen
|
|
id: meta
|
|
env:
|
|
# Bewusst über die Umgebung statt direkt als ${{ ... }} im Skript:
|
|
# Ausdrücke werden vor der Shell eingesetzt, und Tag-Namen dürfen
|
|
# Zeichen wie " oder $ enthalten. Als Variable kann daraus kein
|
|
# zusätzlicher Befehl werden.
|
|
REF_TYPE: ${{ github.ref_type }}
|
|
REF_NAME: ${{ github.ref_name }}
|
|
run: |
|
|
set -eu
|
|
if [ "$REF_TYPE" = "tag" ]; then
|
|
VERSION="$REF_NAME"
|
|
VERSION="${VERSION#v}" # v1.2.3 -> 1.2.3
|
|
IS_RELEASE=true
|
|
else
|
|
VERSION="manual-$(date +%Y%m%d-%H%M%S)"
|
|
IS_RELEASE=false
|
|
fi
|
|
# Die Registry behandelt Namen case-insensitiv -> konsequent klein.
|
|
VERSION="$(echo "$VERSION" | tr '[:upper:]' '[:lower:]')"
|
|
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
echo "is_release=$IS_RELEASE" >> "$GITHUB_OUTPUT"
|
|
# Nur bei echten Tags eine Version in die Fusszeile schreiben; bei
|
|
# manuellen Läufen bleibt sie leer und es erscheint der Commit.
|
|
if [ "$IS_RELEASE" = "true" ]; then
|
|
echo "tag_version=$VERSION" >> "$GITHUB_OUTPUT"
|
|
else
|
|
echo "tag_version=" >> "$GITHUB_OUTPUT"
|
|
fi
|
|
echo "Version: $VERSION (Release: $IS_RELEASE)"
|
|
|
|
- name: Image bauen
|
|
run: |
|
|
set -eu
|
|
docker build \
|
|
--tag "$REGISTRY/$IMAGE_NAME:${{ steps.meta.outputs.version }}" \
|
|
--build-arg "APP_VERSION=${{ steps.meta.outputs.tag_version }}" \
|
|
--build-arg "APP_REVISION=${{ github.sha }}" \
|
|
--label "org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}" \
|
|
--label "org.opencontainers.image.revision=${{ github.sha }}" \
|
|
--label "org.opencontainers.image.version=${{ steps.meta.outputs.version }}" \
|
|
.
|
|
|
|
# Prüft das fertige Image, bevor irgendetwas veröffentlicht wird.
|
|
# Geprüft wird im Container selbst (kein Port-Mapping nötig, damit der
|
|
# Test unabhängig vom Netzwerk-Setup des Runners funktioniert).
|
|
- name: Image testen
|
|
run: |
|
|
set -eu
|
|
BILD="$REGISTRY/$IMAGE_NAME:${{ steps.meta.outputs.version }}"
|
|
CID=$(docker run -d -e ADMIN_PASSWORD=pruef -e SECRET_KEY=pruef "$BILD")
|
|
trap 'docker rm -f "$CID" >/dev/null 2>&1 || true' EXIT
|
|
|
|
for i in $(seq 1 30); do
|
|
# Einzeilig: ein mehrzeiliger String bräche den YAML-Block auf,
|
|
# weil dessen Fortsetzung links vom Einzug stünde.
|
|
if docker exec "$CID" python -c "import urllib.request as u; u.urlopen('http://localhost:8000/health')" 2>/dev/null; then
|
|
break
|
|
fi
|
|
if [ "$i" = "30" ]; then
|
|
echo "Anwendung im Container nicht erreichbar geworden:"
|
|
docker logs "$CID"
|
|
exit 1
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
# Stammdaten: ohne Kategorien und Grössen lässt sich nichts
|
|
# erfassen. Untergrenzen bewusst unter dem Ist-Stand, damit der
|
|
# Test nicht bei jeder Ergänzung anschlägt.
|
|
# -i ist zwingend: ohne angehängtes stdin bekommt "python -" ein
|
|
# leeres Programm, tut nichts und meldet Erfolg. Der Test könnte
|
|
# dann nie fehlschlagen.
|
|
docker exec -i "$CID" python - < scripts/image-pruefen.py
|
|
|
|
# Das CSS muss im Image liegen - es entsteht in einer eigenen
|
|
# Build-Stufe und würde bei einem Fehler dort still fehlen.
|
|
docker exec "$CID" test -s /app/app/static/style.css
|
|
echo "style.css vorhanden."
|
|
|
|
- name: An Registry anmelden
|
|
env:
|
|
# Optional: eigenes Token/Konto als Repo-Secret hinterlegen, falls
|
|
# der automatische GITEA_TOKEN nicht in die Registry schreiben darf.
|
|
REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }}
|
|
REGISTRY_USER: ${{ secrets.REGISTRY_USER }}
|
|
AUTO_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
AKTEUR: ${{ github.actor }}
|
|
run: |
|
|
set -eu
|
|
TOKEN="${REGISTRY_TOKEN:-$AUTO_TOKEN}"
|
|
BENUTZER="${REGISTRY_USER:-$AKTEUR}"
|
|
if [ -z "$TOKEN" ]; then
|
|
echo "Kein Token verfügbar: REGISTRY_TOKEN als Repo-Secret hinterlegen."
|
|
exit 1
|
|
fi
|
|
echo "Anmeldung an $REGISTRY als $BENUTZER"
|
|
# --password-stdin: so steht das Token weder in der Prozessliste
|
|
# noch im Protokoll.
|
|
echo "$TOKEN" | docker login "$REGISTRY" -u "$BENUTZER" --password-stdin
|
|
|
|
- name: Image veröffentlichen
|
|
run: |
|
|
set -eu
|
|
docker push "$REGISTRY/$IMAGE_NAME:${{ steps.meta.outputs.version }}"
|
|
|
|
# "latest" nur für echte Versions-Tags, nicht für manuelle Läufe.
|
|
if [ "${{ steps.meta.outputs.is_release }}" = "true" ]; then
|
|
docker tag "$REGISTRY/$IMAGE_NAME:${{ steps.meta.outputs.version }}" \
|
|
"$REGISTRY/$IMAGE_NAME:latest"
|
|
docker push "$REGISTRY/$IMAGE_NAME:latest"
|
|
fi
|
|
|
|
- name: Abmelden
|
|
if: always()
|
|
run: docker logout "$REGISTRY" || true
|