Skip to content

Commit

Permalink
More error handling and comment on MR with possible reviewers
Browse files Browse the repository at this point in the history
  • Loading branch information
lkm committed Apr 25, 2020
1 parent e7d1f15 commit c594d0e
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 12 deletions.
37 changes: 29 additions & 8 deletions marge/approvals.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import yaml
import logging as log
import shlex
import fnmatch
import shlex

from . import gitlab

Expand All @@ -27,14 +26,24 @@ def refetch_info(self):
def get_approvers_ce(self):
"""get approvers status using thumbs on merge request
"""
owner_globs = self.get_codeowners_ce()
if len(owner_globs) == 0:
log.info("No CODEOWNERS file in master, continuing without approvers flow")
return dict(self._info, approvals_left=0, approved_by=[], codeowners=[])

codeowners = self.determine_responsible_owners(owner_globs, self.get_changes_ce())

if len(codeowners) == 0:
log.info("No matched code owners, continuing without approvers flow")
return dict(self._info, approvals_left=0, approved_by=[], codeowners=[])

codeowners = self.determine_responsible_owners(self.get_codeowners_ce(), self.get_changes_ce())
awards = self.get_awards_ce()

up_votes = [e for e in awards if e['name'] == 'thumbsup' and e['user']['username'] in codeowners]
approver_count = len(codeowners)
approvals_left = max(approver_count - len(up_votes), 0)
return dict(self._info, approvals_left=approvals_left, approved_by=up_votes)

return dict(self._info, approvals_left=approvals_left, approved_by=up_votes, codeowners=codeowners)

def determine_responsible_owners(self, owners_glob, changes):
owners = set([])
Expand All @@ -44,6 +53,7 @@ def determine_responsible_owners(self, owners_glob, changes):
owners.update(owners_glob['*'])

if 'changes' not in changes:
log.info("No changes in merge request!?")
return owners

for change in changes['changes']:
Expand Down Expand Up @@ -73,7 +83,7 @@ def get_codeowners_ce(self):

for line in config_file.splitlines():
if line != "" and not line.startswith(' ') and not line.startswith('#'):
elements = shlex.split(line) # line.split()
elements = shlex.split(line)
glob = elements.pop(0)
owner_globs.setdefault(glob, set([]))

Expand Down Expand Up @@ -107,18 +117,29 @@ def approver_ids(self):
"""Return the uids of the approvers."""
return [who['user']['id'] for who in self.info['approved_by']]

@property
def codeowners(self):
"""Only used for gitlab CE"""
if 'approvers' in self.info:
return self.info['codeowners']

return []

def reapprove(self):
"""Impersonates the approvers and re-approves the merge_request as them.
The idea is that we want to get the approvers, push the rebased branch
(which may invalidate approvals, depending on GitLab settings) and then
restore the approval status.
"""
if self._api.version().release >= (9, 2, 2):
gitlab_version = self._api.version()

if gitlab_version.release >= (9, 2, 2):
approve_url = '/projects/{0.project_id}/merge_requests/{0.iid}/approve'.format(self)
else:
# GitLab botched the v4 api before 9.2.3
approve_url = '/projects/{0.project_id}/merge_requests/{0.id}/approve'.format(self)

for uid in self.approver_ids:
self._api.call(POST(approve_url), sudo=uid)
if gitlab_version.is_ee:
for uid in self.approver_ids:
self._api.call(POST(approve_url), sudo=uid)
13 changes: 13 additions & 0 deletions marge/merge_request.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,19 @@ def fetch_approvals(self):
info = {'id': self.id, 'iid': self.iid, 'project_id': self.project_id}
approvals = Approvals(self.api, info)
approvals.refetch_info()

if not self._api.version().is_ee and approvals.approvals_left > 0 and len(approvals.codeowners) > 0:
reviewer_string = ''
if len(approvals.codeowners) == 1:
reviewer_string = '@' + approvals.codeowners[0]
else:
reviewer_ats = ["@" + reviewer for reviewer in approvals.codeowners]
reviewer_string = '{} or {}'.format(', '.join(reviewer_ats[:-1]), reviewer_ats[-1])

self.comment(
"I can't merge without approval. Please ask {0} to review".format(reviewer_string)
)

return approvals

def fetch_commits(self):
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
from distutils.core import setup
VERSION = open(os.path.join(os.path.dirname(__file__), 'version')).read().strip()
VERSION = open(os.path.join(os.path.dirname(__file__), 'version')).read().strip()
setup(
name='marge',
version=VERSION,
Expand Down
14 changes: 11 additions & 3 deletions tests/test_approvals.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
unmatched/* @test5
"""

# pylint: disable=anomalous-backslash-in-string
CODEOWNERS_FULL = """
# This is an example code owners file, lines starting with a `#` will
# be ignored.
Expand Down Expand Up @@ -68,7 +69,7 @@
# If the path contains spaces, these need to be escaped like this:
path\ with\ spaces/ @space-owner
"""
""" # noqa: W605

AWARDS = [
{
Expand Down Expand Up @@ -214,7 +215,12 @@ def test_fetch_from_merge_request_ce_compat(self):

api.call.assert_not_called()
assert approvals.info == {
'id': 74, 'iid': 6, 'project_id': 1234, 'approvals_left': 2, 'approved_by': [AWARDS[1]],
'id': 74,
'iid': 6,
'project_id': 1234,
'approvals_left': 2,
'approved_by': [AWARDS[1]],
'codeowners': {'default-codeowner', 'ebert', 'test-user1'},
}

def test_properties(self):
Expand Down Expand Up @@ -290,7 +296,9 @@ def test_approvals_ce_get_codeowners_wildcard(self):

approvals = Approvals(api, {'id': 74, 'iid': 6, 'project_id': 1234})

assert approvals.get_codeowners_ce() == {'*': set(['default-codeowner', 'test-user1', 'ebert']), 'unmatched/*': {'test5'}}
assert approvals.get_codeowners_ce() == {
'*': set(['default-codeowner', 'test-user1', 'ebert']), 'unmatched/*': {'test5'}
}

@patch('marge.approvals.Approvals.get_awards_ce', Mock(return_value=AWARDS))
@patch('marge.approvals.Approvals.get_changes_ce', Mock(return_value=CHANGES))
Expand Down

0 comments on commit c594d0e

Please sign in to comment.