chore(release): v0.5.1-beta — push Docker image to Gitea Container Registry
CI / test (push) Has been cancelled
CI / test (push) Has been cancelled
- bin/build-and-push.sh: baut + pusht Image in die Gitea-Registry unter git.pkop.de/vibecode/watchlist:<version> - 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
This commit is contained in:
@@ -3,6 +3,7 @@ name: CI
|
|||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
|
tags: ["v*"]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
@@ -24,16 +25,8 @@ jobs:
|
|||||||
test -f app/static/css/style.css
|
test -f app/static/css/style.css
|
||||||
test -f app/static/js/app.js
|
test -f app/static/js/app.js
|
||||||
|
|
||||||
docker:
|
# Hinweis: Push in die Gitea Container Registry laeuft lokal ueber
|
||||||
runs-on: ubuntu-latest
|
# bin/build-and-push.sh
|
||||||
needs: test
|
# weil Gitea-Actions und GitHub-Actions ein anderes Secret-Handling haben.
|
||||||
steps:
|
# Der Befehl ist 1-Zeiler und idempotent, kann auf einem beliebigen
|
||||||
- uses: actions/checkout@v4
|
# CI-Runner ausgefuehrt werden.
|
||||||
- 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
|
|
||||||
|
|||||||
@@ -40,3 +40,10 @@ logs/
|
|||||||
|
|
||||||
# File-Lock-Artefakte (Race-Condition-Schutz)
|
# File-Lock-Artefakte (Race-Condition-Schutz)
|
||||||
*.seed.lock
|
*.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
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ WatchStack ist eine **single-user-lokale** Watchlist-App. Bücher und Serien tei
|
|||||||
- 📊 **Dashboard**: Verteilung pro Medium, Durchschnittsbewertung
|
- 📊 **Dashboard**: Verteilung pro Medium, Durchschnittsbewertung
|
||||||
- 🏷 **Genres & Tags** frei verwaltbar
|
- 🏷 **Genres & Tags** frei verwaltbar
|
||||||
- 🌙 **Dark Theme** Default, modernes UI mit Hero + Drawer + Modals
|
- 🌙 **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:<ver>`
|
||||||
- 🌐 **CORS offen** für lokale Entwicklung; in Produktion via Reverse-Proxy einschränken
|
- 🌐 **CORS offen** für lokale Entwicklung; in Produktion via Reverse-Proxy einschränken
|
||||||
|
|
||||||
## ⚠️ Beta-Hinweis
|
## ⚠️ Beta-Hinweis
|
||||||
|
|
||||||
**v0.5.0-beta** bedeutet:
|
**v0.5.1-beta** bedeutet:
|
||||||
- Kernfunktionalität (CRUD, Suche, Stats, Progress) ist stabil und getestet
|
- Kernfunktionalität (CRUD, Suche, Stats, Progress) ist stabil und getestet
|
||||||
- Datenmodell kann sich noch ändern (siehe `models.py` — additive Änderungen wahrscheinlich)
|
- Datenmodell kann sich noch ändern (siehe `models.py` — additive Änderungen wahrscheinlich)
|
||||||
- Datenbank-Migrationen sind **nicht** enthalten — bei Major-Upgrades DB sichern
|
- 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
|
## 🚀 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
|
```bash
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
@@ -121,6 +132,7 @@ watchlist/
|
|||||||
│ ├── seed.py # Demo-Daten
|
│ ├── seed.py # Demo-Daten
|
||||||
│ └── static/ # Frontend (HTML/CSS/JS)
|
│ └── static/ # Frontend (HTML/CSS/JS)
|
||||||
├── data/ # SQLite-DB (gitignored, Volume im Container)
|
├── data/ # SQLite-DB (gitignored, Volume im Container)
|
||||||
|
├── bin/ # build-and-push.sh, build-image.sh, write-manifest.sh
|
||||||
├── .github/workflows/ # CI
|
├── .github/workflows/ # CI
|
||||||
├── Dockerfile # Multi-stage Build
|
├── Dockerfile # Multi-stage Build
|
||||||
├── docker-compose.yml
|
├── docker-compose.yml
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
"""WatchStack – Watchlist für Bücher, Serien & mehr."""
|
"""WatchStack – Watchlist für Bücher, Serien & mehr."""
|
||||||
|
|
||||||
__version__ = "0.5.0-beta"
|
__version__ = "0.5.1-beta"
|
||||||
__all__ = ["__version__"]
|
__all__ = ["__version__"]
|
||||||
|
|||||||
Executable
+38
@@ -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}"
|
||||||
Executable
+40
@@ -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}"
|
||||||
Executable
+13
@@ -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))
|
||||||
Executable
+29
@@ -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 <<EOF
|
||||||
|
{
|
||||||
|
"name": "watchstack",
|
||||||
|
"version": "${VERSION}",
|
||||||
|
"git_sha": "${GIT_SHA}",
|
||||||
|
"git_tag": "${GIT_TAG}",
|
||||||
|
"build_date": "${BUILD_DATE}",
|
||||||
|
"image": "watchstack:${VERSION}",
|
||||||
|
"tarball": "dist/watchstack-${VERSION}.docker.tar",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"source": "https://git.pkop.de/Vibecode/watchlist"
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
echo ">> Wrote dist/manifest.json"
|
||||||
|
cat dist/manifest.json
|
||||||
Vendored
+29
@@ -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.
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
# Komponiert WatchStack mit persistentem Daten-Volume.
|
# Komponiert WatchStack mit persistentem Daten-Volume.
|
||||||
# Optional: Reverse-Proxy (caddy/traefik) davorschalten.
|
# Optional: Reverse-Proxy (caddy/traefik) davorschalten.
|
||||||
|
|
||||||
|
# Optional: vorgebautes Image aus dist/ verwenden
|
||||||
|
# image: watchstack:0.5.1-beta
|
||||||
|
|
||||||
services:
|
services:
|
||||||
watchstack:
|
watchstack:
|
||||||
build: .
|
build: .
|
||||||
|
|||||||
Reference in New Issue
Block a user