Commit 3836a3d6 authored by Michal Čihař's avatar Michal Čihař

Merge pull request #500 from nblock/feature/gitlab-support

Feature/gitlab-support
parents 84c9f179 13af2a47
......@@ -34,6 +34,13 @@ repository has been updated.
.. seealso:: http://help.github.com/post-receive-hooks/ :setting:`ENABLE_HOOKS`
.. describe:: POST /hooks/gitlab/
Special hook for handling GitLab notifications and automatically updating
matching subprojects.
.. seealso:: http://doc.gitlab.com/ce/web_hooks/web_hooks.html :setting:`ENABLE_HOOKS`
.. describe:: POST /hooks/bitbucket/
Special hook for handling Bitbucket notifications and automatically
......
......@@ -13,7 +13,7 @@ Weblate can handle all the translation things semi-automatically for you. If
you will give it push access to your repository, the translations can live
without interaction unless some merge conflict occurs.
1. Set up you git repository to tell Weblate whenever there is any change, see
1. Set up your git repository to tell Weblate whenever there is any change, see
:ref:`hooks` for information how to do it.
2. Set push URL at your :ref:`subproject` in Weblate, this will allow Weblate
to push changes to your repository.
......
......@@ -119,6 +119,11 @@
<td>{% trans "Enable Weblate service hook in repository settings." %}</td>
</tr>
<tr>
<th><a href="https://about.gitlab.com/">GitLab</a></th>
<td>{{ site_url }}{% url 'hook-gitlab' %}</td>
<td></td>
</tr>
<tr>
<th><a href="https://bitbucket.org/">Bitbucket</a></th>
<td>{{ site_url }}{% url 'hook-bitbucket' %}</td>
<td></td>
......
......@@ -69,6 +69,46 @@ GITHUB_PAYLOAD = '''
}
'''
GITLAB_PAYLOAD = '''
{
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"ref": "refs/heads/master",
"user_id": 4,
"user_name": "John Smith",
"project_id": 15,
"repository": {
"name": "Diaspora",
"url": "git@example.com:diaspora.git",
"description": "",
"homepage": "http://example.com/diaspora"
},
"commits": [
{
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
"message": "Update Catalan translation to e38cb41.",
"timestamp": "2011-12-12T14:27:31+02:00",
"url": "http://example.com/diaspora/commits/b6568db1b",
"author": {
"name": "Jordi Mallach",
"email": "jordi@softcatala.org"
}
},
{
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
"message": "fixed readme",
"timestamp": "2012-01-03T23:36:29+02:00",
"url": "http://example.com/diaspora/commits/da1560886",
"author": {
"name": "GitLab dev user",
"email": "gitlabdev@dv6700.(none)"
}
}
],
"total_commits_count": 4
}
'''
BITBUCKET_PAYLOAD_GIT = '''
{
"canon_url": "https://bitbucket.org",
......@@ -201,6 +241,15 @@ class HooksViewTest(ViewTestCase):
)
self.assertContains(response, 'update triggered')
def test_view_hook_gitlab(self):
appsettings.BACKGROUND_HOOKS = False
appsettings.ENABLE_HOOKS = True
response = self.client.post(
reverse('hook-gitlab'), GITLAB_PAYLOAD,
content_type="application/json"
)
self.assertContains(response, 'update triggered')
def test_view_hook_bitbucket_git(self):
appsettings.BACKGROUND_HOOKS = False
appsettings.ENABLE_HOOKS = True
......@@ -251,15 +300,20 @@ class HooksViewTest(ViewTestCase):
{'payload': GITHUB_PAYLOAD}
)
self.assertEqual(response.status_code, 405)
response = self.client.post(
reverse('hook-gitlab'), GITLAB_PAYLOAD,
content_type="application/json"
)
self.assertEqual(response.status_code, 405)
response = self.client.post(
reverse('hook-bitbucket'),
{'payload': BITBUCKET_PAYLOAD_GIT}
)
self.assertEqual(response.status_code, 405)
def test_wrong_payload(self):
def test_wrong_payload_github(self):
'''
Tests for invalid payloads.
Tests for invalid payloads with github.
'''
# missing
response = self.client.post(
......@@ -290,3 +344,47 @@ class HooksViewTest(ViewTestCase):
'Invalid data in json payload!',
status_code=400
)
def test_wrong_payload_gitlab(self):
'''
Tests for invalid payloads with gitlab.
'''
# missing
response = self.client.post(
reverse('hook-gitlab'),
)
self.assertContains(
response,
'Could not parse JSON payload!',
status_code=400
)
# missing content-type header
response = self.client.post(
reverse('hook-gitlab'),
{'payload': 'anything'}
)
self.assertContains(
response,
'Could not parse JSON payload!',
status_code=400
)
# wrong
response = self.client.post(
reverse('hook-gitlab'), 'xx',
content_type="application/json"
)
self.assertContains(
response,
'Could not parse JSON payload!',
status_code=400
)
# missing data
response = self.client.post(
reverse('hook-gitlab'), '{}',
content_type="application/json"
)
self.assertContains(
response,
'Invalid data in json payload!',
status_code=400
)
......@@ -92,8 +92,9 @@ def git_service_hook(request, service):
'''
Shared code between Git service hooks.
Currently used for bitbucket_hook and github_hook, but should be usable for
hook from other Git services (Google Code, custom coded sites, etc.) too.
Currently used for bitbucket_hook, github_hook and gitlab_hook, but should
be usable for other Git services (Google Code, custom coded sites, etc.)
too.
'''
# Check for enabled hooks
if appsettings.ENABLE_HOOKS:
......@@ -107,13 +108,20 @@ def git_service_hook(request, service):
# Check if we got payload
try:
data = json.loads(request.POST['payload'])
# GitLab sends json as application/json
if request.META['CONTENT_TYPE'] == 'application/json':
data = json.loads(request.body)
# Bitbucket and GitHub sends json as x-www-form-data
else:
data = json.loads(request.POST['payload'])
except (ValueError, KeyError):
return HttpResponseBadRequest('Could not parse JSON payload!')
# Get service helper
if service == 'github':
hook_helper = github_hook_helper
elif service == 'gitlab':
hook_helper = gitlab_hook_helper
elif service == 'bitbucket':
hook_helper = bitbucket_hook_helper
else:
......@@ -206,6 +214,25 @@ def github_hook_helper(data):
}
@csrf_exempt
def gitlab_hook_helper(data):
'''
API to handle commit hooks from GitLab.
'''
ssh_url = data['repository']['url']
http_url = '.'.join((data['repository']['homepage'], 'git'))
branch = re.sub(r'^refs/heads/', '', data['ref'])
# Construct possible repository URLs
repos = [ssh_url, http_url]
return {
'service_long_name': 'GitLab',
'repos': repos,
'branch': branch,
}
def json_dt_handler(obj):
'''
JSON export handler to include correctly formated datetime objects.
......
......@@ -446,6 +446,11 @@ urlpatterns = patterns(
{'service': 'github'},
name='hook-github',
),
url(
r'^hooks/gitlab/$', 'weblate.trans.views.api.git_service_hook',
{'service': 'gitlab'},
name='hook-gitlab',
),
url(
r'^hooks/bitbucket/$', 'weblate.trans.views.api.git_service_hook',
{'service': 'bitbucket'},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment