- 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>
107 lines
3.6 KiB
Python
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()
|