diff options
author | Fabien Boucher <fboucher@redhat.com> | 2019-11-14 17:26:57 +0100 |
---|---|---|
committer | Tristan Cacqueray <tdecacqu@redhat.com> | 2020-02-12 22:33:03 +0000 |
commit | e20d254e6ded9484f4c7a27cd96711e1c962e7d9 (patch) | |
tree | bec04e570e95a0bdfb054b2b1612b9b66beddc14 | |
parent | f1368e84ece201c653b28406ac35d2584455c83f (diff) | |
download | zuul-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.py | 22 | ||||
-rw-r--r-- | tests/fixtures/layouts/basic-gitlab.yaml | 14 | ||||
-rw-r--r-- | tests/unit/test_gitlab_driver.py | 42 | ||||
-rw-r--r-- | zuul/driver/gitlab/gitlabconnection.py | 28 | ||||
-rw-r--r-- | zuul/driver/gitlab/gitlabreporter.py | 29 |
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 |