-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Sync versions when creating/deleting versions #4876
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 15 commits
c277d4f
05baf4f
50731cb
ab87956
2caab91
d96a412
e5fe6ea
004e9fa
9641ca6
e17a703
97cc096
439221e
1d3862b
107235e
4ee70e8
54f57a1
dd235f3
804d717
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -75,6 +75,29 @@ def build_branches(project, branch_list): | |
return (to_build, not_building) | ||
|
||
|
||
def sync_versions(project): | ||
""" | ||
Sync the versions of a repo using its latest version. | ||
|
||
This doesn't register a new build, | ||
but clones the repo and syncs the versions. | ||
Due that `sync_repository_task` is bound to a version, | ||
we always pass the latest version. | ||
|
||
:returns: The version that was used to trigger the clone (usually latest). | ||
""" | ||
try: | ||
version_slug = LATEST | ||
version = project.versions.get(slug=version_slug) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Won't this fail for users that override the I don't remember exactly, but I think there was also a way to disable There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yup, I was considering using the default branch here instead. |
||
sync_repository_task.delay(version.pk) | ||
return version.slug | ||
except Project.DoesNotExist: | ||
log.info('Unable to sync from %s version', version_slug) | ||
except Exception as e: | ||
log.exception('Unknown sync versions exception') | ||
return None | ||
|
||
|
||
def get_project_from_url(url): | ||
if not url: | ||
return Project.objects.none() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,44 @@ | ||
"""Endpoints integrating with Github, Bitbucket, and other webhooks.""" | ||
|
||
from __future__ import absolute_import | ||
from __future__ import ( | ||
absolute_import, | ||
division, | ||
print_function, | ||
unicode_literals, | ||
) | ||
|
||
import json | ||
import logging | ||
import re | ||
|
||
from builtins import object | ||
import six | ||
from django.shortcuts import get_object_or_404 | ||
from rest_framework import permissions | ||
from rest_framework.views import APIView | ||
from rest_framework.exceptions import NotFound, ParseError | ||
from rest_framework.renderers import JSONRenderer | ||
from rest_framework.response import Response | ||
from rest_framework.exceptions import ParseError, NotFound | ||
|
||
from django.shortcuts import get_object_or_404 | ||
from rest_framework.views import APIView | ||
|
||
from readthedocs.core.views.hooks import build_branches | ||
from readthedocs.core.signals import (webhook_github, webhook_bitbucket, | ||
webhook_gitlab) | ||
from readthedocs.core.signals import ( | ||
webhook_bitbucket, | ||
webhook_github, | ||
webhook_gitlab, | ||
) | ||
from readthedocs.core.views.hooks import build_branches, sync_versions | ||
from readthedocs.integrations.models import HttpExchange, Integration | ||
from readthedocs.integrations.utils import normalize_request_payload | ||
from readthedocs.projects.models import Project | ||
import six | ||
|
||
|
||
log = logging.getLogger(__name__) | ||
|
||
GITHUB_EVENT_HEADER = 'HTTP_X_GITHUB_EVENT' | ||
GITHUB_PUSH = 'push' | ||
GITHUB_CREATE = 'create' | ||
GITHUB_DELETE = 'delete' | ||
GITLAB_PUSH = 'push' | ||
GITLAB_NULL_HASH = '0' * 40 | ||
GITLAB_TAG_PUSH = 'tag_push' | ||
BITBUCKET_EVENT_HEADER = 'HTTP_X_EVENT_KEY' | ||
BITBUCKET_PUSH = 'repo:push' | ||
|
||
|
||
|
@@ -124,6 +136,14 @@ def get_response_push(self, project, branches): | |
'project': project.slug, | ||
'versions': list(to_build)} | ||
|
||
def sync_versions(self, project): | ||
version = sync_versions(project) | ||
return { | ||
'build_triggered': False, | ||
'project': project.slug, | ||
'versions': [version], | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Still not sure about what to return, I'm returning the version that was used to do the clone, I guess this isn't so important, I mean, no one uses this, it's just sent to the integration (GitHub) |
||
|
||
|
||
class GitHubWebhookView(WebhookMixin, APIView): | ||
|
||
|
@@ -154,7 +174,7 @@ def get_data(self): | |
|
||
def handle_webhook(self): | ||
# Get event and trigger other webhook events | ||
event = self.request.META.get('HTTP_X_GITHUB_EVENT', 'push') | ||
event = self.request.META.get(GITHUB_EVENT_HEADER, GITHUB_PUSH) | ||
webhook_github.send(Project, project=self.project, | ||
data=self.data, event=event) | ||
# Handle push events and trigger builds | ||
|
@@ -164,6 +184,9 @@ def handle_webhook(self): | |
return self.get_response_push(self.project, branches) | ||
except KeyError: | ||
raise ParseError('Parameter "ref" is required') | ||
if event in (GITHUB_CREATE, GITHUB_DELETE): | ||
return self.sync_versions(self.project) | ||
return None | ||
|
||
def _normalize_ref(self, ref): | ||
pattern = re.compile(r'^refs/(heads|tags)/') | ||
|
@@ -191,15 +214,31 @@ class GitLabWebhookView(WebhookMixin, APIView): | |
def handle_webhook(self): | ||
# Get event and trigger other webhook events | ||
event = self.request.data.get('object_kind', GITLAB_PUSH) | ||
webhook_gitlab.send(Project, project=self.project, | ||
data=self.request.data, event=event) | ||
webhook_gitlab.send( | ||
Project, | ||
project=self.project, | ||
data=self.request.data, | ||
event=event | ||
) | ||
# Handle push events and trigger builds | ||
if event == GITLAB_PUSH: | ||
if event in (GITLAB_PUSH, GITLAB_TAG_PUSH): | ||
data = self.request.data | ||
before = data['before'] | ||
after = data['after'] | ||
# Tag/branch created/deleted | ||
if GITLAB_NULL_HASH in (before, after): | ||
stsewd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return self.sync_versions(self.project) | ||
# Normal push to master | ||
try: | ||
branches = [self.request.data['ref'].replace('refs/heads/', '')] | ||
branches = [self._normalize_ref(data['ref'])] | ||
return self.get_response_push(self.project, branches) | ||
except KeyError: | ||
raise ParseError('Parameter "ref" is required') | ||
return None | ||
|
||
def _normalize_ref(self, ref): | ||
pattern = re.compile(r'^refs/(heads|tags)/') | ||
return pattern.sub('', ref) | ||
|
||
|
||
class BitbucketWebhookView(WebhookMixin, APIView): | ||
|
@@ -230,19 +269,30 @@ class BitbucketWebhookView(WebhookMixin, APIView): | |
|
||
def handle_webhook(self): | ||
# Get event and trigger other webhook events | ||
event = self.request.META.get('HTTP_X_EVENT_KEY', BITBUCKET_PUSH) | ||
webhook_bitbucket.send(Project, project=self.project, | ||
data=self.request.data, event=event) | ||
# Handle push events and trigger builds | ||
event = self.request.META.get(BITBUCKET_EVENT_HEADER, BITBUCKET_PUSH) | ||
webhook_bitbucket.send( | ||
Project, | ||
project=self.project, | ||
data=self.request.data, | ||
event=event | ||
) | ||
if event == BITBUCKET_PUSH: | ||
try: | ||
changes = self.request.data['push']['changes'] | ||
branches = [change['new']['name'] | ||
for change in changes | ||
if change.get('new')] | ||
return self.get_response_push(self.project, branches) | ||
data = self.request.data | ||
changes = data['push']['changes'] | ||
branches = [] | ||
for change in changes: | ||
old = change['old'] | ||
new = change['new'] | ||
# Normal push to master | ||
if old is not None and new is not None: | ||
branches.append(new['name']) | ||
if branches: | ||
return self.get_response_push(self.project, branches) | ||
return self.sync_versions(self.project) | ||
stsewd marked this conversation as resolved.
Show resolved
Hide resolved
|
||
except KeyError: | ||
raise ParseError('Invalid request') | ||
return None | ||
|
||
|
||
class IsAuthenticatedOrHasToken(permissions.IsAuthenticated): | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Returns the version slug.
You can use
:rtype: string
also here.