-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathweblate-webhook.py
More file actions
executable file
·95 lines (75 loc) · 3.3 KB
/
weblate-webhook.py
File metadata and controls
executable file
·95 lines (75 loc) · 3.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#!/usr/bin/env python3
"""
Weblate webhook handler for automatic synchronization.
This script handles incoming webhooks from Weblate to trigger repository updates.
"""
import os
import subprocess
import json
from flask import Flask, request, jsonify
import hmac
import hashlib
app = Flask(__name__)
# Configuration
WEBHOOK_SECRET = os.environ.get('WEBLATE_WEBHOOK_SECRET', '')
REPO_PATH = os.path.dirname(os.path.abspath(__file__))
def verify_signature(payload, signature):
"""Verify webhook signature for security."""
if not WEBHOOK_SECRET:
return True # Skip verification if no secret set
expected = hmac.new(
WEBHOOK_SECRET.encode('utf-8'),
payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(f'sha256={expected}', signature)
def run_command(cmd):
"""Run a shell command and return the result."""
try:
result = subprocess.run(cmd, shell=True, capture_output=True, text=True, cwd=REPO_PATH)
return result.returncode == 0, result.stdout, result.stderr
except Exception as e:
return False, "", str(e)
@app.route('/webhook/weblate', methods=['POST'])
def weblate_webhook():
"""Handle Weblate webhook notifications."""
# Verify signature if configured
signature = request.headers.get('X-Hub-Signature-256', '')
if not verify_signature(request.data, signature):
return jsonify({'error': 'Invalid signature'}), 403
try:
data = request.json
event = data.get('event', '')
component = data.get('component', {}).get('slug', '')
print(f"Received webhook: {event} for component: {component}")
if event in ['translation_completed', 'translation_updated']:
# Pull latest translations from Weblate
success, stdout, stderr = run_command('wlc pull rust-coreutils')
if success:
# Commit and push changes
run_command('git add src/uu/*/locales/*.ftl')
success, _, _ = run_command('git commit -m "Update translations from Weblate"')
if success:
run_command('git push origin main')
return jsonify({'status': 'success', 'message': 'Translations updated'})
else:
return jsonify({'status': 'no_changes', 'message': 'No new translations'})
else:
return jsonify({'status': 'error', 'message': f'Failed to pull: {stderr}'}), 500
elif event == 'repository_updated':
# Source files changed, push to Weblate
success, stdout, stderr = run_command('wlc push rust-coreutils')
if success:
return jsonify({'status': 'success', 'message': 'Source pushed to Weblate'})
else:
return jsonify({'status': 'error', 'message': f'Failed to push: {stderr}'}), 500
return jsonify({'status': 'ignored', 'message': f'Event {event} not handled'})
except Exception as e:
return jsonify({'status': 'error', 'message': str(e)}), 500
@app.route('/health')
def health_check():
"""Health check endpoint."""
return jsonify({'status': 'healthy'})
if __name__ == '__main__':
# For development only - use proper WSGI server in production
app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 5000)), debug=False)