Skip to content

Commit 9002ff1

Browse files
committed
feat(webhook): Add GitLab webhook end-point.
Add a dedicated GitLab webhook end-point for push events on a GitLab-hosted project. The GitLab webhook end-point must be separate from GitHub as the contents of GitLab's POST message, resulting from a push event, has different payload data than what is found in an equivalent GitHub POST.
1 parent fad2c31 commit 9002ff1

File tree

3 files changed

+121
-0
lines changed

3 files changed

+121
-0
lines changed

readthedocs/core/views.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,31 @@ def github_build(request):
249249
return HttpResponse("You must POST to this resource.")
250250

251251

252+
@csrf_exempt
253+
def gitlab_build(request):
254+
"""
255+
A post-commit hook for GitLab.
256+
"""
257+
if request.method == 'POST':
258+
try:
259+
# GitLab RTD integration
260+
obj = json.loads(request.POST['payload'])
261+
except:
262+
# Generic post-commit hook
263+
obj = json.loads(request.body)
264+
url = obj['repository']['homepage']
265+
ghetto_url = url.replace('http://', '').replace('https://', '')
266+
branch = obj['ref'].replace('refs/heads/', '')
267+
pc_log.info("(Incoming GitLab Build) %s [%s]" % (ghetto_url, branch))
268+
try:
269+
return _build_url(ghetto_url, [branch])
270+
except NoProjectException:
271+
pc_log.error(
272+
"(Incoming GitLab Build) Repo not found: %s" % ghetto_url)
273+
return HttpResponseNotFound('Repo not found: %s' % ghetto_url)
274+
else:
275+
return HttpResponse("You must POST to this resource.")
276+
252277
@csrf_exempt
253278
def bitbucket_build(request):
254279
if request.method == 'POST':

readthedocs/rtd_tests/tests/test_post_commit_hooks.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,101 @@
88
log = logging.getLogger(__name__)
99

1010

11+
class GitLabWebHookTest(TestCase):
12+
fixtures = ["eric", "test_data"]
13+
14+
def tearDown(self):
15+
tasks.update_docs = self.old_bd
16+
17+
def setUp(self):
18+
self.old_bd = tasks.update_docs
19+
20+
def mock(*args, **kwargs):
21+
log.info("Mocking for great profit and speed.")
22+
tasks.update_docs = mock
23+
tasks.update_docs.delay = mock
24+
25+
self.client.login(username='eric', password='test')
26+
self.payload = {
27+
"object_kind": "push",
28+
"before": "95790bf891e76fee5e1747ab589903a6a1f80f22",
29+
"after": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
30+
"ref": "refs/heads/awesome",
31+
"user_id": 4,
32+
"user_name": "John Smith",
33+
"user_email": "[email protected]",
34+
"project_id": 15,
35+
"repository": {
36+
"name": "Diaspora",
37+
"url": "[email protected]:rtfd/readthedocs.org.git",
38+
"description": "",
39+
"homepage": "http://github.com/rtfd/readthedocs.org",
40+
"git_http_url": "http://github.com/rtfd/readthedocs.org.git",
41+
"git_ssh_url": "[email protected]:rtfd/readthedocs.org.git",
42+
"visibility_level":0
43+
},
44+
"commits": [
45+
{
46+
"id": "b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
47+
"message": "Update Catalan translation to e38cb41.",
48+
"timestamp": "2011-12-12T14:27:31+02:00",
49+
"url": "http://github.com/mike/diaspora/commit/b6568db1bc1dcd7f8b4d5a946b0b91f9dacd7327",
50+
"author": {
51+
"name": "Jordi Mallach",
52+
"email": "[email protected]"
53+
}
54+
},
55+
{
56+
"id": "da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
57+
"message": "fixed readme",
58+
"timestamp": "2012-01-03T23:36:29+02:00",
59+
"url": "http://github.com/mike/diaspora/commit/da1560886d4f094c3e6c9ef40349f7d38b5d27d7",
60+
"author": {
61+
"name": "GitLab dev user",
62+
"email": "gitlabdev@dv6700.(none)"
63+
}
64+
}
65+
],
66+
"total_commits_count": 4
67+
}
68+
69+
def test_gitlab_post_commit_hook_builds_branch_docs_if_it_should(self):
70+
"""
71+
Test the github post commit hook to see if it will only build
72+
versions that are set to be built if the branch they refer to
73+
is updated. Otherwise it is no op.
74+
"""
75+
r = self.client.post('/gitlab/', {'payload': json.dumps(self.payload)})
76+
self.assertEqual(r.status_code, 200)
77+
self.assertEqual(r.content, '(URL Build) Build Started: github.com/rtfd/readthedocs.org [awesome]')
78+
self.payload['ref'] = 'refs/heads/not_ok'
79+
r = self.client.post('/gitlab/', {'payload': json.dumps(self.payload)})
80+
self.assertEqual(r.status_code, 200)
81+
self.assertEqual(r.content, '(URL Build) Not Building: github.com/rtfd/readthedocs.org [not_ok]')
82+
self.payload['ref'] = 'refs/heads/unknown'
83+
r = self.client.post('/gitlab/', {'payload': json.dumps(self.payload)})
84+
self.assertEqual(r.status_code, 200)
85+
self.assertEqual(r.content, '(URL Build) Not Building: github.com/rtfd/readthedocs.org []')
86+
87+
def test_gitlab_post_commit_knows_default_branches(self):
88+
"""
89+
Test the gitlab post commit hook so that the default branch
90+
will be respected and built as the latest version.
91+
"""
92+
rtd = Project.objects.get(slug='read-the-docs')
93+
old_default = rtd.default_branch
94+
rtd.default_branch = 'master'
95+
rtd.save()
96+
self.payload['ref'] = 'refs/heads/master'
97+
98+
r = self.client.post('/gitlab/', {'payload': json.dumps(self.payload)})
99+
self.assertEqual(r.status_code, 200)
100+
self.assertEqual(r.content, '(URL Build) Build Started: github.com/rtfd/readthedocs.org [latest]')
101+
102+
rtd.default_branch = old_default
103+
rtd.save()
104+
105+
11106
class PostCommitTest(TestCase):
12107
fixtures = ["eric", "test_data"]
13108

readthedocs/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@
101101
url(r'^admin/', include(admin.site.urls)),
102102
url(r'^dashboard/', include('projects.urls.private')),
103103
url(r'^github', 'core.views.github_build', name='github_build'),
104+
url(r'^gitlab', 'core.views.gitlab_build', name='gitlab_build'),
104105
url(r'^bitbucket', 'core.views.bitbucket_build', name='bitbucket_build'),
105106
url((r'^build/'
106107
r'(?P<project_id_or_slug>{project_slug})'.format(**pattern_opts)),

0 commit comments

Comments
 (0)