fix: update logging messages for database operations and version bump
- Changed logging output for PostgreSQL readiness, schema loading, and migration status to a consistent format using [OK], [FAIL], and [WARN]. - Updated application version to 0.8.14 and modified changelog to reflect recent changes, including a fix for co-trainer backfill logic in the database migration. - Enhanced error handling messages for better clarity during migration processes.
This commit is contained in:
parent
0c044249d9
commit
e69aca51f6
|
|
@ -32,13 +32,13 @@ def wait_for_postgres(max_retries=30):
|
||||||
try:
|
try:
|
||||||
conn = get_connection()
|
conn = get_connection()
|
||||||
conn.close()
|
conn.close()
|
||||||
print("✓ PostgreSQL ready")
|
print("[OK] PostgreSQL ready")
|
||||||
return True
|
return True
|
||||||
except OperationalError:
|
except OperationalError:
|
||||||
print(f" Waiting for PostgreSQL... (attempt {i}/{max_retries})")
|
print(f" Waiting for PostgreSQL... (attempt {i}/{max_retries})")
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
print(f"✗ PostgreSQL not ready after {max_retries} attempts")
|
print(f"[FAIL] PostgreSQL not ready after {max_retries} attempts")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def check_table_exists(table_name="profiles"):
|
def check_table_exists(table_name="profiles"):
|
||||||
|
|
@ -71,10 +71,10 @@ def load_schema(schema_file="/app/schema.sql"):
|
||||||
conn.commit()
|
conn.commit()
|
||||||
cur.close()
|
cur.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
print("✓ Schema loaded from schema.sql")
|
print("[OK] Schema loaded from schema.sql")
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"✗ Error loading schema: {e}")
|
print(f"[FAIL] Error loading schema: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def get_profile_count():
|
def get_profile_count():
|
||||||
|
|
@ -146,10 +146,10 @@ def apply_migration(filepath, filename):
|
||||||
conn.commit()
|
conn.commit()
|
||||||
cur.close()
|
cur.close()
|
||||||
conn.close()
|
conn.close()
|
||||||
print(f" ✓ Applied: {filename}")
|
print(f" [OK] Applied: {filename}")
|
||||||
return True
|
return True
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" ✗ Failed to apply {filename}: {e}")
|
print(f" [FAIL] Failed to apply {filename}: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def run_migrations(migrations_dir="/app/migrations"):
|
def run_migrations(migrations_dir="/app/migrations"):
|
||||||
|
|
@ -158,7 +158,7 @@ def run_migrations(migrations_dir="/app/migrations"):
|
||||||
import re
|
import re
|
||||||
|
|
||||||
if not os.path.exists(migrations_dir):
|
if not os.path.exists(migrations_dir):
|
||||||
print("✓ No migrations directory found")
|
print("[OK] No migrations directory found")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Ensure migration tracking table exists
|
# Ensure migration tracking table exists
|
||||||
|
|
@ -174,7 +174,7 @@ def run_migrations(migrations_dir="/app/migrations"):
|
||||||
migration_files = [f for f in all_files if migration_pattern.match(os.path.basename(f))]
|
migration_files = [f for f in all_files if migration_pattern.match(os.path.basename(f))]
|
||||||
|
|
||||||
if not migration_files:
|
if not migration_files:
|
||||||
print("✓ No migration files found")
|
print("[OK] No migration files found")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Apply pending migrations
|
# Apply pending migrations
|
||||||
|
|
@ -185,7 +185,7 @@ def run_migrations(migrations_dir="/app/migrations"):
|
||||||
pending.append((filepath, filename))
|
pending.append((filepath, filename))
|
||||||
|
|
||||||
if not pending:
|
if not pending:
|
||||||
print(f"✓ All {len(applied)} migrations already applied")
|
print(f"[OK] All {len(applied)} migrations already applied")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
print(f" Found {len(pending)} pending migration(s)...")
|
print(f" Found {len(pending)} pending migration(s)...")
|
||||||
|
|
@ -211,12 +211,12 @@ if __name__ == "__main__":
|
||||||
if not load_schema():
|
if not load_schema():
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
print("✓ Schema already exists")
|
print("[OK] Schema already exists")
|
||||||
|
|
||||||
# Run migrations
|
# Run migrations
|
||||||
print("\nRunning database migrations...")
|
print("\nRunning database migrations...")
|
||||||
if not run_migrations():
|
if not run_migrations():
|
||||||
print("✗ Migration failed")
|
print("[FAIL] Migration failed")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Check for migration
|
# Check for migration
|
||||||
|
|
@ -232,14 +232,14 @@ if __name__ == "__main__":
|
||||||
from migrate_to_postgres import main as migrate
|
from migrate_to_postgres import main as migrate
|
||||||
migrate()
|
migrate()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"✗ Migration failed: {e}")
|
print(f"[FAIL] Migration failed: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
elif os.path.exists(sqlite_db) and profile_count > 0:
|
elif os.path.exists(sqlite_db) and profile_count > 0:
|
||||||
print(f"⚠ SQLite DB exists but PostgreSQL already has {profile_count} profiles")
|
print(f"[WARN] SQLite DB exists but PostgreSQL already has {profile_count} profiles")
|
||||||
print(" Skipping migration (already migrated)")
|
print(" Skipping migration (already migrated)")
|
||||||
elif not os.path.exists(sqlite_db):
|
elif not os.path.exists(sqlite_db):
|
||||||
print("✓ No SQLite database found (fresh install or already migrated)")
|
print("[OK] No SQLite database found (fresh install or already migrated)")
|
||||||
else:
|
else:
|
||||||
print("✓ No migration needed")
|
print("[OK] No migration needed")
|
||||||
|
|
||||||
print("\n✓ Database initialization complete")
|
print("\n[OK] Database initialization complete")
|
||||||
|
|
|
||||||
|
|
@ -21,20 +21,20 @@ from version import APP_VERSION, BUILD_DATE, DB_SCHEMA_VERSION, MODULE_VERSIONS
|
||||||
# Run database migrations before API start — halbes Schema ist schlimmer als kein Start
|
# Run database migrations before API start — halbes Schema ist schlimmer als kein Start
|
||||||
# Lokal ohne DB / nur Tests: SKIP_DB_MIGRATE=1
|
# Lokal ohne DB / nur Tests: SKIP_DB_MIGRATE=1
|
||||||
if os.getenv("SKIP_DB_MIGRATE", "").strip().lower() in ("1", "true", "yes"):
|
if os.getenv("SKIP_DB_MIGRATE", "").strip().lower() in ("1", "true", "yes"):
|
||||||
print("⚠ SKIP_DB_MIGRATE=1 — Migrationen wurden übersprungen (nur für Entwicklung ohne DB)")
|
print("[SKIP_DB_MIGRATE] Migrationen uebersprungen (nur fuer Entwicklung ohne DB)")
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
import run_migrations
|
import run_migrations
|
||||||
|
|
||||||
rc = run_migrations.main()
|
rc = run_migrations.main()
|
||||||
if rc != 0:
|
if rc != 0:
|
||||||
print(f"✗ Datenbank-Migration fehlgeschlagen (Exit-Code {rc}). Start abgebrochen.")
|
print(f"[FAIL] Datenbank-Migration fehlgeschlagen (Exit-Code {rc}). Start abgebrochen.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
print("✓ Database migrations completed")
|
print("[OK] Database migrations completed")
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
raise
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"✗ Migration-Laufzeitfehler: {e}")
|
print(f"[FAIL] Migration-Laufzeitfehler: {e}")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
from routers.auth import limiter as auth_rate_limiter
|
from routers.auth import limiter as auth_rate_limiter
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,9 @@ ON CONFLICT (profile_id, club_id) DO NOTHING;
|
||||||
INSERT INTO club_members (profile_id, club_id, status)
|
INSERT INTO club_members (profile_id, club_id, status)
|
||||||
SELECT DISTINCT elem::int, t.club_id, 'active'
|
SELECT DISTINCT elem::int, t.club_id, 'active'
|
||||||
FROM training_groups t,
|
FROM training_groups t,
|
||||||
LATERAL jsonb_array_elements_text(COALESCE(t.co_trainer_ids, '[]'::jsonb)) AS elem
|
LATERAL jsonb_array_elements_text(t.co_trainer_ids) AS elem
|
||||||
WHERE jsonb_array_length(COALESCE(t.co_trainer_ids, '[]'::jsonb)) > 0
|
WHERE jsonb_typeof(t.co_trainer_ids) = 'array'
|
||||||
|
AND jsonb_array_length(t.co_trainer_ids) > 0
|
||||||
ON CONFLICT (profile_id, club_id) DO NOTHING;
|
ON CONFLICT (profile_id, club_id) DO NOTHING;
|
||||||
|
|
||||||
INSERT INTO club_member_roles (club_member_id, role_code)
|
INSERT INTO club_member_roles (club_member_id, role_code)
|
||||||
|
|
|
||||||
|
|
@ -49,14 +49,14 @@ def get_db_connection():
|
||||||
password=p["password"],
|
password=p["password"],
|
||||||
)
|
)
|
||||||
conn.autocommit = False
|
conn.autocommit = False
|
||||||
print(f"✓ Connected to database: {p['dbname']}")
|
print(f"[OK] Connected to database: {p['dbname']}")
|
||||||
return conn
|
return conn
|
||||||
except psycopg2.OperationalError:
|
except psycopg2.OperationalError:
|
||||||
if i < max_retries - 1:
|
if i < max_retries - 1:
|
||||||
print(f"Waiting for database... ({i+1}/{max_retries})")
|
print(f"Waiting for database... ({i+1}/{max_retries})")
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
else:
|
else:
|
||||||
print(f"✗ Failed to connect to database after {max_retries} attempts")
|
print(f"[FAIL] Failed to connect to database after {max_retries} attempts")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -72,7 +72,7 @@ def init_migrations_table(conn):
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
print("✓ schema_migrations initialisiert")
|
print("[OK] schema_migrations initialisiert")
|
||||||
|
|
||||||
|
|
||||||
_LEADING_DIGITS = re.compile(r"^(\d+)")
|
_LEADING_DIGITS = re.compile(r"^(\d+)")
|
||||||
|
|
@ -190,7 +190,7 @@ def run_migration(conn, migration_name: str, filepath: str) -> bool:
|
||||||
if shutil.which("psql"):
|
if shutil.which("psql"):
|
||||||
ok, diag = _run_file_with_psql(filepath)
|
ok, diag = _run_file_with_psql(filepath)
|
||||||
if not ok:
|
if not ok:
|
||||||
print(f" ✗ psql fehlgeschlagen:\n{diag or '(kein Output)'}")
|
print(f" [FAIL] psql fehlgeschlagen:\n{diag or '(kein Output)'}")
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
return False
|
return False
|
||||||
detail_suffix = "(psql -1)"
|
detail_suffix = "(psql -1)"
|
||||||
|
|
@ -199,7 +199,7 @@ def run_migration(conn, migration_name: str, filepath: str) -> bool:
|
||||||
with open(filepath, "r", encoding="utf-8") as fh:
|
with open(filepath, "r", encoding="utf-8") as fh:
|
||||||
body = fh.read()
|
body = fh.read()
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
print(f" ✗ kann Datei nicht lesen: {e}")
|
print(f" [FAIL] kann Datei nicht lesen: {e}")
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
@ -207,7 +207,7 @@ def run_migration(conn, migration_name: str, filepath: str) -> bool:
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
if not statements:
|
if not statements:
|
||||||
print(
|
print(
|
||||||
f" ⚠ keine ausführbaren Statements (leer?) — "
|
f" [WARN] keine ausführbaren Statements (leer?) — "
|
||||||
f"Eintrag trotzdem: {migration_name}"
|
f"Eintrag trotzdem: {migration_name}"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
@ -217,12 +217,12 @@ def run_migration(conn, migration_name: str, filepath: str) -> bool:
|
||||||
|
|
||||||
_record_migration(conn, migration_name)
|
_record_migration(conn, migration_name)
|
||||||
conn.commit()
|
conn.commit()
|
||||||
print(f" ✓ {migration_name} erfolgreich {detail_suffix}")
|
print(f" [OK] {migration_name} erfolgreich {detail_suffix}")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
conn.rollback()
|
conn.rollback()
|
||||||
print(f" ✗ {migration_name}: {e}")
|
print(f" [FAIL] {migration_name}: {e}")
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -243,7 +243,7 @@ def main():
|
||||||
pending = get_pending(conn, migrations_dir)
|
pending = get_pending(conn, migrations_dir)
|
||||||
|
|
||||||
if not pending:
|
if not pending:
|
||||||
print("✓ Keine ausstehenden Migrationen — Schema aktuell.")
|
print("[OK] Keine ausstehenden Migrationen — Schema aktuell.")
|
||||||
conn.close()
|
conn.close()
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
@ -262,17 +262,17 @@ def main():
|
||||||
|
|
||||||
print("\n" + "=" * 60)
|
print("\n" + "=" * 60)
|
||||||
if failed:
|
if failed:
|
||||||
print(f"✗ Abbruch nach: {failed}")
|
print(f"[FAIL] Abbruch nach: {failed}")
|
||||||
print(" (Bereits erfolgreiche Dateien dieser Session sind committed.)")
|
print(" (Bereits erfolgreiche Dateien dieser Session sind committed.)")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
print(f"✓ {len(pending)} Migration(s) angewendet — Schema aktuell.")
|
print(f"[OK] {len(pending)} Migration(s) angewendet — Schema aktuell.")
|
||||||
print("=" * 60)
|
print("=" * 60)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"\n✗ Fehler: {e}")
|
print(f"\n[FAIL] Fehler: {e}")
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Shinkan Jinkendo Version Information
|
# Shinkan Jinkendo Version Information
|
||||||
|
|
||||||
APP_VERSION = "0.8.12"
|
APP_VERSION = "0.8.14"
|
||||||
BUILD_DATE = "2026-05-05"
|
BUILD_DATE = "2026-05-05"
|
||||||
DB_SCHEMA_VERSION = "20260505039"
|
DB_SCHEMA_VERSION = "20260505039"
|
||||||
|
|
||||||
|
|
@ -23,6 +23,20 @@ MODULE_VERSIONS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
CHANGELOG = [
|
CHANGELOG = [
|
||||||
|
{
|
||||||
|
"version": "0.8.14",
|
||||||
|
"date": "2026-05-05",
|
||||||
|
"changes": [
|
||||||
|
"DB 039 Fix: Co-Trainer-Backfill nur wenn co_trainer_ids ein JSON-Array ist (vermeidet jsonb_array_length auf Nicht-Array)",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"version": "0.8.13",
|
||||||
|
"date": "2026-05-05",
|
||||||
|
"changes": [
|
||||||
|
"Fix: Startup unter Windows (cp1252) — Emoji/Sonderzeichen in print durch ASCII ([OK]/[FAIL]/[WARN]) ersetzt (main, run_migrations, db_init)",
|
||||||
|
],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"version": "0.8.12",
|
"version": "0.8.12",
|
||||||
"date": "2026-05-05",
|
"date": "2026-05-05",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
// Shinkan Jinkendo Frontend Version
|
// Shinkan Jinkendo Frontend Version
|
||||||
|
|
||||||
export const APP_VERSION = "0.8.12"
|
export const APP_VERSION = "0.8.14"
|
||||||
export const BUILD_DATE = "2026-05-05"
|
export const BUILD_DATE = "2026-05-05"
|
||||||
|
|
||||||
export const PAGE_VERSIONS = {
|
export const PAGE_VERSIONS = {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user