feat: automatische CalVer-Version (Script, API, Header, Image-Tags)
This commit is contained in:
1 parent
25a482054d
commit
bfe5d7bca8
9 files changed
+72
-2
No files matched your search
@@ -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 }}
|
||||||
@@ -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=..`
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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"]
|
||||||
@@ -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}
|
||||||
|
|||||||
@@ -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"}
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -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) => {
|
||||||
|
|||||||
Executable
+10
@@ -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
|
||||||
Reference in new issue
Block a user