gitlab: implement the approval reporter
Change-Id: Iac34f7883d1eda5179b707b3620d17b085bf135c
This commit is contained in:
parent
7fae9a5926
commit
b1494db03e
|
@ -19,14 +19,17 @@
|
|||
success:
|
||||
gitlab.com:
|
||||
comment: true
|
||||
approval: true
|
||||
sqlreporter:
|
||||
failure:
|
||||
gitlab.com:
|
||||
comment: true
|
||||
approval: false
|
||||
sqlreporter:
|
||||
start:
|
||||
gitlab.com:
|
||||
comment: true
|
||||
approval: false
|
||||
sqlreporter:
|
||||
|
||||
- pipeline:
|
||||
|
|
|
@ -159,6 +159,12 @@ is taken from the pipeline.
|
|||
Boolean value that determines if the reporter should add a
|
||||
comment to the pipeline status to the GitLab Merge Request.
|
||||
|
||||
.. attr:: approval
|
||||
|
||||
Bolean value that determines whether to report *approve* or *unapprove*
|
||||
into the merge request approval system. To set an approval the Zuul user
|
||||
must be a *Developer* or *Maintainer* project's member. If not set approval
|
||||
won't be reported.
|
||||
|
||||
Requirements Configuration
|
||||
--------------------------
|
||||
|
|
|
@ -1682,6 +1682,18 @@ class FakeGitlabAPIClient(gitlabconnection.GitlabAPIClient):
|
|||
mr = self._get_mr(match)
|
||||
mr.addNote(params['body'])
|
||||
|
||||
match = re.match(
|
||||
r'.+/projects/(.+)/merge_requests/(\d+)/approve$', url)
|
||||
if match:
|
||||
mr = self._get_mr(match)
|
||||
mr.approved = True
|
||||
|
||||
match = re.match(
|
||||
r'.+/projects/(.+)/merge_requests/(\d+)/unapprove$', url)
|
||||
if match:
|
||||
mr = self._get_mr(match)
|
||||
mr.approved = False
|
||||
|
||||
return {}, 200, "", "POST"
|
||||
|
||||
|
||||
|
@ -1715,6 +1727,7 @@ class FakeGitlabMergeRequest(object):
|
|||
self.url = "https://%s/%s/merge_requests/%s" % (
|
||||
self.gitlab.server, self.project, self.number)
|
||||
self.is_merged = False
|
||||
self.approved = False
|
||||
self.mr_ref = self._createMRRef()
|
||||
self._addCommitInMR(files=files)
|
||||
|
||||
|
@ -1789,7 +1802,7 @@ class FakeGitlabMergeRequest(object):
|
|||
def _updateTimeStamp(self):
|
||||
self.updated_at = datetime.datetime.now()
|
||||
|
||||
def getMergeRequestOpenedEvent(self):
|
||||
def getMergeRequestOpenedEvent(self, action='open'):
|
||||
name = 'gl_merge_request'
|
||||
data = {
|
||||
'object_kind': 'merge_request',
|
||||
|
@ -1804,14 +1817,15 @@ class FakeGitlabMergeRequest(object):
|
|||
'%Y-%m-%d %H:%M:%S UTC'),
|
||||
'iid': self.number,
|
||||
'target_branch': self.branch,
|
||||
'last_commit': {'id': self.sha}
|
||||
'last_commit': {'id': self.sha},
|
||||
'action': action
|
||||
},
|
||||
}
|
||||
return (name, data)
|
||||
|
||||
def getMergeRequestUpdatedEvent(self):
|
||||
self.addCommit()
|
||||
return self.getMergeRequestOpenedEvent()
|
||||
return self.getMergeRequestOpenedEvent(action='update')
|
||||
|
||||
def getMergeRequestCommentedEvent(self, note):
|
||||
self.addNote(note)
|
||||
|
|
|
@ -16,9 +16,11 @@
|
|||
success:
|
||||
gitlab:
|
||||
comment: True
|
||||
approval: True
|
||||
failure:
|
||||
gitlab:
|
||||
comment: True
|
||||
approval: False
|
||||
|
||||
- pipeline:
|
||||
name: post
|
||||
|
|
|
@ -114,6 +114,7 @@ class TestGitlabDriver(ZuulTestCase):
|
|||
self.assertThat(
|
||||
A.notes[1]['body'],
|
||||
MatchesRegex(r'.*project-test2.*SUCCESS.*', re.DOTALL))
|
||||
self.assertTrue(A.approved)
|
||||
|
||||
@simple_layout('layouts/basic-gitlab.yaml', driver='gitlab')
|
||||
def test_merge_request_updated(self):
|
||||
|
|
|
@ -128,10 +128,13 @@ class GitlabEventConnector(threading.Thread):
|
|||
event.patch_number = attrs['last_commit']['id']
|
||||
event.change_url = self.connection.getPullUrl(event.project_name,
|
||||
event.change_number)
|
||||
if event.created_at == event.updated_at:
|
||||
if attrs['action'] == 'open':
|
||||
event.action = 'opened'
|
||||
else:
|
||||
elif attrs['action'] == 'update':
|
||||
event.action = 'changed'
|
||||
else:
|
||||
# Do not handle other merge_request action for now.
|
||||
return None
|
||||
event.type = 'gl_merge_request'
|
||||
return event
|
||||
|
||||
|
@ -294,6 +297,26 @@ class GitlabAPIClient():
|
|||
self._manage_error(*resp, zuul_event_id=zuul_event_id)
|
||||
return resp[0]
|
||||
|
||||
# https://docs.gitlab.com/ee/api/merge_request_approvals.html#approve-merge-request
|
||||
def approve_mr(self, project_name, number, approve=True,
|
||||
zuul_event_id=None):
|
||||
approve = 'approve' if approve else 'unapprove'
|
||||
path = "/projects/%s/merge_requests/%s/%s" % (
|
||||
quote_plus(project_name), number, approve)
|
||||
params = {}
|
||||
resp = self.post(
|
||||
self.baseurl + path, params=params,
|
||||
zuul_event_id=zuul_event_id)
|
||||
try:
|
||||
self._manage_error(*resp, zuul_event_id=zuul_event_id)
|
||||
except GitlabAPIClientException:
|
||||
# approve and unapprove endpoint could return code 401 whether the
|
||||
# actual state of the Merge Request approval. Two call on approve
|
||||
# endpoint the second call return 401.
|
||||
if resp[1] != 401:
|
||||
raise
|
||||
return resp[0]
|
||||
|
||||
|
||||
class GitlabConnection(BaseConnection):
|
||||
driver_name = 'gitlab'
|
||||
|
@ -490,6 +513,13 @@ class GitlabConnection(BaseConnection):
|
|||
project_name, number, message, zuul_event_id=event)
|
||||
log.info("Commented on MR %s#%s", project_name, number)
|
||||
|
||||
def approveMR(self, project_name, number, approve, event=None):
|
||||
log = get_annotated_logger(self.log, event)
|
||||
self.gl_client.approve_mr(
|
||||
project_name, number, approve, zuul_event_id=event)
|
||||
log.info(
|
||||
"Set approval: %s on MR %s#%s", approve, project_name, number)
|
||||
|
||||
|
||||
class GitlabWebController(BaseWebController):
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ class GitlabReporter(BaseReporter):
|
|||
def __init__(self, driver, connection, pipeline, config=None):
|
||||
super(GitlabReporter, self).__init__(driver, connection, config)
|
||||
self._create_comment = self.config.get('comment', True)
|
||||
self._approval = self.config.get('approval', None)
|
||||
|
||||
def report(self, item):
|
||||
"""Report on an event."""
|
||||
|
@ -42,15 +43,26 @@ class GitlabReporter(BaseReporter):
|
|||
if hasattr(item.change, 'number'):
|
||||
if self._create_comment:
|
||||
self.addMRComment(item)
|
||||
if self._approval is not None:
|
||||
self.setApproval(item)
|
||||
|
||||
def addMRComment(self, item, comment=None):
|
||||
def addMRComment(self, item):
|
||||
log = get_annotated_logger(self.log, item.event)
|
||||
message = comment or self._formatItemReport(item)
|
||||
message = self._formatItemReport(item)
|
||||
project = item.change.project.name
|
||||
pr_number = item.change.number
|
||||
mr_number = item.change.number
|
||||
log.debug('Reporting change %s, params %s, message: %s',
|
||||
item.change, self.config, message)
|
||||
self.connection.commentMR(project, pr_number, message,
|
||||
self.connection.commentMR(project, mr_number, message,
|
||||
event=item.event)
|
||||
|
||||
def setApproval(self, item):
|
||||
log = get_annotated_logger(self.log, item.event)
|
||||
project = item.change.project.name
|
||||
mr_number = item.change.number
|
||||
log.debug('Reporting change %s, params %s, approval: %s',
|
||||
item.change, self.config, self._approval)
|
||||
self.connection.approveMR(project, mr_number, self._approval,
|
||||
event=item.event)
|
||||
|
||||
def mergePull(self, item):
|
||||
|
@ -63,5 +75,6 @@ class GitlabReporter(BaseReporter):
|
|||
def getSchema():
|
||||
gitlab_reporter = v.Schema({
|
||||
'comment': bool,
|
||||
'approval': bool,
|
||||
})
|
||||
return gitlab_reporter
|
||||
|
|
Loading…
Reference in New Issue