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