toppyr-stack/webhooks/gitea-openproject-webhook.py
Dotty 6e6ff63f08 Add full stack configuration
- docker-compose.yml with all services
- .env.example with placeholder secrets
- Landing page HTML
- Gitea→OpenProject webhook script
- Comprehensive README with architecture docs
2026-03-28 19:04:45 +01:00

99 lines
3.2 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Gitea → OpenProject Webhook Handler
Parses commit messages for WP-XXX patterns and adds comments to Work Packages
"""
import os
import re
import json
import base64
import urllib.request
from http.server import HTTPServer, BaseHTTPRequestHandler
OPENPROJECT_URL = os.getenv("OPENPROJECT_URL", "https://project.toppyr.de")
OPENPROJECT_API_KEY = os.getenv("OPENPROJECT_API_KEY", "")
GITEA_URL = os.getenv("GITEA_URL", "https://git.toppyr.de")
WP_PATTERN = re.compile(r"WP-(\d+)", re.IGNORECASE)
class WebhookHandler(BaseHTTPRequestHandler):
def do_POST(self):
content_length = int(self.headers.get("Content-Length", 0))
body = self.rfile.read(content_length)
try:
payload = json.loads(body)
self.process_push(payload)
self.send_response(200)
self.end_headers()
self.wfile.write(b"OK")
except Exception as e:
print(f"Error: {e}")
self.send_response(500)
self.end_headers()
self.wfile.write(str(e).encode())
def process_push(self, payload):
repo_name = payload.get("repository", {}).get("full_name", "unknown")
commits = payload.get("commits", [])
for commit in commits:
message = commit.get("message", "")
sha = commit.get("id", "")[:8]
author = commit.get("author", {}).get("name", "Unknown")
url = commit.get("url", "")
# Find all WP-XXX references
matches = WP_PATTERN.findall(message)
for wp_id in matches:
self.add_openproject_comment(
wp_id=wp_id,
repo=repo_name,
sha=sha,
message=message,
author=author,
url=url
)
def add_openproject_comment(self, wp_id, repo, sha, message, author, url):
if not OPENPROJECT_API_KEY:
print(f"No API key - would comment on WP-{wp_id}")
return
comment = f"""**Git Commit** [{sha}]({url})
**Repository:** {repo}
**Author:** {author}
```
{message}
```
"""
api_url = f"{OPENPROJECT_URL}/api/v3/work_packages/{wp_id}/activities"
data = json.dumps({"comment": {"raw": comment}}).encode()
# Basic auth with apikey as username
auth = base64.b64encode(f"apikey:{OPENPROJECT_API_KEY}".encode()).decode()
req = urllib.request.Request(
api_url,
data=data,
headers={
"Content-Type": "application/json",
"Authorization": f"Basic {auth}"
},
method="POST"
)
try:
with urllib.request.urlopen(req) as resp:
print(f"Added comment to WP-{wp_id}: {resp.status}")
except Exception as e:
print(f"Failed to comment on WP-{wp_id}: {e}")
def log_message(self, format, *args):
print(f"[Webhook] {args[0]}")
if __name__ == "__main__":
port = int(os.getenv("PORT", 9000))
print(f"Starting webhook handler on port {port}")
HTTPServer(("0.0.0.0", port), WebhookHandler).serve_forever()