From 94d9cac77b550882dcc2a506997dcdd6c632f5bf Mon Sep 17 00:00:00 2001 From: tleininger Date: Mon, 21 Sep 2026 07:58:46 +0200 Subject: [PATCH] Add release/dev build scripts and branch-based deploy workflow - scripts/release.sh: build from main, tag :latest + short SHA, push both. Aborts if not on main or working tree is dirty; warns on unpushed commits. Prevents dev states from becoming :latest. - scripts/dev-build.sh: local dev image (tagged per branch), never pushed -- keeps development builds off the registry. - docs/deployment.md: document branch/PR workflow, replace manual build/push steps with the scripts, SHA-based rollback now standard. - .gitattributes: force LF on *.sh so the shebang works on Windows. Co-Authored-By: Claude Opus 4.8 --- .gitattributes | 3 ++ docs/deployment.md | 69 +++++++++++++++++++++++++------------------- scripts/dev-build.sh | 22 ++++++++++++++ scripts/release.sh | 55 +++++++++++++++++++++++++++++++++++ 4 files changed, 119 insertions(+), 30 deletions(-) create mode 100644 .gitattributes create mode 100644 scripts/dev-build.sh create mode 100644 scripts/release.sh diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..de4af22 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Shell-Skripte brauchen Unix-Zeilenenden (LF), sonst scheitert der #!-Aufruf +# in bash. Unabhaengig von core.autocrlf auf Windows erzwingen. +*.sh text eol=lf diff --git a/docs/deployment.md b/docs/deployment.md index d38cb8a..0329275 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -35,35 +35,44 @@ eingegeben werden muss. --- +## Arbeitsweise: Branches, nie direkt auf main + +`main` ist der **veröffentlichte** Stand — nur daraus wird `:latest` gebaut, und +nur `:latest` zieht Unraid. Deshalb wird nie direkt auf `main` committet: + +1. Feature-Branch anlegen: `git switch -c /` (z.B. + `deployment/sha-tagging`, `content/pipeline`). +2. Dort committen, Branch pushen: `git push -u origin `. +3. In Gitea einen **Pull Request** gegen `main` öffnen und dort mergen. +4. Erst danach aus `main` das Release-Image bauen (unten). + +**Dev-Images bleiben lokal.** Zum Ausprobieren auf dem eigenen Rechner: + +```bash +scripts/dev-build.sh # baut elternbeirat-web:dev-, pusht NICHTS +``` + +So kann ein Entwicklungsstand nie versehentlich als `:latest` in der Registry +landen. + ## Neuen Stand ausrollen (Handbetrieb) -Alle Befehle auf dem Entwicklungsrechner (Docker installiert), im Repo-Root. - -### 1. Image bauen +Voraussetzung: einmalig an der Registry angemeldet (siehe unten). Dann, **auf +main** und mit sauberem Arbeitsverzeichnis: ```bash -docker build -t gitea.anticarnist.de/tom/elternbeirat:latest . +scripts/release.sh ``` -Der Image-Pfad ist **kleingeschrieben** — Container-Registries verlangen das im -Pfad, obwohl Benutzer (`Tom`) und Repo (`Elternbeirat`) großgeschrieben sind. +Das Skript baut das Image, taggt es mit `:latest` **und** dem Commit-Kurz-SHA +(für Rollback) und pusht beide. Es **bricht ab**, wenn du nicht auf `main` bist +oder uncommittete Änderungen hast, und warnt bei ungepushten Commits. -### 2. An der Registry anmelden (einmalig, bis das Token wechselt) +> Der Image-Pfad `gitea.anticarnist.de/tom/elternbeirat` ist **kleingeschrieben** +> — Container-Registries verlangen das im Pfad, obwohl Benutzer (`Tom`) und Repo +> (`Elternbeirat`) großgeschrieben sind. -```bash -docker login gitea.anticarnist.de -``` - -- **Username:** `Tom` -- **Password:** das `package`-Token (nicht das Kontopasswort). - -### 3. Image in die Registry pushen - -```bash -docker push gitea.anticarnist.de/tom/elternbeirat:latest -``` - -### 4. Unraid einmalig an der Registry anmelden +### Unraid einmalig an der Registry anmelden Das Image ist **privat**, deshalb muss Unraid sich einmal anmelden, bevor es ziehen kann. Das **Compose Manager Plus**-Plugin hat dafür kein UI-Feld — der @@ -90,7 +99,7 @@ wechselt. Zwei erfahrungsgemäße Stolpersteine: `/root/.docker/config.json`. Auf dem eigenen Server für den Anfang okay. *Später sauberer:* einen Credential-Helper einrichten (→ offener Punkt unten). -### 5. Auf Unraid neu ziehen und starten +### Auf Unraid neu ziehen und starten Im **Compose Manager Plus**-Plugin (Unraid-Weboberfläche): @@ -150,17 +159,17 @@ networks: ## Rollback -`:latest` allein macht Rollback unmöglich — deshalb sobald wir auf Gitea Actions -umstellen (Schritt 10) **immer auch mit dem Commit-SHA taggen** und pushen: +`scripts/release.sh` taggt jeden Release zusätzlich mit dem Commit-Kurz-SHA, der +sich — anders als das wandernde `:latest` — nie verschiebt. Zum Zurückrollen in +der Unraid-`compose.yaml` `:latest` durch `:` des letzten funktionierenden +Stands ersetzen und neu hochfahren: -```bash -docker build -t gitea.anticarnist.de/tom/elternbeirat:latest \ - -t gitea.anticarnist.de/tom/elternbeirat: . -docker push gitea.anticarnist.de/tom/elternbeirat --all-tags +```yaml + image: gitea.anticarnist.de/tom/elternbeirat:99dd052 # statt :latest ``` -Zum Zurückrollen in der Unraid-`compose.yaml` `:latest` durch `:` des -letzten funktionierenden Stands ersetzen und neu hochfahren. +Welche SHA-Tags in der Registry liegen, zeigt Gitea unter +`Tom/-/packages` → `elternbeirat`. --- diff --git a/scripts/dev-build.sh b/scripts/dev-build.sh new file mode 100644 index 0000000..31c49a2 --- /dev/null +++ b/scripts/dev-build.sh @@ -0,0 +1,22 @@ +#!/usr/bin/env bash +# Baut ein lokales Dev-Image zum Ausprobieren auf dem eigenen Rechner. +# Pusht NICHTS in die Registry -- der Stand bleibt privat auf dem Laptop. +# +# Der Tag enthaelt den aktuellen Branchnamen, damit Dev-Images nicht mit dem +# Produktiv-:latest verwechselt werden. Anschliessend z.B. lokal starten: +# docker run --rm -p 5000:8080 elternbeirat-web:dev- +# oder ueber die lokale compose.yaml. + +set -euo pipefail + +cd "$(dirname "$0")/.." + +branch="$(git rev-parse --abbrev-ref HEAD | tr '/' '-')" +tag="elternbeirat-web:dev-$branch" + +echo "Baue lokales Dev-Image: $tag (kein Push)" +docker build -t "$tag" . + +echo +echo "Fertig. Lokal starten z.B. mit:" +echo " docker run --rm -p 5000:8080 $tag" diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100644 index 0000000..49e43b6 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash +# Baut das Produktiv-Image aus dem aktuellen main-Stand und pusht es in die +# Gitea-Registry, getaggt mit :latest UND dem Commit-Kurz-SHA (Rollback). +# +# Nur fuer freigegebene Staende: das Skript verweigert den Push, wenn du nicht +# auf main bist oder uncommittete Aenderungen hast. Fuer Dev-Builds ohne Push +# stattdessen scripts/dev-build.sh nutzen. +# +# Voraussetzung: einmalig `docker login gitea.anticarnist.de` (siehe +# docs/deployment.md). + +set -euo pipefail + +IMAGE="gitea.anticarnist.de/tom/elternbeirat" + +# Ins Repo-Root wechseln (Skript liegt in scripts/), damit der Docker-Build- +# Kontext stimmt, egal von wo aufgerufen. +cd "$(dirname "$0")/.." + +branch="$(git rev-parse --abbrev-ref HEAD)" +if [[ "$branch" != "main" ]]; then + echo "ABBRUCH: du bist auf '$branch', nicht auf 'main'." >&2 + echo "Ein :latest-Release darf nur aus main gebaut werden." >&2 + echo "Fuer einen Dev-Build ohne Push: scripts/dev-build.sh" >&2 + exit 1 +fi + +if [[ -n "$(git status --porcelain)" ]]; then + echo "ABBRUCH: Arbeitsverzeichnis nicht sauber (uncommittete Aenderungen)." >&2 + echo "Erst committen, damit der SHA-Tag den Image-Inhalt eindeutig benennt." >&2 + exit 1 +fi + +# Warnung, wenn lokaler main dem Remote voraus ist (ungepushte Commits) — dann +# wuerde ein SHA getaggt, den es auf Gitea noch nicht gibt. +if git rev-parse --verify --quiet origin/main >/dev/null; then + ahead="$(git rev-list --count origin/main..HEAD)" + if [[ "$ahead" -gt 0 ]]; then + echo "WARNUNG: lokaler main ist origin/main um $ahead Commit(s) voraus." >&2 + echo " Erst 'git push', damit der SHA auf Gitea existiert." >&2 + read -r -p "Trotzdem fortfahren? [y/N] " answer + [[ "$answer" == "y" || "$answer" == "Y" ]] || exit 1 + fi +fi + +sha="$(git rev-parse --short HEAD)" +echo "Baue $IMAGE (Tags: latest, $sha)" + +docker build -t "$IMAGE:latest" -t "$IMAGE:$sha" . +docker push "$IMAGE" --all-tags + +echo +echo "Fertig. Gepusht: $IMAGE:latest und $IMAGE:$sha" +echo "Auf Unraid: Stack 'elternbeirat' -> Compose Down/Up (bzw. Pull), damit" +echo "das neue :latest gezogen wird." -- 2.54.0