Skip to content

Commit 0692076

Browse files
authored
Merge pull request #6614 from stsewd/dont-trigger-two-syncs
Don't trigger a sync twice on creation/deletion for GitHub
2 parents 50c63f7 + a95c90c commit 0692076

File tree

4 files changed

+126
-4
lines changed

4 files changed

+126
-4
lines changed

readthedocs/api/v2/views/integrations.py

+22-3
Original file line numberDiff line numberDiff line change
@@ -196,12 +196,19 @@ def get_response_push(self, project, branches):
196196
'versions': list(to_build),
197197
}
198198

199-
def sync_versions(self, project):
200-
version = sync_versions(project)
199+
def sync_versions(self, project, sync=True):
200+
"""
201+
Trigger a sync and returns a response indicating if the build was triggered or not.
202+
203+
If `sync` is False, the sync isn't triggered and a response indicating so is returned.
204+
"""
205+
version = None
206+
if sync:
207+
version = sync_versions(project)
201208
return {
202209
'build_triggered': False,
203210
'project': project.slug,
204-
'versions': [version],
211+
'versions': [version] if version else [],
205212
'versions_synced': version is not None,
206213
}
207214

@@ -379,6 +386,18 @@ def handle_webhook(self):
379386
raise ParseError('Parameter "ref" is required')
380387
# Sync versions on other PUSH events that create or delete
381388
elif event in (GITHUB_CREATE, GITHUB_DELETE, GITHUB_PUSH):
389+
if event == GITHUB_PUSH:
390+
# GitHub will send push and create/delete events on a creation/deletion.
391+
# If we receive a push event we need to check if the webhook doesn't
392+
# already have the create/delete events. So we don't trigger the sync twice.
393+
# We listen to push events for creation/deletion for old webhooks only.
394+
integration = self.get_integration()
395+
events = integration.provider_data.get('events', [])
396+
if (
397+
(created and GITHUB_CREATE in events) or
398+
(deleted and GITHUB_DELETE in events)
399+
):
400+
return self.sync_versions(self.project, sync=False)
382401
return self.sync_versions(self.project)
383402

384403
elif (
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# -*- coding: utf-8 -*-
2+
# Generated by Django 1.11.27 on 2020-02-17 18:14
3+
from __future__ import unicode_literals
4+
5+
from django.db import migrations
6+
import jsonfield.fields
7+
8+
9+
class Migration(migrations.Migration):
10+
11+
dependencies = [
12+
('integrations', '0005_change_default_integration_secret'),
13+
]
14+
15+
operations = [
16+
migrations.AlterField(
17+
model_name='integration',
18+
name='provider_data',
19+
field=jsonfield.fields.JSONField(default=dict, verbose_name='Provider data'),
20+
),
21+
]

readthedocs/integrations/models.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ class Integration(models.Model):
252252
max_length=32,
253253
choices=INTEGRATIONS,
254254
)
255-
provider_data = JSONField(_('Provider data'))
255+
provider_data = JSONField(_('Provider data'), default=dict)
256256
exchanges = GenericRelation(
257257
'HttpExchange',
258258
related_query_name='integrations',

readthedocs/rtd_tests/tests/test_api.py

+82
Original file line numberDiff line numberDiff line change
@@ -1345,6 +1345,88 @@ def test_github_skip_signature_validation(self, trigger_build):
13451345
)
13461346
self.assertEqual(resp.status_code, 200)
13471347

1348+
def test_github_sync_on_push_event(self, trigger_build):
1349+
"""Sync if the webhook doesn't have the create/delete events, but we recieve a push event with created/deleted."""
1350+
integration = Integration.objects.create(
1351+
project=self.project,
1352+
integration_type=Integration.GITHUB_WEBHOOK,
1353+
provider_data={
1354+
'events': [],
1355+
},
1356+
secret=None,
1357+
)
1358+
1359+
client = APIClient()
1360+
1361+
headers = {
1362+
GITHUB_EVENT_HEADER: GITHUB_PUSH,
1363+
}
1364+
payload = {
1365+
'ref': 'master',
1366+
'created': True,
1367+
'deleted': False,
1368+
}
1369+
resp = client.post(
1370+
reverse(
1371+
'api_webhook_github',
1372+
kwargs={'project_slug': self.project.slug}
1373+
),
1374+
payload,
1375+
format='json',
1376+
**headers
1377+
)
1378+
self.assertTrue(resp.json()['versions_synced'])
1379+
1380+
def test_github_dont_trigger_double_sync(self, trigger_build):
1381+
"""Don't trigger a sync twice if the webhook has the create/delete events."""
1382+
integration = Integration.objects.create(
1383+
project=self.project,
1384+
integration_type=Integration.GITHUB_WEBHOOK,
1385+
provider_data={
1386+
'events': [
1387+
GITHUB_CREATE,
1388+
GITHUB_DELETE,
1389+
],
1390+
},
1391+
secret=None,
1392+
)
1393+
1394+
client = APIClient()
1395+
1396+
headers = {
1397+
GITHUB_EVENT_HEADER: GITHUB_PUSH,
1398+
}
1399+
payload = {
1400+
'ref': 'master',
1401+
'created': True,
1402+
'deleted': False,
1403+
}
1404+
resp = client.post(
1405+
reverse(
1406+
'api_webhook_github',
1407+
kwargs={'project_slug': self.project.slug}
1408+
),
1409+
payload,
1410+
format='json',
1411+
**headers
1412+
)
1413+
self.assertFalse(resp.json()['versions_synced'])
1414+
1415+
headers = {
1416+
GITHUB_EVENT_HEADER: GITHUB_CREATE,
1417+
}
1418+
payload = {'ref': 'master'}
1419+
resp = client.post(
1420+
reverse(
1421+
'api_webhook_github',
1422+
kwargs={'project_slug': self.project.slug}
1423+
),
1424+
payload,
1425+
format='json',
1426+
**headers
1427+
)
1428+
self.assertTrue(resp.json()['versions_synced'])
1429+
13481430
def test_gitlab_webhook_for_branches(self, trigger_build):
13491431
"""GitLab webhook API."""
13501432
client = APIClient()

0 commit comments

Comments
 (0)