Merge "gitlab: implement the approval reporter"
This commit is contained in:
commit
6902e8b483
|
@ -19,14 +19,17 @@
|
||||||
success:
|
success:
|
||||||
gitlab.com:
|
gitlab.com:
|
||||||
comment: true
|
comment: true
|
||||||
|
approval: true
|
||||||
sqlreporter:
|
sqlreporter:
|
||||||
failure:
|
failure:
|
||||||
gitlab.com:
|
gitlab.com:
|
||||||
comment: true
|
comment: true
|
||||||
|
approval: false
|
||||||
sqlreporter:
|
sqlreporter:
|
||||||
start:
|
start:
|
||||||
gitlab.com:
|
gitlab.com:
|
||||||
comment: true
|
comment: true
|
||||||
|
approval: false
|
||||||
sqlreporter:
|
sqlreporter:
|
||||||
|
|
||||||
- pipeline:
|
- pipeline:
|
||||||
|
|
|
@ -159,6 +159,12 @@ is taken from the pipeline.
|
||||||
Boolean value that determines if the reporter should add a
|
Boolean value that determines if the reporter should add a
|
||||||
comment to the pipeline status to the GitLab Merge Request.
|
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
|
Requirements Configuration
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
|
@ -1682,6 +1682,18 @@ class FakeGitlabAPIClient(gitlabconnection.GitlabAPIClient):
|
||||||
mr = self._get_mr(match)
|
mr = self._get_mr(match)
|
||||||
mr.addNote(params['body'])
|
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"
|
return {}, 200, "", "POST"
|
||||||
|
|
||||||
|
|
||||||
|
@ -1715,6 +1727,7 @@ class FakeGitlabMergeRequest(object):
|
||||||
self.url = "https://%s/%s/merge_requests/%s" % (
|
self.url = "https://%s/%s/merge_requests/%s" % (
|
||||||
self.gitlab.server, self.project, self.number)
|
self.gitlab.server, self.project, self.number)
|
||||||
self.is_merged = False
|
self.is_merged = False
|
||||||
|
self.approved = False
|
||||||
self.mr_ref = self._createMRRef()
|
self.mr_ref = self._createMRRef()
|
||||||
self._addCommitInMR(files=files)
|
self._addCommitInMR(files=files)
|
||||||
|
|
||||||
|
@ -1789,7 +1802,7 @@ class FakeGitlabMergeRequest(object):
|
||||||
def _updateTimeStamp(self):
|
def _updateTimeStamp(self):
|
||||||
self.updated_at = datetime.datetime.now()
|
self.updated_at = datetime.datetime.now()
|
||||||
|
|
||||||
def getMergeRequestOpenedEvent(self):
|
def getMergeRequestOpenedEvent(self, action='open'):
|
||||||
name = 'gl_merge_request'
|
name = 'gl_merge_request'
|
||||||
data = {
|
data = {
|
||||||
'object_kind': 'merge_request',
|
'object_kind': 'merge_request',
|
||||||
|
@ -1804,14 +1817,15 @@ class FakeGitlabMergeRequest(object):
|
||||||
'%Y-%m-%d %H:%M:%S UTC'),
|
'%Y-%m-%d %H:%M:%S UTC'),
|
||||||
'iid': self.number,
|
'iid': self.number,
|
||||||
'target_branch': self.branch,
|
'target_branch': self.branch,
|
||||||
'last_commit': {'id': self.sha}
|
'last_commit': {'id': self.sha},
|
||||||
|
'action': action
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return (name, data)
|
return (name, data)
|
||||||
|
|
||||||
def getMergeRequestUpdatedEvent(self):
|
def getMergeRequestUpdatedEvent(self):
|
||||||
self.addCommit()
|
self.addCommit()
|
||||||
return self.getMergeRequestOpenedEvent()
|
return self.getMergeRequestOpenedEvent(action='update')
|
||||||
|
|
||||||
def getMergeRequestCommentedEvent(self, note):
|
def getMergeRequestCommentedEvent(self, note):
|
||||||
self.addNote(note)
|
self.addNote(note)
|
||||||
|
|
|
@ -16,9 +16,11 @@
|
||||||
success:
|
success:
|
||||||
gitlab:
|
gitlab:
|
||||||
comment: True
|
comment: True
|
||||||
|
approval: True
|
||||||
failure:
|
failure:
|
||||||
gitlab:
|
gitlab:
|
||||||
comment: True
|
comment: True
|
||||||
|
approval: False
|
||||||
|
|
||||||
- pipeline:
|
- pipeline:
|
||||||
name: post
|
name: post
|
||||||
|
|
|
@ -114,6 +114,7 @@ class TestGitlabDriver(ZuulTestCase):
|
||||||
self.assertThat(
|
self.assertThat(
|
||||||
A.notes[1]['body'],
|
A.notes[1]['body'],
|
||||||
MatchesRegex(r'.*project-test2.*SUCCESS.*', re.DOTALL))
|
MatchesRegex(r'.*project-test2.*SUCCESS.*', re.DOTALL))
|
||||||
|
self.assertTrue(A.approved)
|
||||||
|
|
||||||
@simple_layout('layouts/basic-gitlab.yaml', driver='gitlab')
|
@simple_layout('layouts/basic-gitlab.yaml', driver='gitlab')
|
||||||
def test_merge_request_updated(self):
|
def test_merge_request_updated(self):
|
||||||
|
|
|
@ -128,10 +128,13 @@ class GitlabEventConnector(threading.Thread):
|
||||||
event.patch_number = attrs['last_commit']['id']
|
event.patch_number = attrs['last_commit']['id']
|
||||||
event.change_url = self.connection.getPullUrl(event.project_name,
|
event.change_url = self.connection.getPullUrl(event.project_name,
|
||||||
event.change_number)
|
event.change_number)
|
||||||
if event.created_at == event.updated_at:
|
if attrs['action'] == 'open':
|
||||||
event.action = 'opened'
|
event.action = 'opened'
|
||||||
else:
|
elif attrs['action'] == 'update':
|
||||||
event.action = 'changed'
|
event.action = 'changed'
|
||||||
|
else:
|
||||||
|
# Do not handle other merge_request action for now.
|
||||||
|
return None
|
||||||
event.type = 'gl_merge_request'
|
event.type = 'gl_merge_request'
|
||||||
return event
|
return event
|
||||||
|
|
||||||
|
@ -294,6 +297,26 @@ class GitlabAPIClient():
|
||||||
self._manage_error(*resp, zuul_event_id=zuul_event_id)
|
self._manage_error(*resp, zuul_event_id=zuul_event_id)
|
||||||
return resp[0]
|
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):
|
class GitlabConnection(BaseConnection):
|
||||||
driver_name = 'gitlab'
|
driver_name = 'gitlab'
|
||||||
|
@ -490,6 +513,13 @@ class GitlabConnection(BaseConnection):
|
||||||
project_name, number, message, zuul_event_id=event)
|
project_name, number, message, zuul_event_id=event)
|
||||||
log.info("Commented on MR %s#%s", project_name, number)
|
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):
|
class GitlabWebController(BaseWebController):
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ class GitlabReporter(BaseReporter):
|
||||||
def __init__(self, driver, connection, pipeline, config=None):
|
def __init__(self, driver, connection, pipeline, config=None):
|
||||||
super(GitlabReporter, self).__init__(driver, connection, config)
|
super(GitlabReporter, self).__init__(driver, connection, config)
|
||||||
self._create_comment = self.config.get('comment', True)
|
self._create_comment = self.config.get('comment', True)
|
||||||
|
self._approval = self.config.get('approval', None)
|
||||||
|
|
||||||
def report(self, item):
|
def report(self, item):
|
||||||
"""Report on an event."""
|
"""Report on an event."""
|
||||||
|
@ -42,15 +43,26 @@ class GitlabReporter(BaseReporter):
|
||||||
if hasattr(item.change, 'number'):
|
if hasattr(item.change, 'number'):
|
||||||
if self._create_comment:
|
if self._create_comment:
|
||||||
self.addMRComment(item)
|
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)
|
log = get_annotated_logger(self.log, item.event)
|
||||||
message = comment or self._formatItemReport(item)
|
message = self._formatItemReport(item)
|
||||||
project = item.change.project.name
|
project = item.change.project.name
|
||||||
pr_number = item.change.number
|
mr_number = item.change.number
|
||||||
log.debug('Reporting change %s, params %s, message: %s',
|
log.debug('Reporting change %s, params %s, message: %s',
|
||||||
item.change, self.config, message)
|
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)
|
event=item.event)
|
||||||
|
|
||||||
def mergePull(self, item):
|
def mergePull(self, item):
|
||||||
|
@ -63,5 +75,6 @@ class GitlabReporter(BaseReporter):
|
||||||
def getSchema():
|
def getSchema():
|
||||||
gitlab_reporter = v.Schema({
|
gitlab_reporter = v.Schema({
|
||||||
'comment': bool,
|
'comment': bool,
|
||||||
|
'approval': bool,
|
||||||
})
|
})
|
||||||
return gitlab_reporter
|
return gitlab_reporter
|
||||||
|
|
Loading…
Reference in New Issue