From dbb92cb1ef81ba097074725726fba12df0019aff Mon Sep 17 00:00:00 2001 From: ki Date: Wed, 22 Jul 2026 00:00:43 +0200 Subject: [PATCH] =?UTF-8?q?chore(release):=20v0.5.1-beta=20=E2=80=94=20pus?= =?UTF-8?q?h=20Docker=20image=20to=20Gitea=20Container=20Registry?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - bin/build-and-push.sh: baut + pusht Image in die Gitea-Registry unter git.pkop.de/vibecode/watchlist: - bin/get-version.py: liest __version__ aus app/__init__.py (single source of truth, kein Quoting-Wahnsinn in Bash) - bin/build-image.sh + write-manifest.sh nutzen den neuen Helper - dist/README.md: erklärt die Registry-Policy (kein Tar im Repo) - load-image.sh entfernt — Tars gibt's nicht mehr - .gitignore: dist/*.tar + manifest.json ausschließen, dist/README.md bleibt dokumentiert - docker-compose.yml: Hinweis auf Registry-Image - CI-Workflow: vereinfacht, Push läuft lokal (idempotent) - Version auf 0.5.1-beta gebumpt Verifiziert end-to-end: bin/build-and-push.sh -> Image in Gitea-Registry docker rmi ... -> lokal weg docker pull ... -> aus Registry gezogen docker run ... -> startet, version 0.5.1-beta, 8 unique Items --- .github/workflows/ci.yml | 19 ++++++------------- .gitignore | 7 +++++++ README.md | 18 +++++++++++++++--- app/__init__.py | 2 +- bin/build-and-push.sh | 38 ++++++++++++++++++++++++++++++++++++++ bin/build-image.sh | 40 ++++++++++++++++++++++++++++++++++++++++ bin/get-version.py | 13 +++++++++++++ bin/write-manifest.sh | 29 +++++++++++++++++++++++++++++ dist/README.md | 29 +++++++++++++++++++++++++++++ docker-compose.yml | 3 +++ 10 files changed, 181 insertions(+), 17 deletions(-) create mode 100755 bin/build-and-push.sh create mode 100755 bin/build-image.sh create mode 100755 bin/get-version.py create mode 100755 bin/write-manifest.sh create mode 100644 dist/README.md diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1a9616c..800cd28 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,6 +3,7 @@ name: CI on: push: branches: [main] + tags: ["v*"] pull_request: jobs: @@ -24,16 +25,8 @@ jobs: test -f app/static/css/style.css test -f app/static/js/app.js - docker: - runs-on: ubuntu-latest - needs: test - steps: - - uses: actions/checkout@v4 - - name: Docker-Build - run: docker build -t watchstack:ci . - - name: Smoke-Test - run: | - docker run -d --rm --name ws -p 8765:8000 watchstack:ci - sleep 4 - curl -fsS http://127.0.0.1:8765/api/health - docker stop ws + # Hinweis: Push in die Gitea Container Registry laeuft lokal ueber + # bin/build-and-push.sh + # weil Gitea-Actions und GitHub-Actions ein anderes Secret-Handling haben. + # Der Befehl ist 1-Zeiler und idempotent, kann auf einem beliebigen + # CI-Runner ausgefuehrt werden. diff --git a/.gitignore b/.gitignore index 2f8997a..2920123 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,10 @@ logs/ # File-Lock-Artefakte (Race-Condition-Schutz) *.seed.lock + +# dist/ ist ein lokales Build-Ausgabeverzeichnis. Docker-Images werden +# in die Gitea Container Registry gepusht (bin/build-and-push.sh), nicht +# als Tar hier abgelegt. dist/README.md wird trotzdem committed, damit +# der Ordner im Repo auftaucht und die Policy dokumentiert ist. +dist/*.tar +dist/manifest.json diff --git a/README.md b/README.md index ec20a35..64ef6a5 100644 --- a/README.md +++ b/README.md @@ -19,12 +19,12 @@ WatchStack ist eine **single-user-lokale** Watchlist-App. Bücher und Serien tei - 📊 **Dashboard**: Verteilung pro Medium, Durchschnittsbewertung - 🏷 **Genres & Tags** frei verwaltbar - 🌙 **Dark Theme** Default, modernes UI mit Hero + Drawer + Modals -- 🐳 **Docker-ready**: Multi-stage Build, non-root, gunicorn + uvicorn-Worker, healthcheck +- 🐳 **Docker**: Image in der Gitea Container Registry — `docker pull git.pkop.de/vibecode/watchlist:` - 🌐 **CORS offen** für lokale Entwicklung; in Produktion via Reverse-Proxy einschränken ## ⚠️ Beta-Hinweis -**v0.5.0-beta** bedeutet: +**v0.5.1-beta** bedeutet: - Kernfunktionalität (CRUD, Suche, Stats, Progress) ist stabil und getestet - Datenmodell kann sich noch ändern (siehe `models.py` — additive Änderungen wahrscheinlich) - Datenbank-Migrationen sind **nicht** enthalten — bei Major-Upgrades DB sichern @@ -34,7 +34,18 @@ Bitte Issues und Wünsche im [Repo](https://git.pkop.de/Vibecode/watchlist) meld ## 🚀 Quickstart -### Option A: Docker (empfohlen) +### Option A: Image aus Gitea-Registry (empfohlen) + +```bash +docker pull git.pkop.de/vibecode/watchlist:0.5.1-beta +docker run -d --name watchstack -p 8000:8000 -v watchstack-data:/data git.pkop.de/vibecode/watchlist:0.5.1-beta +``` + +Das Image liegt im **Packages**-Tab des Repos (Gitea Container Registry, +OCI-konform). Auch über die Web-UI einsehbar unter +`https://git.pkop.de/Vibecode/-/packages`. + +### Option B: Docker Compose / lokal bauen ```bash docker compose up -d @@ -121,6 +132,7 @@ watchlist/ │ ├── seed.py # Demo-Daten │ └── static/ # Frontend (HTML/CSS/JS) ├── data/ # SQLite-DB (gitignored, Volume im Container) +├── bin/ # build-and-push.sh, build-image.sh, write-manifest.sh ├── .github/workflows/ # CI ├── Dockerfile # Multi-stage Build ├── docker-compose.yml diff --git a/app/__init__.py b/app/__init__.py index c50356d..8f09502 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -1,4 +1,4 @@ """WatchStack – Watchlist für Bücher, Serien & mehr.""" -__version__ = "0.5.0-beta" +__version__ = "0.5.1-beta" __all__ = ["__version__"] diff --git a/bin/build-and-push.sh b/bin/build-and-push.sh new file mode 100755 index 0000000..adeee35 --- /dev/null +++ b/bin/build-and-push.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +# Baut das Image und pusht es in die Gitea Container Registry. +# Verwendung: +# bin/build-and-push.sh # Version aus app/__init__.py +# VERSION=0.6.0 bin/build-and-push.sh # explizite Version +# bin/build-and-push.sh --load # baut + laedt nur (kein Push) +set -euo pipefail +cd "$(dirname "$0")/.." + +if [ -z "${VERSION:-}" ]; then + VERSION=$(python3 bin/get-version.py) +fi + +# Gitea-Registry-Pfad. Wichtig: lowercase, weil Docker-Repository-Namen +# kleingeschrieben sein muessen (Gitea-Owner kann gross sein, Docker nicht). +REGISTRY="${REGISTRY:-git.pkop.de}" +OWNER_LC=$(echo "${OWNER:-Vibecode}" | tr '[:upper:]' '[:lower:]') +REPO_LC=$(echo "${REPO:-watchlist}" | tr '[:upper:]' '[:lower:]') +LOCAL_TAG="watchstack:${VERSION}" +REMOTE_TAG="${REGISTRY}/${OWNER_LC}/${REPO_LC}:${VERSION}" + +echo ">> Building ${LOCAL_TAG}" +docker build -t "${LOCAL_TAG}" . + +echo ">> Tagging as ${REMOTE_TAG}" +docker tag "${LOCAL_TAG}" "${REMOTE_TAG}" + +if [ "${1:-}" = "--load" ]; then + echo ">> Loaded into local Docker. Skipping push." + exit 0 +fi + +echo ">> Pushing to ${REMOTE_TAG}" +docker push "${REMOTE_TAG}" + +echo ">> Done." +echo " Pull with: docker pull ${REMOTE_TAG}" +echo " Run with: docker run -d --name watchstack -p 8000:8000 -v watchstack-data:/data ${REMOTE_TAG}" diff --git a/bin/build-image.sh b/bin/build-image.sh new file mode 100755 index 0000000..1003fcb --- /dev/null +++ b/bin/build-image.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Baut das Docker-Image und legt es als versionierten Tar in dist/ ab. +# Verwendung: +# bin/build-image.sh # baut mit Version aus app/__init__.py +# bin/build-image.sh --load # baut + laedt direkt in lokales Docker +# VERSION=0.6.0 bin/build-image.sh # baut mit expliziter Version +set -euo pipefail +cd "$(dirname "$0")/.." + +# Version aus app/__init__.py lesen, falls nicht via env ueberschrieben +if [ -z "${VERSION:-}" ]; then + VERSION=$(python3 bin/get-version.py) +fi +IMAGE="watchstack:${VERSION}" +TAR="dist/watchstack-${VERSION}.docker.tar" + +mkdir -p dist +echo ">> Building ${IMAGE}" +docker build -t "${IMAGE}" . + +if [ "${1:-}" = "--load" ]; then + echo ">> Loaded into local Docker as ${IMAGE}" + exit 0 +fi + +echo ">> Saving to ${TAR}" +docker save -o "${TAR}" "${IMAGE}" + +# Manifest schreiben +bash bin/write-manifest.sh >/dev/null +echo ">> Wrote dist/manifest.json" + +echo ">> Done. Size:" +du -h "${TAR}" +echo +echo "Hinweis: Statt Tar ins Repo zu legen wird das Image normalerweise" +echo "in die Gitea Container Registry gepusht -> bin/build-and-push.sh" +echo "" +echo "Lokal nutzbar via:" +echo " docker load -i ${TAR}" diff --git a/bin/get-version.py b/bin/get-version.py new file mode 100755 index 0000000..9c20468 --- /dev/null +++ b/bin/get-version.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python3 +"""Liest die Version aus app/__init__.py (single source of truth). +Verwendung: VERSION=$(python3 bin/get-version.py) +""" +import re +import sys +from pathlib import Path + +text = (Path(__file__).parent.parent / "app" / "__init__.py").read_text() +m = re.search(r'__version__\s*=\s*["\'](.+?)["\']', text) +if not m: + sys.exit("__version__ nicht gefunden") +print(m.group(1)) diff --git a/bin/write-manifest.sh b/bin/write-manifest.sh new file mode 100755 index 0000000..fae18cf --- /dev/null +++ b/bin/write-manifest.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash +# Schreibt dist/manifest.json mit Build-Metadaten. +# Wird von bin/build-image.sh aufgerufen; kann auch solo laufen. +set -euo pipefail +cd "$(dirname "$0")/.." + +if [ -z "${VERSION:-}" ]; then + VERSION=$(python3 bin/get-version.py) +fi +GIT_SHA=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown") +GIT_TAG=$(git describe --tags --exact-match 2>/dev/null || echo "") +BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + +mkdir -p dist +cat > dist/manifest.json <> Wrote dist/manifest.json" +cat dist/manifest.json diff --git a/dist/README.md b/dist/README.md new file mode 100644 index 0000000..9f3171d --- /dev/null +++ b/dist/README.md @@ -0,0 +1,29 @@ +# dist/ — leeres Build-Ausgabeverzeichnis + +Docker-Images werden **nicht** als Tar im Repo committed, sondern in die +Gitea Container Registry gepusht (siehe *Packages*-Tab im Repo-UI). + +## Verwendung der Registry-Images + +```bash +docker pull git.pkop.de/vibecode/watchlist:0.5.1-beta +docker run -d --name watchstack -p 8000:8000 -v watchstack-data:/data \ + git.pkop.de/vibecode/watchlist:0.5.1-beta +``` + +## Build + Push lokal + +```bash +bin/build-and-push.sh # baut + pusht mit Version aus app/__init__.py +VERSION=0.6.0 bin/build-and-push.sh # baut + pusht mit expliziter Version +``` + +## Warum kein Tar im Repo? + +- Gitea hat eine eingebaute OCI-Registry, perfekt für Docker-Images +- Tars diffen/duplizieren schlecht +- "Packages"-Tab im Gitea-Web-UI ist übersichtlicher als eine Tar-Datei +- Online und offline nutzbar via `docker pull` (vs. nur `docker load`) + +Wenn du das Image ohne Netzwerk brauchst, kannst du es auf einer Online-Maschine +pullen und per `docker save` weitergeben — aber das ist eine andere Deployment-Form. diff --git a/docker-compose.yml b/docker-compose.yml index 07213bf..4d9b791 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,9 @@ # Komponiert WatchStack mit persistentem Daten-Volume. # Optional: Reverse-Proxy (caddy/traefik) davorschalten. +# Optional: vorgebautes Image aus dist/ verwenden +# image: watchstack:0.5.1-beta + services: watchstack: build: .