Add transifex webhook handler
This commit is contained in:
parent
a7076d3b65
commit
0a9a5d0968
278
pybitmessage.wsgi
Normal file
278
pybitmessage.wsgi
Normal file
|
@ -0,0 +1,278 @@
|
|||
#!/usr/bin/python2.7
|
||||
|
||||
#import datetime
|
||||
from base64 import b64encode
|
||||
from cStringIO import StringIO
|
||||
import fcntl
|
||||
from hashlib import sha1
|
||||
import hmac
|
||||
import httplib
|
||||
import json
|
||||
import os
|
||||
import pprint
|
||||
import requests
|
||||
import shutil
|
||||
from subprocess import call, Popen
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
from urlparse import parse_qs
|
||||
|
||||
gitHubSecret = ""
|
||||
gitHubUsername = ""
|
||||
gitHubToken = ""
|
||||
transifexSecret = ""
|
||||
transifexUsername = ""
|
||||
transifexPassword = ""
|
||||
branch = "v0.6"
|
||||
lock = None
|
||||
lockFile = ".webhook.lock"
|
||||
|
||||
os.chdir("/usr/src/PyBitmessage")
|
||||
if os.environ.get("HOME") is None:
|
||||
os.environ["HOME"] = "/var/www"
|
||||
|
||||
def debug(obj):
|
||||
sys.stderr.write(pprint.pformat(obj) + "\n")
|
||||
|
||||
def verifyGitHubSignature (environ, payload_body):
|
||||
signature = 'sha1=' + hmac.new(gitHubSecret, payload_body, sha1).hexdigest()
|
||||
try:
|
||||
if signature != environ.get('HTTP_X_HUB_SIGNATURE'):
|
||||
return False
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def verifyTransifexSignature (environ, payload_body):
|
||||
signature = b64encode(hmac.new(transifexSecret, payload_body, sha1).digest())
|
||||
try:
|
||||
debug(signature)
|
||||
if signature != environ.get('HTTP_X_TX_SIGNATURE'):
|
||||
return False
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def returnMessage(status = False, message = "Unimplemented"):
|
||||
output = json.dumps({"status": "OK" if status else "FAIL", "message": message})
|
||||
return [output, [('Content-type', 'text/plain'),
|
||||
('Content-Length', str(len(output)))
|
||||
]]
|
||||
|
||||
def updateLocalTranslationSource():
|
||||
call(["git", "stash", "-q"])
|
||||
call(["git", "checkout", "-q", branch])
|
||||
call(["git", "pull", "-q"])
|
||||
call(["pylupdate4", "src/translations/bitmessage.pro"])
|
||||
|
||||
def uploadTranslationSource():
|
||||
headers = {"Authorization": "Basic " + b64encode(transifexUsername + ":" + transifexPassword)}
|
||||
response = requests.put("https://www.transifex.com/api/2/project/pybitmessage/resource/pybitmessage/content/",
|
||||
headers=headers, files={'bitmessage_en.ts': open("src/translations/bitmessage_en.ts", "rb")})
|
||||
return response
|
||||
|
||||
def updateLocalTranslationDestination(ts, lang):
|
||||
call(["git", "pull", "--all", "-q"])
|
||||
call(["git", "stash", "-q"])
|
||||
call(["git", "checkout", "-q", branch])
|
||||
call(["git", "checkout", "-q", "-b", "translate_" + lang + "_" + str(ts)])
|
||||
call(["git", "branch", "-q", "--set-upstream-to=origin/v0.6"])
|
||||
|
||||
def downloadTranslatedLanguage(ts, lang):
|
||||
headers = {"Authorization": "Basic " + b64encode(transifexUsername + ":" + transifexPassword)}
|
||||
resname = "pybitmessage_" + lang + ".ts"
|
||||
fname = "bitmessage_" + lang.lower() + ".ts"
|
||||
with open("src/translations/" + fname, "wt") as handle:
|
||||
response = requests.get("https://www.transifex.com/api/2/project/pybitmessage/resource/pybitmessage/translation/" + lang + "/",
|
||||
headers=headers)
|
||||
if response.ok:
|
||||
content = json.loads(response.content)["content"]
|
||||
handle.write(content.encode("utf-8"))
|
||||
# print "Response from github for pull request: %i, %s" % (response.status_code, response.content)
|
||||
return response
|
||||
|
||||
def commitTranslatedLanguage(ts, lang):
|
||||
call(["lrelease-qt4", "src/translations/bitmessage.pro"])
|
||||
call(["git", "add", "src/translations/bitmessage_" + lang + ".ts", "src/translations/bitmessage_" + lang + ".qm"])
|
||||
call(["git", "commit", "-q", "-S", "-m", "Auto-updated language %s from transifex" % (lang)])
|
||||
newbranch = "translate_" + lang + "_" + str(ts)
|
||||
call(["git", "push", "-q", "translations", newbranch + ":" + newbranch])
|
||||
request = {
|
||||
"title": "Translation update " + lang,
|
||||
"body": "Auto-updated from transifex",
|
||||
"head": "PyBitmessageTranslations:" + newbranch,
|
||||
"base": branch
|
||||
}
|
||||
headers = {"Authorization": "token " + gitHubToken}
|
||||
response = requests.post("https://api.github.com/repos/Bitmessage/PyBitmessage/pulls",
|
||||
headers=headers, data=json.dumps(request))
|
||||
# TODO: save pull request number
|
||||
return response
|
||||
# print "JSON dumps request: %s" % (json.dumps(request))
|
||||
# print "Response from github for pull request: %i, %s" % (response.status_code, response.content)
|
||||
|
||||
def listPullRequests():
|
||||
headers = {"Authorization": "token " + gitHubToken}
|
||||
response = requests.get("https://api.github.com/repos/Bitmessage/PyBitmessage/pulls?state=open&base=%s&sort=created&direction=desc" % branch,
|
||||
headers=headers)
|
||||
pulls = []
|
||||
if response.ok:
|
||||
try:
|
||||
data = json.loads(response.content)
|
||||
for i in data:
|
||||
if i['user']['login'] != gitHubUsername:
|
||||
continue
|
||||
if not i['head']['label'].startswith(gitHubUsername):
|
||||
continue
|
||||
# print i['number'], i['title'], i['user']['login'], i['head']['label'], i['head']['ref']
|
||||
pulls.append({'number': i['number'], 'branch': i['head']['ref']})
|
||||
except:
|
||||
print "Exception"
|
||||
traceback.print_exc()
|
||||
pass
|
||||
else:
|
||||
print "Not ok"
|
||||
return pulls
|
||||
# print "JSON dumps request: %s" % (json.dumps(request))
|
||||
# print "Response from github for pull request: %i, %s" % (response.status_code, response.content)
|
||||
|
||||
def rebasePullRequest(newbranch):
|
||||
# newbranch = "translate_" + lang + "_" + str(ts)
|
||||
call(["git", "pull", "--all", "-q"])
|
||||
call(["git", "stash", "-q"])
|
||||
call(["git", "checkout", "-q", newbranch])
|
||||
call(["git", "branch", "-q", "--set-upstream-to=origin/v0.6"])
|
||||
call(["git", "rebase", "-q"])
|
||||
call(["git", "commit", "-q", "--no-edit", "--amend", "-S"])
|
||||
call(["git", "push", "-q", "-f", "translations", newbranch + ":" + newbranch])
|
||||
call(["git", "checkout", "-q", branch])
|
||||
|
||||
def checkIfPullRequestMerged(ts, lang):
|
||||
# Get if a pull request has been merged
|
||||
# GET /repos/:owner/:repo/pulls/:number/merge
|
||||
# Response if pull request has been merged
|
||||
# Status: 204 No Content
|
||||
# Response if pull request has not been merged
|
||||
# Status: 404 Not Found
|
||||
return
|
||||
|
||||
def deleteBranch(ts, lang):
|
||||
newbranch = "translate_" + lang + "_" + str(ts)
|
||||
call(["git", "branch", "-q", "-D", newbranch])
|
||||
# TODO: delete remote branch
|
||||
|
||||
def lockWait():
|
||||
global lockFile, lock
|
||||
lock = open(lockFile, "wb")
|
||||
fcntl.lockf(lock, fcntl.LOCK_EX)
|
||||
|
||||
def unlock():
|
||||
global lockFile, lock
|
||||
fcntl.lockf(lock, fcntl.LOCK_UN)
|
||||
if os.path.isfile(lockFile):
|
||||
os.unlink(lockFile)
|
||||
|
||||
def application(environ, start_response):
|
||||
status = '200 OK'
|
||||
output = ''
|
||||
|
||||
lockWait()
|
||||
length = int(environ.get('CONTENT_LENGTH', '0'))
|
||||
body = environ['wsgi.input'].read(length)
|
||||
# h environ['wsgi.input'] = body
|
||||
|
||||
if environ.get("HTTP_X_GITHUB_EVENT") == "ping":
|
||||
if not verifyGitHubSignature(environ, body):
|
||||
output, responseHeaders = returnMessage(False, "Checksum bad")
|
||||
start_response(status, responseHeaders)
|
||||
unlock()
|
||||
return [output]
|
||||
output, responseHeaders = returnMessage(True, "Test OK")
|
||||
elif environ.get("HTTP_X_GITHUB_EVENT") == "push":
|
||||
if not verifyGitHubSignature(environ, body):
|
||||
output, responseHeaders = returnMessage(False, "Checksum bad")
|
||||
start_response(status, responseHeaders)
|
||||
unlock()
|
||||
return [output]
|
||||
try:
|
||||
payload = json.loads(body)
|
||||
if payload['ref'] != "refs/heads/" + branch:
|
||||
unlock()
|
||||
raise Exception
|
||||
updateLocalTranslationSource()
|
||||
response = uploadTranslationSource()
|
||||
output, responseHeaders = returnMessage(True, "Processed: %i, %s:" % (response.status_code, response.content))
|
||||
except:
|
||||
output, responseHeaders = returnMessage(True, "Not processing")
|
||||
elif "Transifex" in environ.get("HTTP_USER_AGENT"):
|
||||
# debug(environ)
|
||||
# debug(body)
|
||||
if not verifyTransifexSignature(environ, body):
|
||||
debug ("Verify Transifex Signature fail, but fuck them")
|
||||
else:
|
||||
debug ("Verify Transifex Signature ok")
|
||||
# output, responseHeaders = returnMessage(False, "Checksum bad")
|
||||
# start_response(status, responseHeaders)
|
||||
# unlock()
|
||||
# return [output]
|
||||
try:
|
||||
# debug(body)
|
||||
payload = parse_qs(body)
|
||||
# debug(payload)
|
||||
if 'pybitmessage' in payload['project'] and 'pybitmessage' in payload['resource']:
|
||||
if 'translated' in payload and '100' in payload['translated']:
|
||||
ts = int(time.time())
|
||||
updateLocalTranslationDestination(ts, payload['language'][0].lower())
|
||||
downloadTranslatedLanguage(ts, payload['language'][0])
|
||||
response = commitTranslatedLanguage(ts, payload['language'][0].lower())
|
||||
if response.ok:
|
||||
output, responseHeaders = returnMessage(True, "Processed.")
|
||||
else:
|
||||
output, responseHeaders = returnMessage(False, "Error: %i." % (response.status_code))
|
||||
else:
|
||||
output, responseHeaders = returnMessage(False, "Nothing to do")
|
||||
else:
|
||||
output, responseHeaders = returnMessage(False, "Nothing to do")
|
||||
except:
|
||||
output, responseHeaders = returnMessage(True, "Not processing")
|
||||
else:
|
||||
debug("Unknown command %s" % (environ.get("HTTP_X_GITHUB_EVENT")))
|
||||
output, responseHeaders = returnMessage(True, "Unknown command, ignoring")
|
||||
# output = ''
|
||||
# for k, v in environ.items():
|
||||
# output += '%.40s %s\n' % (k, v)
|
||||
#responseHeaders = sendFile("ffb8c8eb-3d3b-4306-b65e-e0d1fa4f7ea0")
|
||||
start_response(status, responseHeaders)
|
||||
unlock()
|
||||
return [output]
|
||||
|
||||
if __name__ == "__main__":
|
||||
lockWait()
|
||||
if len(sys.argv) < 2:
|
||||
unlock()
|
||||
sys.exit()
|
||||
if sys.argv[1] == "commit":
|
||||
updateLocalTranslationSource(tempdir)
|
||||
response = uploadTranslationSource(tempdir)
|
||||
print "Uploaded to transifex: %i, %s" % (response.status_code, response.content)
|
||||
elif sys.argv[1] == "translated":
|
||||
if len(sys.argv) < 3:
|
||||
unlock()
|
||||
sys.exit()
|
||||
lang = sys.argv[2]
|
||||
print "Cloning repo"
|
||||
ts = int(time.time())
|
||||
updateLocalTranslationDestination(ts, lang.lower())
|
||||
print "Downloading translated file"
|
||||
downloadTranslatedLanguage(ts, lang)
|
||||
print "Creating pull request"
|
||||
response = commitTranslatedLanguage(ts, lang.lower())
|
||||
print "Pull request sent"
|
||||
elif sys.argv[1] == "rebase":
|
||||
for pull in listPullRequests():
|
||||
rebasePullRequest(pull['branch'])
|
||||
print "Rebased %s" % (pull['number'])
|
||||
break
|
||||
unlock()
|
Loading…
Reference in New Issue
Block a user