From 8f727952c72fa15dbcfe9e876f3eafe553596718 Mon Sep 17 00:00:00 2001 From: Simon Strandgaard Date: Sun, 8 Mar 2026 19:23:27 +0100 Subject: [PATCH 1/3] Log git commit hash in startup EventItem for rollback reference When frontend_multi_user starts, the "Flask app started" EventItem now includes the short git commit hash in both the message and context, making it easy to identify which version is running and rollback if needed. Co-Authored-By: Claude Opus 4.6 --- frontend_multi_user/src/app.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/frontend_multi_user/src/app.py b/frontend_multi_user/src/app.py index 2828c1b1..ba275cb6 100644 --- a/frontend_multi_user/src/app.py +++ b/frontend_multi_user/src/app.py @@ -16,6 +16,7 @@ import zipfile import secrets import hashlib +import subprocess import tempfile from urllib.parse import quote_plus, urlparse from typing import ClassVar, Dict, Optional, Tuple, Any, cast @@ -606,14 +607,29 @@ def load_user(user_id): self._track_flask_app_started() + @staticmethod + def _get_git_commit_hash() -> str: + """Return the short git commit hash, or 'unknown' if unavailable.""" + try: + return subprocess.check_output( + ["git", "rev-parse", "--short", "HEAD"], + stderr=subprocess.DEVNULL, + text=True, + ).strip() + except Exception: + return "unknown" + def _track_flask_app_started(self): logger.info(f"MyFlaskApp._track_flask_app_started. Starting...") - + # Determine if this is the main process or reloader process is_reloader = os.environ.get('WERKZEUG_RUN_MAIN') == 'true' is_debug_mode = self.app.debug if hasattr(self, 'app') else True - + + commit_hash = self._get_git_commit_hash() + event_context = { + "commit_hash": commit_hash, "pid": str(os.getpid()), "parent_pid": str(os.getppid()), "is_reloader_process": is_reloader, @@ -624,18 +640,18 @@ def _track_flask_app_started(self): "FLASK_ENV": os.environ.get('FLASK_ENV', 'not_set'), "FLASK_DEBUG": os.environ.get('FLASK_DEBUG', 'not_set') } - + with self.app.app_context(): event = _new_model( EventItem, event_type=EventType.GENERIC_EVENT, - message="Flask app started", + message=f"Flask app started (commit {commit_hash})", context=event_context, ) self.db.session.add(event) self.db.session.commit() - - logger.info(f"MyFlaskApp._track_flask_app_started. Logged {event_context!r}") + + logger.info(f"MyFlaskApp._track_flask_app_started. commit={commit_hash} context={event_context!r}") def _start_check(self): # When the Flask app launches in debug mode it runs __init__ twice, so that the app can hot reload. From 32e7b16c426ad9462cd7c612b60dc2ce59fc1bad Mon Sep 17 00:00:00 2001 From: Simon Strandgaard Date: Sun, 8 Mar 2026 19:28:02 +0100 Subject: [PATCH 2/3] Bake git commit hash into Docker image at build time The container has no .git directory, so the runtime git fallback always returned "unknown". Now the hash is passed as a Docker build arg (GIT_COMMIT_HASH) and baked into the PLANEXE_GIT_COMMIT_HASH env var. The Python code checks this env var first before falling back to git. Usage: GIT_COMMIT_HASH=$(git rev-parse --short HEAD) docker compose build Co-Authored-By: Claude Opus 4.6 --- docker-compose.yml | 2 ++ frontend_multi_user/Dockerfile | 3 +++ frontend_multi_user/src/app.py | 9 ++++++++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 2bd9d77e..699fa943 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -181,6 +181,8 @@ services: build: context: . dockerfile: frontend_multi_user/Dockerfile + args: + GIT_COMMIT_HASH: ${GIT_COMMIT_HASH:-unknown} container_name: frontend_multi_user depends_on: database_postgres: diff --git a/frontend_multi_user/Dockerfile b/frontend_multi_user/Dockerfile index fa9c44cc..85bfced4 100644 --- a/frontend_multi_user/Dockerfile +++ b/frontend_multi_user/Dockerfile @@ -1,5 +1,8 @@ FROM python:3.13-slim +ARG GIT_COMMIT_HASH=unknown +ENV PLANEXE_GIT_COMMIT_HASH=${GIT_COMMIT_HASH} + ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \ PLANEXE_CONFIG_PATH=/app \ diff --git a/frontend_multi_user/src/app.py b/frontend_multi_user/src/app.py index ba275cb6..f1c24519 100644 --- a/frontend_multi_user/src/app.py +++ b/frontend_multi_user/src/app.py @@ -609,7 +609,14 @@ def load_user(user_id): @staticmethod def _get_git_commit_hash() -> str: - """Return the short git commit hash, or 'unknown' if unavailable.""" + """Return the short git commit hash, or 'unknown' if unavailable. + + Checks the PLANEXE_GIT_COMMIT_HASH env var first (set at Docker + build time), then falls back to running git directly. + """ + from_env = os.environ.get("PLANEXE_GIT_COMMIT_HASH", "").strip() + if from_env and from_env != "unknown": + return from_env try: return subprocess.check_output( ["git", "rev-parse", "--short", "HEAD"], From 831d4ae3459c8f0181ab587a9147128c3f5d044c Mon Sep 17 00:00:00 2001 From: Simon Strandgaard Date: Sun, 8 Mar 2026 19:33:12 +0100 Subject: [PATCH 3/3] Support Railway's RAILWAY_GIT_COMMIT_SHA build arg Railway auto-injects RAILWAY_GIT_COMMIT_SHA for GitHub-triggered deploys. The Dockerfile now accepts it and prefers it over the manual GIT_COMMIT_HASH arg, so the commit hash works on Railway with zero configuration. Co-Authored-By: Claude Opus 4.6 --- frontend_multi_user/Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend_multi_user/Dockerfile b/frontend_multi_user/Dockerfile index 85bfced4..1d80ec08 100644 --- a/frontend_multi_user/Dockerfile +++ b/frontend_multi_user/Dockerfile @@ -1,7 +1,9 @@ FROM python:3.13-slim +# Accept commit hash from docker-compose build arg or Railway's built-in variable. ARG GIT_COMMIT_HASH=unknown -ENV PLANEXE_GIT_COMMIT_HASH=${GIT_COMMIT_HASH} +ARG RAILWAY_GIT_COMMIT_SHA +ENV PLANEXE_GIT_COMMIT_HASH=${RAILWAY_GIT_COMMIT_SHA:-${GIT_COMMIT_HASH}} ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 \