Commit 72ba58a7 authored by Guilhem Saurel's avatar Guilhem Saurel
Browse files

fix tests

parent ca7c1b56
......@@ -22,5 +22,5 @@ build:
script:
- docker build -t ${DOCKER_TAG} .
- docker run --rm -e SECRET_KEY -e GITHUB_WEBHOOK_KEY -e GITLAB_WEBHOOK_KEY -e GITHUB_PIPELINE_TOKEN -e GITLAB_PIPELINE_TOKEN -e PYTHONWARNINGS ${DOCKER_TAG} ./manage.py migrate
- docker run --rm -e SECRET_KEY -e GITHUB_WEBHOOK_KEY -e GITLAB_WEBHOOK_KEY -e GITHUB_PIPELINE_TOKEN -e GITLAB_PIPELINE_TOKEN -e PYTHONWARNINGS ${DOCKER_TAG} ./manage.py test
- docker run --rm -e SECRET_KEY -e GITHUB_WEBHOOK_KEY -e GITLAB_WEBHOOK_KEY -e GITHUB_PIPELINE_TOKEN -e GITLAB_PIPELINE_TOKEN -e PYTHONWARNINGS ${DOCKER_TAG} ./manage.py test --parallel 1
- docker push ${DOCKER_TAG}
import asyncio
from ipaddress import ip_address, ip_network
from django.conf import settings
from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
from django.shortcuts import reverse
from django.utils.decorators import sync_and_async_middleware
from rest_framework import permissions
......@@ -15,19 +17,30 @@ def ip_laas(request: HttpRequest) -> bool:
return any(forwarded_for in ip_network(net) for net in settings.LAAS_NETWORKS)
class LAASPermsMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request: HttpRequest) -> HttpResponse:
def allowed(request: HttpRequest) -> bool:
"""Allow access to pages protected at a higher application level,
or if the user is authenticated,
or if the request comes from a trusted IP.
"""
allowed = (any(request.path.startswith(f'/{url}/') for url in ALLOWED_URLS)
return (any(request.path.startswith(f'/{url}/') for url in ALLOWED_URLS)
or request.user and request.user.is_authenticated
or request.method in permissions.SAFE_METHODS and ip_laas(request))
if allowed:
return self.get_response(request)
@sync_and_async_middleware
def laas_perms_middleware(get_response):
# One-time configuration and initialization goes here.
if asyncio.iscoroutinefunction(get_response):
async def middleware(request) -> HttpResponse:
if allowed(request):
return await get_response(request)
return HttpResponseRedirect(reverse('login'))
else:
def middleware(request) -> HttpResponse:
if allowed(request):
return get_response(request)
return HttpResponseRedirect(reverse('login'))
return middleware
......@@ -58,7 +58,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
f'{PROJECT}.middleware.LAASPermsMiddleware',
f'{PROJECT}.middleware.laas_perms_middleware',
]
ROOT_URLCONF = f'{PROJECT}.urls'
......
import hmac
import re
from hashlib import sha1
import logging
from asyncio import sleep
from asgiref.sync import sync_to_async
from django.conf import settings
from django.test import TestCase
from django.urls import reverse
......@@ -11,6 +14,8 @@ import git
from autoslug.utils import slugify
from rainboard.models import Forge, Namespace, Project
LOGGER = logging.getLogger('dashboard.gh.tests')
def redact_token(func):
"""Decorator used to prevent git from leaking tokens in exception messages."""
......@@ -54,6 +59,9 @@ class GhTests(TestCase):
if branch_name in gl_branches:
cls.gitlab.branches.delete(branch_name)
logging.basicConfig(level=logging.DEBUG)
LOGGER.info('start gh tests')
def assertSync(self, branch):
"""Raise an exception if the branch is not synced between both repos."""
last_commit_github = self.github.get_branch(branch).commit.sha
......@@ -61,23 +69,23 @@ class GhTests(TestCase):
self.assertEqual(last_commit_github, last_commit_gitlab)
@redact_token
def sync(self):
async def sync(self):
"""Force both repos to be synced."""
for branch in ('master', 'devel'):
last_commit_github = self.github.get_branch(branch).commit.sha
last_commit_gitlab = self.gitlab.commits.list(ref_name=branch)[0].id
if last_commit_github != last_commit_gitlab:
print(f'sync: {branch} is not synced, force pushing commit {last_commit_gitlab} on github')
LOGGER.warning(f'sync: {branch} is not synced, force pushing commit {last_commit_gitlab} on github')
git_repo = self.project.git()
# Create the remotes if necessary
gl_remote_name = f'gitlab/{self.namespace.slug}'
gh_remote_name = f'github/{self.namespace.slug}'
if gl_remote_name not in git_repo.remotes:
git_repo.create_remote(gl_remote_name, url=self.project.remote_url_gitlab())
git_repo.create_remote(gl_remote_name, url=await sync_to_async(self.project.remote_url_gitlab)())
if gh_remote_name not in git_repo.remotes:
git_repo.create_remote(gh_remote_name, url=self.project.remote_url_github())
git_repo.create_remote(gh_remote_name, url=await sync_to_async(self.project.remote_url_github)())
# Force push the latest gitlab commit on github
git_repo.remote(gl_remote_name).fetch()
......@@ -86,7 +94,7 @@ class GhTests(TestCase):
self.assertSync(branch)
@redact_token
def gh_webhook_event(self, event, last_commit='', branch='master', pr_action='', pr_number='', pr_login=''):
async def gh_webhook_event(self, event, last_commit='', branch='master', pr_action='', pr_number='', pr_login=''):
"""Simulate receiving an event from a github webhook."""
data = {
'repository': {
......@@ -105,7 +113,7 @@ class GhTests(TestCase):
'owner': {
'login': pr_login
},
'clone_url': self.project.remote_url_github()
'clone_url': await sync_to_async(self.project.remote_url_github)()
},
'sha': last_commit
}
......@@ -116,15 +124,17 @@ class GhTests(TestCase):
request_body = self.client._encode_data(encoded_data, content_type='application/json')
msg = force_bytes(request_body)
signature = 'sha1=' + hmac.new(force_bytes(settings.GITHUB_WEBHOOK_KEY), msg, digestmod=sha1).hexdigest()
return self.client.post(reverse('webhook'),
LOGGER.info('posting a simulated gh webhook event')
LOGGER.debug(f'with: {data}')
return await self.async_client.post(reverse('webhook'),
data,
content_type='application/json',
HTTP_X_FORWARDED_FOR='140.82.112.1',
HTTP_X_HUB_SIGNATURE=signature,
HTTP_X_GITHUB_EVENT=event)
X_FORWARDED_FOR='140.82.112.1',
X_HUB_SIGNATURE=signature,
X_GITHUB_EVENT=event)
@redact_token
def gl_webhook_event(self, event, last_commit='', branch='master', status=''):
async def gl_webhook_event(self, event, last_commit='', branch='master', status=''):
"""Simulate receiving an event from a gitlab webhook."""
data = {
'repository': {
......@@ -143,74 +153,76 @@ class GhTests(TestCase):
'id': 1
}
}
return self.client.post(reverse('gl-webhook'),
return await self.async_client.post(reverse('gl-webhook'),
data,
content_type='application/json',
HTTP_X_FORWARDED_FOR='140.93.0.1',
HTTP_X_GITLAB_TOKEN=settings.GITLAB_WEBHOOK_KEY,
HTTP_X_GITLAB_EVENT=event)
X_FORWARDED_FOR='140.93.0.1',
X_GITLAB_TOKEN=settings.GITLAB_WEBHOOK_KEY,
X_GITLAB_EVENT=event)
def test_gh_webhook(self):
async def test_gh_webhook(self):
"""Test the security of the github webhook."""
# Not from github IP
response = self.client.get(reverse('webhook'), HTTP_X_FORWARDED_FOR='5.5.5.5')
response = await self.async_client.get(reverse('webhook'), X_FORWARDED_FOR='5.5.5.5')
self.assertEqual(response.status_code, 302)
# No signature
response = self.client.get(reverse('webhook'), HTTP_X_FORWARDED_FOR='140.82.112.1')
response = await self.async_client.get(reverse('webhook'), X_FORWARDED_FOR='140.82.112.1')
self.assertEqual(response.status_code, 302)
# Signature not sha1
response = self.client.get(reverse('webhook'),
HTTP_X_FORWARDED_FOR='140.82.112.1',
HTTP_X_HUB_SIGNATURE='sha256=foo')
response = await self.async_client.get(reverse('webhook'),
X_FORWARDED_FOR='140.82.112.1',
X_HUB_SIGNATURE='sha256=foo')
self.assertEqual(response.status_code, 501)
# Wrong signature
response = self.client.get(reverse('webhook'),
HTTP_X_FORWARDED_FOR='140.82.112.1',
HTTP_X_HUB_SIGNATURE='sha1=foo')
response = await self.async_client.get(reverse('webhook'),
X_FORWARDED_FOR='140.82.112.1',
X_HUB_SIGNATURE='sha1=foo')
self.assertEqual(response.status_code, 403)
# Ping
response = self.gh_webhook_event('ping')
response = await self.gh_webhook_event('ping')
self.assertEqual(response.status_code, 200)
def test_gl_webhook(self):
async def test_gl_webhook(self):
"""Test the security of the gitlab webhook."""
# Not from gitlab IP
response = self.client.get(reverse('gl-webhook'), HTTP_X_FORWARDED_FOR='5.5.5.5')
response = await self.async_client.get(reverse('gl-webhook'), X_FORWARDED_FOR='5.5.5.5')
self.assertEqual(response.status_code, 302)
# No token
response = self.client.get(reverse('gl-webhook'), HTTP_X_FORWARDED_FOR='140.93.0.1')
response = await self.async_client.get(reverse('gl-webhook'), X_FORWARDED_FOR='140.93.0.1')
self.assertEqual(response.status_code, 302)
# Wrong token
response = self.client.get(reverse('gl-webhook'), HTTP_X_FORWARDED_FOR='140.93.0.1', HTTP_X_GITLAB_TOKEN='foo')
response = await self.async_client.get(reverse('gl-webhook'),
X_FORWARDED_FOR='140.93.0.1',
X_GITLAB_TOKEN='foo')
self.assertEqual(response.status_code, 403)
# Ping
response = self.client.get(reverse('gl-webhook'),
HTTP_X_FORWARDED_FOR='140.93.0.1',
HTTP_X_GITLAB_TOKEN=settings.GITLAB_WEBHOOK_KEY,
HTTP_X_GITLAB_EVENT='ping')
response = await self.async_client.get(reverse('gl-webhook'),
X_FORWARDED_FOR='140.93.0.1',
X_GITLAB_TOKEN=settings.GITLAB_WEBHOOK_KEY,
X_GITLAB_EVENT='ping')
self.assertEqual(response.status_code, 200)
def test_push_already_synced(self):
async def test_push_already_synced(self):
"""Test push when both repos are already synced."""
self.sync()
await self.sync()
last_commit = self.github.get_branch('master').commit.sha
response = self.gh_webhook_event('push', last_commit)
response = await self.gh_webhook_event('push', last_commit)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content.decode(), 'already synced')
def push_github(self, branch):
async def push_github(self, branch):
"""Test sync after pushing to the given branch on github."""
self.sync()
await self.sync()
last_commit = self.github.get_branch(branch).commit.sha
file = self.github.get_contents('README.md', branch)
......@@ -223,24 +235,24 @@ class GhTests(TestCase):
last_commit_github = self.github.get_branch(branch).commit.sha
self.assertNotEqual(last_commit, last_commit_github)
response = self.gh_webhook_event('push', last_commit_github, branch)
response = await self.gh_webhook_event('push', last_commit_github, branch)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content.decode(), 'push event detected')
last_commit_gitlab = self.gitlab.commits.list(ref_name=branch)[0].id
self.assertEqual(last_commit_github, last_commit_gitlab)
def test_push_github_master(self):
async def test_push_github_master(self):
"""Test sync after pushing to github on master."""
self.push_github('master')
await self.push_github('master')
def test_push_github_devel(self):
async def test_push_github_devel(self):
"""Test sync after pushing to github on devel."""
self.push_github('devel')
await self.push_github('devel')
def push_gitlab(self, branch):
async def push_gitlab(self, branch):
"""Test sync after pushing to the given branch on gitlab."""
self.sync()
await self.sync()
last_commit = self.gitlab.commits.list(ref_name=branch)[0].id
# Push a new commit to gitlab
......@@ -251,24 +263,24 @@ class GhTests(TestCase):
last_commit_gitlab = self.gitlab.commits.list(ref_name=branch)[0].id
self.assertNotEqual(last_commit, last_commit_gitlab)
response = self.gl_webhook_event('Push Hook', last_commit_gitlab, branch)
response = await self.gl_webhook_event('Push Hook', last_commit_gitlab, branch)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content.decode(), 'push event detected')
last_commit_github = self.github.get_branch(branch).commit.sha
self.assertEqual(last_commit_github, last_commit_gitlab)
def test_push_gitlab_master(self):
async def test_push_gitlab_master(self):
"""Test sync after pushing to gitlab on master."""
self.push_gitlab('master')
await self.push_gitlab('master')
def test_push_gitlab_devel(self):
async def test_push_gitlab_devel(self):
"""Test sync after pushing to gitlab on devel."""
self.push_gitlab('devel')
await self.push_gitlab('devel')
def test_branch_github(self):
async def test_branch_github(self):
"""Test sync after creating or deleting a branch on github."""
self.sync()
await self.sync()
source_branch_name = 'master'
target_branch_name = 'test-branch-github'
last_commit = self.github.get_branch(source_branch_name).commit.sha
......@@ -289,7 +301,7 @@ class GhTests(TestCase):
target_branch = self.github.get_branch(target_branch_name)
last_commit_github = target_branch.commit.sha
response = self.gh_webhook_event('push', last_commit_github, target_branch_name)
response = await self.gh_webhook_event('push', last_commit_github, target_branch_name)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content.decode(), 'push event detected')
......@@ -300,14 +312,14 @@ class GhTests(TestCase):
branch_ref.delete()
self.assertNotIn(target_branch_name, [b.name for b in self.github.get_branches()])
response = self.gh_webhook_event('push', '0000000000000000000000000000000000000000', target_branch_name)
response = await self.gh_webhook_event('push', '0000000000000000000000000000000000000000', target_branch_name)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content.decode(), 'push event detected')
self.assertNotIn(target_branch_name, [b.name for b in self.gitlab.branches.list()])
def test_branch_gitlab(self):
async def test_branch_gitlab(self):
"""Test sync after creating or deleting a branch on gitlab."""
self.sync()
await self.sync()
source_branch_name = 'master'
target_branch_name = 'test-branch-gitlab'
last_commit = self.gitlab.commits.list(ref_name=source_branch_name)[0].id
......@@ -323,7 +335,7 @@ class GhTests(TestCase):
file.save(branch=target_branch_name, commit_message='Test new branch on gitlab')
last_commit_gitlab = self.gitlab.commits.list(ref_name=target_branch_name)[0].id
response = self.gl_webhook_event('Push Hook', last_commit_gitlab, target_branch_name)
response = await self.gl_webhook_event('Push Hook', last_commit_gitlab, target_branch_name)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content.decode(), 'push event detected')
......@@ -334,51 +346,77 @@ class GhTests(TestCase):
target_branch.delete()
self.assertNotIn(target_branch_name, [b.name for b in self.gitlab.branches.list()])
response = self.gl_webhook_event('Push Hook', '0000000000000000000000000000000000000000', target_branch_name)
response = await self.gl_webhook_event('Push Hook', '0000000000000000000000000000000000000000',
target_branch_name)
self.assertEqual(response.status_code, 200)
self.assertEqual(response.content.decode(), 'push event detected')
self.assertNotIn(target_branch_name, [b.name for b in self.github.get_branches()])
def test_pipeline(self):
async def test_pipeline(self):
"""Test reporting the gitlab pipeline status to github."""
self.sync()
await self.sync()
last_commit = self.gitlab.commits.list(ref_name='master')[0].id
response = self.gl_webhook_event('Pipeline Hook', last_commit, status='success')
response = await self.gl_webhook_event('Pipeline Hook', last_commit, status='success')
self.assertEqual(response.status_code, 200)
self.assertIn('success', [status.state for status in self.github.get_branch('master').commit.get_statuses()])
def test_pr(self):
async def test_pr(self):
"""Test github's pull requests."""
self.sync()
LOGGER.debug('test_pr: 0')
await self.sync()
LOGGER.debug('test_pr: 1')
not_accepted_string = "doesn't usually accept pull requests on master"
LOGGER.debug('test_pr: 2')
# Test pr on master
last_commit = self.github.get_branch("devel").commit.sha
pr_master = self.project.github().create_pull(title="Test pr on master", body='', head="devel", base="master")
response = self.gh_webhook_event('pull_request',
LOGGER.debug('test_pr: 3')
github = await sync_to_async(self.project.github)()
LOGGER.debug('test_pr: 4')
pr_master = github.create_pull(title="Test pr on master", body='', head="devel", base="master")
LOGGER.debug('test_pr: 5')
response = await self.gh_webhook_event('pull_request',
last_commit=last_commit,
pr_action="opened",
pr_login="foo",
pr_number=pr_master.number)
LOGGER.debug('test_pr: 6')
self.assertEqual(response.status_code, 200)
LOGGER.debug('test_pr: 7')
self.assertTrue([c.body for c in pr_master.get_issue_comments() if not_accepted_string in c.body])
LOGGER.debug('test_pr: 8')
await sleep(60)
LOGGER.debug('test_pr: 9')
self.assertIn(f'pr/{pr_master.number}', [b.name for b in self.gitlab.branches.list()])
LOGGER.debug('test_pr: 10')
# Test pr on devel
last_commit = self.github.get_branch("master").commit.sha
pr_devel = self.project.github().create_pull(title="Test pr on devel", body='', head="master", base="devel")
response = self.gh_webhook_event('pull_request',
LOGGER.debug('test_pr: 11')
pr_devel = github.create_pull(title="Test pr on devel", body='', head="master", base="devel")
LOGGER.debug('test_pr: 12')
response = await self.gh_webhook_event('pull_request',
last_commit=last_commit,
pr_action="opened",
pr_login="foo",
pr_number=pr_devel.number)
LOGGER.debug('test_pr: 13')
self.assertEqual(response.status_code, 200)
LOGGER.debug('test_pr: 14')
self.assertFalse([c.body for c in pr_devel.get_issue_comments() if not_accepted_string in c.body])
LOGGER.debug('test_pr: 15')
await sleep(60)
LOGGER.debug('test_pr: 16')
self.assertIn(f'pr/{pr_devel.number}', [b.name for b in self.gitlab.branches.list()])
LOGGER.debug('test_pr: 17')
# Close the pr
for pr in [pr_master, pr_devel]:
pr.edit(state="closed")
response = self.gh_webhook_event('pull_request', pr_action="closed", pr_login="foo", pr_number=pr.number)
response = await self.gh_webhook_event('pull_request',
pr_action="closed",
pr_login="foo",
pr_number=pr.number)
self.assertEqual(response.status_code, 200)
await sleep(60)
self.assertNotIn(f'pr/{pr.number}', [b.name for b in self.gitlab.branches.list()])
......@@ -7,6 +7,7 @@ from hashlib import sha1
from ipaddress import ip_address, ip_network
from json import loads
from asgiref.sync import sync_to_async, async_to_sync
from django.conf import settings
from django.core.mail import mail_admins
from django.http import HttpRequest
......@@ -27,8 +28,11 @@ from . import models
logger = logging.getLogger(__name__)
PR_MASTER_MSG = """Hi ! This project doesn't usually accept pull requests on master. If this wasn't intentionnal, you
can change the base branch of this pull request to devel (No need to close it for that). Best, a bot."""
def check_suite(request: HttpRequest, rep: str) -> HttpResponse:
async def check_suite(request: HttpRequest, rep: str) -> HttpResponse:
"""Manage Github's check suites."""
data = loads(request.body.decode())
slug = slugify(data['repository']['name'])
......@@ -36,39 +40,43 @@ def check_suite(request: HttpRequest, rep: str) -> HttpResponse:
if 'ros-release' in slug: # Don't run check suites on ros-release repositories
return HttpResponse(rep)
models.GithubCheckSuite.objects.get_or_create(id=data['check_suite']['id'])
await sync_to_async(models.GithubCheckSuite.objects.get_or_create)(id=data['check_suite']['id'])
return HttpResponse(rep)
def pull_request(request: HttpRequest, rep: str) -> HttpResponse:
async def pull_request(request: HttpRequest, rep: str) -> HttpResponse:
"""Manage Github's Pull Requests."""
logger.info('process gh pr')
data = loads(request.body.decode())
event = data['action']
branch = f'pr/{data["number"]}'
login = slugify(data["pull_request"]["head"]["repo"]["owner"]["login"])
namespace = get_object_or_404(Namespace, slug_github=slugify(data['repository']['owner']['login']))
project = get_object_or_404(Project, main_namespace=namespace, slug=slugify(data['repository']['name']))
git_repo = project.git()
namespace = await sync_to_async(get_object_or_404)(Namespace,
slug_github=slugify(data['repository']['owner']['login']))
project = await sync_to_async(get_object_or_404)(Project,
main_namespace=namespace,
slug=slugify(data['repository']['name']))
git_repo = await sync_to_async(project.git)()
logger.debug(f'{namespace.slug}/{project.slug}: Pull request on {branch}: {event}')
# Prevent pull requests on master when necessary
if event in ['opened', 'reopened']:
gh = project.github()
pr = gh.get_pull(data["number"])
gh = await sync_to_async(project.github)()
pr = await sync_to_async(gh.get_pull)(data["number"])
pr_branch = pr.base.ref
if not project.accept_pr_to_master and pr_branch == 'master' \
and 'devel' in [b.name for b in gh.get_branches()] and login != namespace.slug_github:
if not project.accept_pr_to_master and pr_branch == 'master' and 'devel' in [
b.name for b in await sync_to_async(gh.get_branches)()
] and login != namespace.slug_github:
logger.info(f"{namespace.slug}/{project.slug}: New pr {data['number']} to master")
pr.create_issue_comment("Hi ! This project doesn't usually accept pull requests on master. If this wasn't "
"intentionnal, you can change the base branch of this pull request to devel "
"(No need to close it for that). Best, a bot.")
await sync_to_async(pr.create_issue_comment)(PR_MASTER_MSG)
gh_remote_name = f'github/{login}'
if gh_remote_name not in git_repo.remotes:
remote = git_repo.create_remote(gh_remote_name, data["pull_request"]["head"]["repo"]["clone_url"])
remote = await sync_to_async(git_repo.create_remote)(gh_remote_name,
data["pull_request"]["head"]["repo"]["clone_url"])
else:
remote = git_repo.remote(gh_remote_name)
remote = await sync_to_async(git_repo.remote)(gh_remote_name)
# Sync the pull request with the pr/XX branch on Gitlab
if event in ['opened', 'reopened', 'synchronize']:
......@@ -79,12 +87,13 @@ def pull_request(request: HttpRequest, rep: str) -> HttpResponse:
if branch in git_repo.branches:
git_repo.heads[branch].commit = commit
else:
git_repo.create_head(branch, commit=commit)
await sync_to_async(git_repo.create_head)(branch, commit=commit)
# Create a gitlab remote if it doesn't exist
gl_remote_name = f'gitlab/{namespace.slug}'
if gl_remote_name not in git_repo.remotes:
git_repo.create_remote(gl_remote_name, url=project.remote_url_gitlab())
url = await sync_to_async(project.remote_url_gitlab)()
await sync_to_async(git_repo.create_remote)(gl_remote_name, url=url)
# Push the changes to gitlab
logger.info(f'{namespace.slug}/{project.slug}: Pushing {commit} on {branch} on gitlab')
......@@ -99,14 +108,16 @@ def pull_request(request: HttpRequest, rep: str) -> HttpResponse:
if branch in git_repo.branches:
git_repo.delete_head(branch, force=True)
git_repo.delete_remote(gh_remote_name)
project.gitlab().branches.delete(branch)
gitlab = await sync_to_async(project.gitlab)()
await sync_to_async(gitlab.branches.delete)(branch)
logger.info(f'{namespace.slug}/{project.slug}: Deleted branch {branch}')
return HttpResponse(rep)
def push(request: HttpRequest, source: SOURCES, rep: str) -> HttpResponse:
async def push(request: HttpRequest, source: SOURCES, rep: str) -> HttpResponse:
"""Someone pushed on github or gitlab. Synchronise local & remote repos."""
logger.debug('start gh.views.push')
data = loads(request.body.decode())
slug = slugify(data['repository']['name'])
......@@ -114,18 +125,20 @@ def push(request: HttpRequest, source: SOURCES, rep: str) -> HttpResponse:
return HttpResponse(rep)
if source == SOURCES.gitlab:
namespace = get_object_or_404(Namespace,
slug_gitlab=slugify(data['project']['path_with_namespace'].split('/')[0]))
namespace = await sync_to_async(get_object_or_404)(Namespace,
slug_gitlab=slugify(
data['project']['path_with_namespace'].split('/')[0]))
else:
namespace = get_object_or_404(Namespace, slug_github=slugify(data['repository']['owner']['login']))
namespace = await sync_to_async(get_object_or_404)(Namespace,
slug_github=slugify(data['repository']['owner']['login']))
project = get_object_or_404(Project, main_namespace=namespace, slug=slug)
project = await sync_to_async(get_object_or_404)(Project, main_namespace=namespace, slug=slug)
branch = data['ref'][11:] # strip 'refs/heads/'
commit = data['after']
gl_remote_name = f'gitlab/{namespace.slug}'
gh_remote_name = f'github/{namespace.slug}'
git_repo = project.git()
git_repo = await sync_to_async(project.git)()
logger.debug(f'{namespace.slug}/{slug}: Push detected on {source.name} {branch} (commit {commit})')
if branch.startswith('pr/'): # Don't sync pr/XX branches here, they are already handled by pull_request()
......@@ -136,16 +149,18 @@ def push(request: HttpRequest, source: SOURCES, rep: str) -> HttpResponse:
# Fetch the latest commit from gitlab
if gl_remote_name in git_repo.remotes:
gl_remote = git_repo.remote(gl_remote_name)
gl_remote = await sync_to_async(git_repo.remote)(gl_remote_name)
else:
gl_remote = git_repo.create_remote(gl_remote_name, url=project.remote_url_gitlab())
url = await sync_to_async(project.remote_url_gitlab)()
gl_remote = await sync_to_async(git_repo.create_remote)(gl_remote_name, url=url)
gl_remote.fetch()