Release v2.0.3

This commit is contained in:
Christian 2026-01-28 10:35:02 +01:00
parent 2f022bf085
commit 19fdd7d91e
5 changed files with 57 additions and 6 deletions

View File

@ -8,7 +8,7 @@
# RELEASE VERSION
# =====================================================
# Tag fra Gitea (f.eks. v1.0.0, v1.2.3)
RELEASE_VERSION=v2.0.2
RELEASE_VERSION=v2.0.3
# =====================================================
# GITEA AUTHENTICATION

8
RELEASE_NOTES_v2.0.3.md Normal file
View File

@ -0,0 +1,8 @@
# Release Notes v2.0.3
## Changes
- Allow executing SQL migration files directly from `/settings/migrations`, including user feedback on success/failure.
- Pipe the migration SQL files into the Postgres container so the execution works across Docker and Podman.
---
Release Date: 28. januar 2026

View File

@ -1 +1 @@
2.0.2
2.0.3

View File

@ -7,6 +7,8 @@ from pathlib import Path
from fastapi import APIRouter, Request, HTTPException
from fastapi.responses import HTMLResponse
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel
import shlex
import subprocess
from app.core.config import settings
@ -49,11 +51,15 @@ async def migrations_page(request: Request):
})
class MigrationExecution(BaseModel):
file_name: str
@router.post("/settings/migrations/execute", tags=["Frontend"])
def execute_migration(file_name: str):
def execute_migration(payload: MigrationExecution):
"""Execute a migration SQL file"""
migrations_dir = Path(__file__).resolve().parents[3] / "migrations"
migration_file = migrations_dir / file_name
migration_file = migrations_dir / payload.file_name
if not migration_file.exists():
raise HTTPException(status_code=404, detail="Migration file not found")
@ -62,7 +68,11 @@ def execute_migration(file_name: str):
container_runtime = "podman" if settings.CONTAINER_RUNTIME == "podman" else "docker"
# Execute the migration file
command = f"{container_runtime} exec bmc-hub-postgres psql -U {settings.POSTGRES_USER} -d {settings.POSTGRES_DB} -f {migration_file}"
command = (
f"cat {shlex.quote(str(migration_file))} | "
f"{container_runtime} exec -i bmc-hub-postgres "
f"psql -U {settings.POSTGRES_USER} -d {settings.POSTGRES_DB}"
)
result = subprocess.run(command, shell=True, capture_output=True, text=True)
if result.returncode != 0:

View File

@ -67,10 +67,13 @@
</td>
<td>{{ migration.size_kb }} KB</td>
<td>{{ migration.modified }}</td>
<td class="text-end">
<td class="text-end d-flex gap-2 justify-content-end">
<button class="btn btn-sm btn-outline-primary" onclick="showCommand('{{ migration.name }}')">
<i class="bi bi-terminal me-1"></i>Vis kommando
</button>
<button class="btn btn-sm btn-success" onclick="runMigration('{{ migration.name }}', this)">
<i class="bi bi-play-circle me-1"></i>Kør migration
</button>
</td>
</tr>
{% endfor %}
@ -103,6 +106,7 @@
<i class="bi bi-clipboard-plus me-2"></i>Kopiér alt
</button>
</div>
<div id="migrationFeedback" class="alert d-none mt-3" role="alert"></div>
</div>
</div>
@ -148,5 +152,34 @@
if (!currentAltCommand) return;
await navigator.clipboard.writeText(currentAltCommand);
}
async function runMigration(migrationName, button) {
const feedback = document.getElementById('migrationFeedback');
const url = '/settings/migrations/execute';
button.disabled = true;
feedback.className = 'alert alert-info mt-3';
feedback.textContent = 'Kører migration...';
feedback.classList.remove('d-none');
try {
const response = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ file_name: migrationName })
});
const data = await response.json();
if (!response.ok) throw new Error(data.detail || data.message);
feedback.className = 'alert alert-success mt-3';
feedback.innerHTML = `<strong>Migration kørt</strong><br><pre class="mb-0">${data.output}</pre>`;
} catch (error) {
feedback.className = 'alert alert-danger mt-3';
feedback.innerHTML = `<strong>Fejl</strong><br>${error.message}`;
} finally {
button.disabled = false;
}
}
</script>
{% endblock %}