hatch-surf/gitea-webhook.py
Riley Zhang dcc26b766b deploy: landing page redesign - static HTML with anime.js
- Simplified Dockerfile to serve static files directly (no Next.js build)
- Copied redesign files (index.html, style.css, main.js) to out/
- Added brand/favicon assets
- Backed up previous Next.js build to out.backup.*
- Container rebuilt and verified healthy on port 8080

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-06-25 03:36:11 +02:00

107 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""
Gitea webhook server for hatch.surf deployment
Listens on port 9000 for POST requests from Gitea
"""
import http.server
import json
import subprocess
import logging
from pathlib import Path
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('/home/nara/logs/gitea-webhook.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
DEPLOY_SCRIPT = Path(__file__).parent / "deploy.sh"
class WebhookHandler(http.server.BaseHTTPRequestHandler):
def do_POST(self):
"""Handle POST request from Gitea webhook"""
content_length = int(self.headers.get('Content-Length', 0))
body = self.rfile.read(content_length) if content_length > 0 else b''
try:
payload = json.loads(body) if body else {}
event = self.headers.get('X-Gitea-Event', 'unknown')
logger.info(f"Received webhook: {event}")
logger.info(f"Payload: {json.dumps(payload, indent=2)}")
# Only deploy on push to main branch
if event == 'push':
ref = payload.get('ref', '')
if ref == 'refs/heads/main':
logger.info("Push to main branch - triggering deployment...")
self._deploy()
else:
logger.info(f"Ignoring push to {ref}")
else:
logger.info(f"Ignoring event: {event}")
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({"status": "ok"}).encode())
except Exception as e:
logger.error(f"Error processing webhook: {e}")
self.send_response(500)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({"status": "error", "message": str(e)}).encode())
def _deploy(self):
"""Run the deployment script"""
try:
logger.info(f"Running deploy script: {DEPLOY_SCRIPT}")
result = subprocess.run(
[str(DEPLOY_SCRIPT)],
capture_output=True,
text=True,
timeout=300 # 5 minute timeout
)
if result.returncode == 0:
logger.info("Deployment successful!")
logger.info(f"Output: {result.stdout}")
else:
logger.error(f"Deployment failed with code {result.returncode}")
logger.error(f"Stdout: {result.stdout}")
logger.error(f"Stderr: {result.stderr}")
except subprocess.TimeoutExpired:
logger.error("Deployment timed out after 5 minutes")
except Exception as e:
logger.error(f"Error running deployment: {e}")
def do_GET(self):
"""Health check endpoint"""
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({"status": "healthy"}).encode())
def log_message(self, format, *args):
"""Override to use our logger"""
logger.info(format % args)
def main():
server = http.server.HTTPServer(('0.0.0.0', 9000), WebhookHandler)
logger.info("Starting webhook server on port 9000...")
try:
server.serve_forever()
except KeyboardInterrupt:
logger.info("Shutting down webhook server...")
server.shutdown()
if __name__ == '__main__':
main()