Skip to content

Commit 07bcf4c

Browse files
stsewdagjohnson
authored andcommitted
Allow tags from GitHub webhooks (#3546)
* Filter by verbose_name * Allow tags from GitHub webhook * Add tests * Remove useless instance * Add real tests for parsing ref * Fix versions * Check for versions * Refactor tests * Split tests
1 parent f9316b9 commit 07bcf4c

File tree

3 files changed

+61
-5
lines changed

3 files changed

+61
-5
lines changed

readthedocs/projects/models.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -784,7 +784,8 @@ def versions_from_branch_name(self, branch):
784784
return (
785785
self.versions.filter(identifier=branch) |
786786
self.versions.filter(identifier='remotes/origin/%s' % branch) |
787-
self.versions.filter(identifier='origin/%s' % branch)
787+
self.versions.filter(identifier='origin/%s' % branch) |
788+
self.versions.filter(verbose_name=branch)
788789
)
789790

790791
def get_default_version(self):

readthedocs/restapi/views/integrations.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from __future__ import absolute_import
44
import json
55
import logging
6+
import re
67

78
from builtins import object
89
from rest_framework import permissions
@@ -159,11 +160,15 @@ def handle_webhook(self):
159160
# Handle push events and trigger builds
160161
if event == GITHUB_PUSH:
161162
try:
162-
branches = [self.data['ref'].replace('refs/heads/', '')]
163+
branches = [self._normalize_ref(self.data['ref'])]
163164
return self.get_response_push(self.project, branches)
164165
except KeyError:
165166
raise ParseError('Parameter "ref" is required')
166167

168+
def _normalize_ref(self, ref):
169+
pattern = re.compile(r'^refs/(heads|tags)/')
170+
return pattern.sub('', ref)
171+
167172

168173
class GitLabWebhookView(WebhookMixin, APIView):
169174

readthedocs/rtd_tests/tests/test_api.py

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
from readthedocs.integrations.models import Integration
2222
from readthedocs.oauth.models import RemoteOrganization, RemoteRepository
2323
from readthedocs.projects.models import Feature, Project
24+
from readthedocs.restapi.views.integrations import GitHubWebhookView
2425
from readthedocs.restapi.views.task_views import get_status_data
2526

2627
super_auth = base64.b64encode(b'super:test').decode('utf-8')
@@ -632,18 +633,21 @@ class IntegrationsTests(TestCase):
632633

633634
def setUp(self):
634635
self.project = get(Project)
635-
self.version = get(Version, verbose_name='master', project=self.project)
636+
self.version = get(Version, verbose_name='master', active=True, project=self.project)
637+
self.version_tag = get(Version, verbose_name='v1.0', active=True, project=self.project)
636638

637-
def test_github_webhook(self, trigger_build):
639+
def test_github_webhook_for_branches(self, trigger_build):
638640
"""GitHub webhook API."""
639641
client = APIClient()
642+
640643
client.post(
641644
'/api/v2/webhook/github/{0}/'.format(self.project.slug),
642645
{'ref': 'master'},
643646
format='json',
644647
)
645648
trigger_build.assert_has_calls(
646-
[mock.call(force=True, version=mock.ANY, project=self.project)])
649+
[mock.call(force=True, version=self.version, project=self.project)])
650+
647651
client.post(
648652
'/api/v2/webhook/github/{0}/'.format(self.project.slug),
649653
{'ref': 'non-existent'},
@@ -652,6 +656,52 @@ def test_github_webhook(self, trigger_build):
652656
trigger_build.assert_has_calls(
653657
[mock.call(force=True, version=mock.ANY, project=self.project)])
654658

659+
client.post(
660+
'/api/v2/webhook/github/{0}/'.format(self.project.slug),
661+
{'ref': 'refs/heads/master'},
662+
format='json',
663+
)
664+
trigger_build.assert_has_calls(
665+
[mock.call(force=True, version=self.version, project=self.project)])
666+
667+
def test_github_webhook_for_tags(self, trigger_build):
668+
"""GitHub webhook API."""
669+
client = APIClient()
670+
671+
client.post(
672+
'/api/v2/webhook/github/{0}/'.format(self.project.slug),
673+
{'ref': 'v1.0'},
674+
format='json',
675+
)
676+
trigger_build.assert_has_calls(
677+
[mock.call(force=True, version=self.version_tag, project=self.project)])
678+
679+
client.post(
680+
'/api/v2/webhook/github/{0}/'.format(self.project.slug),
681+
{'ref': 'refs/heads/non-existent'},
682+
format='json',
683+
)
684+
trigger_build.assert_has_calls(
685+
[mock.call(force=True, version=mock.ANY, project=self.project)])
686+
687+
client.post(
688+
'/api/v2/webhook/github/{0}/'.format(self.project.slug),
689+
{'ref': 'refs/tags/v1.0'},
690+
format='json',
691+
)
692+
trigger_build.assert_has_calls(
693+
[mock.call(force=True, version=self.version_tag, project=self.project)])
694+
695+
def test_github_parse_ref(self, trigger_build):
696+
wh = GitHubWebhookView()
697+
698+
self.assertEqual(wh._normalize_ref('refs/heads/master'), 'master')
699+
self.assertEqual(wh._normalize_ref('refs/heads/v0.1'), 'v0.1')
700+
self.assertEqual(wh._normalize_ref('refs/tags/v0.1'), 'v0.1')
701+
self.assertEqual(wh._normalize_ref('refs/tags/tag'), 'tag')
702+
self.assertEqual(wh._normalize_ref('refs/heads/stable/2018'), 'stable/2018')
703+
self.assertEqual(wh._normalize_ref('refs/tags/tag/v0.1'), 'tag/v0.1')
704+
655705
def test_github_invalid_webhook(self, trigger_build):
656706
"""GitHub webhook unhandled event."""
657707
client = APIClient()

0 commit comments

Comments
 (0)