summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabien Boucher <fboucher@redhat.com>2019-11-14 17:26:57 +0100
committerTristan Cacqueray <tdecacqu@redhat.com>2020-02-12 22:33:03 +0000
commite20d254e6ded9484f4c7a27cd96711e1c962e7d9 (patch)
treebec04e570e95a0bdfb054b2b1612b9b66beddc14
parentf1368e84ece201c653b28406ac35d2584455c83f (diff)
downloadzuul-e20d254e6ded9484f4c7a27cd96711e1c962e7d9.tar.gz
Gitlab - Minimal reporter ables to comment on MR
For history: https://gitlab.com/fabien.dot.boucher/demo-zuul/merge_requests/7#note_244782493 Change-Id: I2b7486c00dad24752d7073f301ce8d3384c0646c
-rw-r--r--tests/base.py22
-rw-r--r--tests/fixtures/layouts/basic-gitlab.yaml14
-rw-r--r--tests/unit/test_gitlab_driver.py42
-rw-r--r--zuul/driver/gitlab/gitlabconnection.py28
-rw-r--r--zuul/driver/gitlab/gitlabreporter.py29
5 files changed, 132 insertions, 3 deletions
diff --git a/tests/base.py b/tests/base.py
index f2c50aa03..f03cbbd5d 100644
--- a/tests/base.py
+++ b/tests/base.py
@@ -1584,6 +1584,18 @@ class FakeGitlabAPIClient(gitlabconnection.GitlabAPIClient):
if match:
return [{'name': 'master'}], 200, "", "GET"
+ def post(self, url, params=None, zuul_event_id=None):
+
+ self.log.info(
+ "Posting on resource %s, params (%s) ..." % (url, params))
+
+ match = re.match(r'.+/projects/(.+)/merge_requests/(\d+)/notes$', url)
+ if match:
+ mr = self._get_mr(match)
+ mr.addNote(params['body'])
+
+ return {}, 200, "", "POST"
+
class GitlabChangeReference(git.Reference):
_common_path_default = "refs/merge-requests"
@@ -1612,6 +1624,7 @@ class FakeGitlabMergeRequest(object):
self.merge_status = 'can_be_merged'
self.uuid = uuid.uuid4().hex
self.labels = []
+ self.notes = []
self.upstream_root = upstream_root
self.url = "https://%s/%s/merge_requests/%s" % (
self.gitlab.server, urllib.parse.quote_plus(
@@ -1632,6 +1645,15 @@ class FakeGitlabMergeRequest(object):
def getMRReference(self):
return '%s/head' % self.number
+ def addNote(self, body):
+ self.notes.append(
+ {
+ "body": body,
+ "created_at": datetime.datetime.now().strftime(
+ '%Y-%m-%dT%H:%M:%S.%fZ'),
+ }
+ )
+
def _addCommitInMR(self, files=[], reset=False):
repo = self._getRepo()
ref = repo.references[self.getMRReference()]
diff --git a/tests/fixtures/layouts/basic-gitlab.yaml b/tests/fixtures/layouts/basic-gitlab.yaml
index 2140778d7..96731e8fd 100644
--- a/tests/fixtures/layouts/basic-gitlab.yaml
+++ b/tests/fixtures/layouts/basic-gitlab.yaml
@@ -6,6 +6,15 @@
- event: gl_merge_request
action:
- opened
+ start:
+ gitlab:
+ comment: True
+ success:
+ gitlab:
+ comment: True
+ failure:
+ gitlab:
+ comment: True
- job:
name: base
@@ -16,8 +25,13 @@
name: project-test1
run: playbooks/project-test1.yaml
+- job:
+ name: project-test2
+ run: playbooks/project-test2.yaml
+
- project:
name: org/project
check:
jobs:
- project-test1
+ - project-test2
diff --git a/tests/unit/test_gitlab_driver.py b/tests/unit/test_gitlab_driver.py
index 96cfacde4..d3d978cee 100644
--- a/tests/unit/test_gitlab_driver.py
+++ b/tests/unit/test_gitlab_driver.py
@@ -12,11 +12,14 @@
# License for the specific language governing permissions and limitations
# under the License.
+import re
import socket
from tests.base import ZuulTestCase, simple_layout
from tests.base import ZuulWebFixture
+from testtools.matchers import MatchesRegex
+
class TestGitlabWebhook(ZuulTestCase):
config_file = 'zuul-gitlab-driver.conf'
@@ -67,3 +70,42 @@ class TestGitlabWebhook(ZuulTestCase):
self.assertEqual('SUCCESS',
self.getJobFromHistory('project-test1').result)
+
+
+class TestGitlabDriver(ZuulTestCase):
+ config_file = 'zuul-gitlab-driver.conf'
+
+ @simple_layout('layouts/basic-gitlab.yaml', driver='gitlab')
+ def test_pull_request_opened(self):
+
+ description = "This is the\nMR description."
+ A = self.fake_gitlab.openFakeMergeRequest(
+ 'org/project', 'master', 'A', description=description)
+ self.fake_gitlab.emitEvent(
+ A.getMergeRequestEvent(), project='org/project')
+ self.waitUntilSettled()
+
+ self.assertEqual('SUCCESS',
+ self.getJobFromHistory('project-test1').result)
+
+ self.assertEqual('SUCCESS',
+ self.getJobFromHistory('project-test2').result)
+
+ job = self.getJobFromHistory('project-test2')
+ zuulvars = job.parameters['zuul']
+ self.assertEqual(str(A.number), zuulvars['change'])
+ self.assertEqual(str(A.patch_number), zuulvars['patchset'])
+ self.assertEqual('master', zuulvars['branch'])
+ self.assertEquals('https://gitlab/org/project/merge_requests/1',
+ zuulvars['items'][0]['change_url'])
+ self.assertEqual(zuulvars["message"], description)
+ self.assertEqual(2, len(self.history))
+ self.assertEqual(2, len(A.notes))
+ self.assertEqual(
+ A.notes[0]['body'], "Starting check jobs.")
+ self.assertThat(
+ A.notes[1]['body'],
+ MatchesRegex(r'.*project-test1.*SUCCESS.*', re.DOTALL))
+ self.assertThat(
+ A.notes[1]['body'],
+ MatchesRegex(r'.*project-test2.*SUCCESS.*', re.DOTALL))
diff --git a/zuul/driver/gitlab/gitlabconnection.py b/zuul/driver/gitlab/gitlabconnection.py
index 363825d64..ef2e216ba 100644
--- a/zuul/driver/gitlab/gitlabconnection.py
+++ b/zuul/driver/gitlab/gitlabconnection.py
@@ -184,7 +184,7 @@ class GitlabAPIClient():
self.session = requests.Session()
self.baseurl = '%s/api/v4/' % baseurl
self.api_token = api_token
- self.headers = {'Authorization': 'Authorization: Bearer %s' % (
+ self.headers = {'Authorization': 'Bearer %s' % (
self.api_token)}
def _manage_error(self, data, code, url, verb, zuul_event_id=None):
@@ -204,6 +204,15 @@ class GitlabAPIClient():
ret.status_code, ret.text))
return ret.json(), ret.status_code, ret.url, 'GET'
+ def post(self, url, params=None, zuul_event_id=None):
+ log = get_annotated_logger(self.log, zuul_event_id)
+ log.info(
+ "Posting on resource %s, params (%s) ..." % (url, params))
+ ret = self.session.post(url, data=params, headers=self.headers)
+ log.debug("POST returned (code: %s): %s" % (
+ ret.status_code, ret.text))
+ return ret.json(), ret.status_code, ret.url, 'POST'
+
# https://docs.gitlab.com/ee/api/merge_requests.html#get-single-mr
def get_mr(self, project_name, number, zuul_event_id=None):
path = "/projects/%s/merge_requests/%s" % (
@@ -220,6 +229,17 @@ class GitlabAPIClient():
self._manage_error(*resp, zuul_event_id=zuul_event_id)
return [branch['name'] for branch in resp[0]]
+ # https://docs.gitlab.com/ee/api/notes.html#create-new-merge-request-note
+ def comment_mr(self, project_name, number, msg, zuul_event_id=None):
+ path = "/projects/%s/merge_requests/%s/notes" % (
+ quote_plus(project_name), number)
+ params = {'body': msg}
+ resp = self.post(
+ self.baseurl + path, params=params,
+ zuul_event_id=zuul_event_id)
+ self._manage_error(*resp, zuul_event_id=zuul_event_id)
+ return resp[0]
+
class GitlabConnection(BaseConnection):
driver_name = 'gitlab'
@@ -393,6 +413,12 @@ class GitlabConnection(BaseConnection):
log.info('Got MR %s#%s', project_name, number)
return mr
+ def commentMR(self, project_name, number, message, event=None):
+ log = get_annotated_logger(self.log, event)
+ self.gl_client.comment_mr(
+ project_name, number, message, zuul_event_id=event)
+ log.info("Commented on MR %s#%s", project_name, number)
+
class GitlabWebController(BaseWebController):
diff --git a/zuul/driver/gitlab/gitlabreporter.py b/zuul/driver/gitlab/gitlabreporter.py
index 753239349..ab14887a8 100644
--- a/zuul/driver/gitlab/gitlabreporter.py
+++ b/zuul/driver/gitlab/gitlabreporter.py
@@ -16,6 +16,8 @@ import logging
import voluptuous as v
from zuul.reporter import BaseReporter
+from zuul.lib.logutil import get_annotated_logger
+from zuul.driver.gitlab.gitlabsource import GitlabSource
class GitlabReporter(BaseReporter):
@@ -26,10 +28,30 @@ 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)
def report(self, item):
"""Report on an event."""
- raise NotImplementedError()
+ if not isinstance(item.change.project.source, GitlabSource):
+ return
+
+ if item.change.project.source.connection.canonical_hostname != \
+ self.connection.canonical_hostname:
+ return
+
+ if hasattr(item.change, 'number'):
+ if self._create_comment:
+ self.addMRComment(item)
+
+ def addMRComment(self, item, comment=None):
+ log = get_annotated_logger(self.log, item.event)
+ message = comment or self._formatItemReport(item)
+ project = item.change.project.name
+ pr_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,
+ event=item.event)
def mergePull(self, item):
raise NotImplementedError()
@@ -39,4 +61,7 @@ class GitlabReporter(BaseReporter):
def getSchema():
- return v.Schema({})
+ gitlab_reporter = v.Schema({
+ 'comment': bool,
+ })
+ return gitlab_reporter