From 38efe4f3eecd2c2d4d653a2b1b0a7144f46518b6 Mon Sep 17 00:00:00 2001 From: Gitea Deploy Date: Sun, 9 Nov 2025 11:47:40 +0000 Subject: [PATCH] Add webhook endpoint with automatic container restart on push --- =7.0.0 | 11 +++ backend/igny8_core/modules/system/views.py | 95 ++++++++++++++++++++-- backend/requirements.txt | 1 + 3 files changed, 100 insertions(+), 7 deletions(-) create mode 100644 =7.0.0 diff --git a/=7.0.0 b/=7.0.0 new file mode 100644 index 00000000..ec4d978c --- /dev/null +++ b/=7.0.0 @@ -0,0 +1,11 @@ +Collecting docker + Downloading docker-7.1.0-py3-none-any.whl.metadata (3.8 kB) +Requirement already satisfied: requests>=2.26.0 in /usr/local/lib/python3.11/site-packages (from docker) (2.32.5) +Requirement already satisfied: urllib3>=1.26.0 in /usr/local/lib/python3.11/site-packages (from docker) (2.5.0) +Requirement already satisfied: charset_normalizer<4,>=2 in /usr/local/lib/python3.11/site-packages (from requests>=2.26.0->docker) (3.4.4) +Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/site-packages (from requests>=2.26.0->docker) (3.11) +Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/site-packages (from requests>=2.26.0->docker) (2025.10.5) +Downloading docker-7.1.0-py3-none-any.whl (147 kB) +Installing collected packages: docker +Successfully installed docker-7.1.0 +WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager, possibly rendering your system unusable. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv. Use the --root-user-action option if you know what you are doing and want to suppress this warning. diff --git a/backend/igny8_core/modules/system/views.py b/backend/igny8_core/modules/system/views.py index 95749b40..7fbc8b39 100644 --- a/backend/igny8_core/modules/system/views.py +++ b/backend/igny8_core/modules/system/views.py @@ -530,21 +530,102 @@ def gitea_webhook(request): logger.info(f"[Webhook] Processing push: {commit_count} commit(s) by {pusher} to {repo_full_name}") - # Trigger deployment - # The post-receive hook in Gitea will handle the actual deployment - # This webhook is for logging and potential additional actions + # Trigger deployment - restart containers + # Note: Git pull is handled by post-receive hook in Gitea + # This webhook restarts containers to apply changes + deployment_success = False + deployment_error = None - # You can add additional deployment logic here if needed - # For example, triggering a rebuild, restarting services, etc. + try: + # Try to use docker Python library first, fallback to subprocess + try: + import docker as docker_lib + client = docker_lib.DockerClient(base_url='unix://var/run/docker.sock') + + # Restart frontend container (don't restart backend from within itself) + logger.info(f"[Webhook] Restarting frontend container...") + frontend_container = client.containers.get("igny8_frontend") + frontend_container.restart(timeout=30) + logger.info(f"[Webhook] Frontend container restarted successfully") + + # Schedule backend restart via subprocess in background (non-blocking) + # This avoids deadlock from restarting the container we're running in + logger.info(f"[Webhook] Scheduling backend container restart...") + import threading + def restart_backend(): + import time + time.sleep(2) # Give webhook time to respond + try: + backend_container = client.containers.get("igny8_backend") + backend_container.restart(timeout=30) + logger.info(f"[Webhook] Backend container restarted successfully (delayed)") + except Exception as e: + logger.error(f"[Webhook] Delayed backend restart failed: {e}") + + restart_thread = threading.Thread(target=restart_backend, daemon=True) + restart_thread.start() + + deployment_success = True + + except ImportError: + # Fallback to subprocess with docker command + logger.info(f"[Webhook] Docker library not available, using subprocess...") + + # Try /usr/bin/docker or docker in PATH + docker_cmd = "/usr/bin/docker" + import shutil + if not os.path.exists(docker_cmd): + docker_cmd = shutil.which("docker") or "docker" + + # Restart backend container + logger.info(f"[Webhook] Restarting backend container...") + backend_result = subprocess.run( + [docker_cmd, "restart", "igny8_backend"], + capture_output=True, + text=True, + timeout=30 + ) + + if backend_result.returncode != 0: + raise Exception(f"Backend restart failed: {backend_result.stderr}") + logger.info(f"[Webhook] Backend container restarted successfully") + + # Restart frontend container + logger.info(f"[Webhook] Restarting frontend container...") + frontend_result = subprocess.run( + [docker_cmd, "restart", "igny8_frontend"], + capture_output=True, + text=True, + timeout=30 + ) + + if frontend_result.returncode != 0: + raise Exception(f"Frontend restart failed: {frontend_result.stderr}") + logger.info(f"[Webhook] Frontend container restarted successfully") + + deployment_success = True + + logger.info(f"[Webhook] Deployment completed: containers restarted") + + except subprocess.TimeoutExpired as e: + deployment_error = f"Deployment timeout: {str(e)}" + logger.error(f"[Webhook] {deployment_error}") + except Exception as deploy_error: + deployment_error = str(deploy_error) + logger.error(f"[Webhook] Deployment error: {deploy_error}", exc_info=True) return Response({ - 'status': 'success', + 'status': 'success' if deployment_success else 'partial', 'message': 'Webhook received and processed', 'repository': repo_full_name, 'branch': ref, 'commits': commit_count, 'pusher': pusher, - 'event': event_type + 'event': event_type, + 'deployment': { + 'success': deployment_success, + 'error': deployment_error + } }, status=http_status.HTTP_200_OK) except json.JSONDecodeError as e: diff --git a/backend/requirements.txt b/backend/requirements.txt index 9dd84a03..c364bb9b 100755 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -11,3 +11,4 @@ requests>=2.31.0 celery>=5.3.0 beautifulsoup4>=4.12.0 psutil>=5.9.0 +docker>=7.0.0