feat: automatische CalVer-Version (Script, API, Header, Image-Tags)

This commit is contained in:
loki committed 2026-10-04 11:04:21 +02:00
1 parent 25a482054d
commit bfe5d7bca8
9 files changed
+72 -2

No files matched your search

+17 -2
View File
@@ -10,8 +10,20 @@ env:
REGISTRY: gitea.lokcal.de REGISTRY: gitea.lokcal.de
jobs: jobs:
version:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.v.outputs.version }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- id: v
run: echo "version=$(./scripts/version.sh)" >> "$GITHUB_OUTPUT"
backend: backend:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: version
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Login to registry - name: Login to registry
@@ -25,12 +37,15 @@ jobs:
with: with:
context: ./backend context: ./backend
push: true push: true
build-args: |
VERSION=${{ needs.version.outputs.version }}
tags: | tags: |
${{ env.REGISTRY }}/${{ gitea.repository_owner }}/streamrip-ui-backend:latest ${{ env.REGISTRY }}/${{ gitea.repository_owner }}/streamrip-ui-backend:latest
${{ env.REGISTRY }}/${{ gitea.repository_owner }}/streamrip-ui-backend:${{ gitea.sha }} ${{ env.REGISTRY }}/${{ gitea.repository_owner }}/streamrip-ui-backend:${{ needs.version.outputs.version }}
frontend: frontend:
runs-on: ubuntu-latest runs-on: ubuntu-latest
needs: version
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Login to registry - name: Login to registry
@@ -46,4 +61,4 @@ jobs:
push: true push: true
tags: | tags: |
${{ env.REGISTRY }}/${{ gitea.repository_owner }}/streamrip-ui-frontend:latest ${{ env.REGISTRY }}/${{ gitea.repository_owner }}/streamrip-ui-frontend:latest
${{ env.REGISTRY }}/${{ gitea.repository_owner }}/streamrip-ui-frontend:${{ gitea.sha }} ${{ env.REGISTRY }}/${{ gitea.repository_owner }}/streamrip-ui-frontend:${{ needs.version.outputs.version }}
+13
View File
@@ -97,6 +97,19 @@ services:
CI (`.gitea/workflows/ci.yml`): Backend-Tests + Docker-Builds beider Images bei jedem Push auf `main`. CI (`.gitea/workflows/ci.yml`): Backend-Tests + Docker-Builds beider Images bei jedem Push auf `main`.
## Versionierung (automatisch, CalVer)
`scripts/version.sh` erzeugt `DATUM.Commitanzahl` (z. B. `2026.10.04.7`, sonst `dev`).
Lokal vor dem Bauen exportieren, die Action macht das selbst:
```bash
export APP_VERSION=$(./scripts/version.sh)
docker compose up --build -d
```
Die Version steckt im Backend-Image (`GET /api/version`), steht im Header der UI
und taggt die Registry-Images (`:latest` + `:2026.10.04.7`).
## API-Überblick (Backend) ## API-Überblick (Backend)
- `GET /api/search?type=track|album|artist|playlist|podcast&q=..` - `GET /api/search?type=track|album|artist|playlist|podcast&q=..`
+3
View File
@@ -21,6 +21,9 @@ RUN pip install --no-cache-dir -r requirements.txt && pip install --no-cache-dir
COPY app ./app COPY app ./app
RUN chown -R appuser:appuser /app RUN chown -R appuser:appuser /app
ARG VERSION=dev
ENV APP_VERSION=$VERSION
USER appuser USER appuser
EXPOSE 8000 EXPOSE 8000
+1
View File
@@ -9,6 +9,7 @@ CONFIG_PATH = os.environ.get(
DOWNLOAD_DIR = os.environ.get( DOWNLOAD_DIR = os.environ.get(
"STREAMRIP_DOWNLOAD_DIR", str(Path.home() / "StreamripDownloads") "STREAMRIP_DOWNLOAD_DIR", str(Path.home() / "StreamripDownloads")
) )
APP_VERSION = os.environ.get("APP_VERSION", "dev")
DEFAULT_QUALITY = int(os.environ.get("STREAMRIP_DEFAULT_QUALITY", "2")) DEFAULT_QUALITY = int(os.environ.get("STREAMRIP_DEFAULT_QUALITY", "2"))
DEFAULT_CODEC = os.environ.get("STREAMRIP_DEFAULT_CODEC", "") DEFAULT_CODEC = os.environ.get("STREAMRIP_DEFAULT_CODEC", "")
SOURCES = ["deezer"] SOURCES = ["deezer"]
+5
View File
@@ -19,6 +19,11 @@ def health():
return {"status": "ok"} return {"status": "ok"}
@app.get("/api/version")
def version():
return {"version": settings.APP_VERSION}
@app.get("/api/sources") @app.get("/api/sources")
def sources(): def sources():
return {"sources": settings.SOURCES} return {"sources": settings.SOURCES}
+10
View File
@@ -14,3 +14,13 @@ def test_sources_deezer_only():
r = c.get("/api/sources") r = c.get("/api/sources")
assert r.status_code == 200 assert r.status_code == 200
assert r.json()["sources"] == ["deezer"] assert r.json()["sources"] == ["deezer"]
def test_version_endpoint(monkeypatch):
from app.core import settings
monkeypatch.setattr(settings, "APP_VERSION", "2026.10.04.7")
c = TestClient(app)
r = c.get("/api/version")
assert r.status_code == 200
assert r.json() == {"version": "2026.10.04.7"}
+1
View File
@@ -5,6 +5,7 @@ services:
args: args:
UID: ${UID:-1000} UID: ${UID:-1000}
GID: ${GID:-1000} GID: ${GID:-1000}
VERSION: ${APP_VERSION:-dev}
ports: ports:
- "${BACKEND_HOST_PORT:-8000}:${BACKEND_PORT:-8000}" - "${BACKEND_HOST_PORT:-8000}:${BACKEND_PORT:-8000}"
environment: environment:
+12
View File
@@ -18,6 +18,7 @@ const NAV = [
export default function Header() { export default function Header() {
const pathname = usePathname(); const pathname = usePathname();
const [backendOk, setBackendOk] = useState<boolean | null>(null); const [backendOk, setBackendOk] = useState<boolean | null>(null);
const [appVersion, setAppVersion] = useState("");
const [theme, setTheme] = useState<"dark" | "light">("dark"); const [theme, setTheme] = useState<"dark" | "light">("dark");
const [basketCount, setBasketCount] = useState(0); const [basketCount, setBasketCount] = useState(0);
@@ -63,6 +64,12 @@ export default function Header() {
.catch(() => { .catch(() => {
if (alive) setBackendOk(false); if (alive) setBackendOk(false);
}); });
fetch("/api/version")
.then((r) => r.json())
.then((b) => {
if (alive && b?.version) setAppVersion(b.version);
})
.catch(() => {});
return () => { return () => {
alive = false; alive = false;
}; };
@@ -102,6 +109,11 @@ export default function Header() {
}} }}
/> />
<span style={{ fontWeight: 700, fontSize: 18, letterSpacing: "-0.01em" }}>streamrip-ui</span> <span style={{ fontWeight: 700, fontSize: 18, letterSpacing: "-0.01em" }}>streamrip-ui</span>
{appVersion && (
<span className="muted" style={{ fontSize: 12 }} title="App-Version">
v{appVersion}
</span>
)}
</Link> </Link>
<nav style={{ display: "flex", gap: 4, flex: 1 }}> <nav style={{ display: "flex", gap: 4, flex: 1 }}>
{NAV.map((item) => { {NAV.map((item) => {
+10
View File
@@ -0,0 +1,10 @@
#!/bin/sh
# Print the app version: YYYY.MM.DD.<total-commit-count> (e.g. 2026.10.04.7).
# Falls back to "dev" outside a git checkout.
set -eu
DATE=$(date +%Y.%m.%d)
if COUNT=$(git rev-list --count HEAD 2>/dev/null); then
echo "${DATE}.${COUNT}"
else
echo "dev"
fi