diff --git a/swh/web/ui/converters.py b/swh/web/ui/converters.py --- a/swh/web/ui/converters.py +++ b/swh/web/ui/converters.py @@ -165,6 +165,7 @@ return from_swh(revision, hashess=set(['id', 'directory', 'parents', 'children']), bytess=set(['name', + 'fullname', 'email', 'message']), dates={'date', 'committer_date'}) diff --git a/swh/web/ui/service.py b/swh/web/ui/service.py --- a/swh/web/ui/service.py +++ b/swh/web/ui/service.py @@ -216,6 +216,37 @@ 'Only sha1_git is supported.') res = backend.revision_get(sha1_git_bin) + res.pop('message', None) + return converters.from_revision(res) + + +def lookup_revision_message(rev_sha1_git): + """Return the raw message of the revision with sha1 revision_sha1_git. + + Args: + revision_sha1_git: The revision's sha1 as hexadecimal + + Returns: + Decoded revision message as dict {'message': } + + Raises: + ValueError if the identifier provided is not of sha1 nature. + NotFoundExc if the revision is not found, or if it has no message + + """ + _, sha1_git_bin = query.parse_hash_with_algorithms_or_throws( + rev_sha1_git, + ['sha1'], + 'Only sha1_git is supported.') + + revision = backend.revision_get(sha1_git_bin) + if not revision: + raise NotFoundExc('Revision with sha1_git %s not found.' + % rev_sha1_git) + if 'message' not in revision: + raise NotFoundExc('No message for revision with sha1_git %s.' + % rev_sha1_git) + res = {'message': revision['message']} return converters.from_revision(res) diff --git a/swh/web/ui/tests/test_service.py b/swh/web/ui/tests/test_service.py --- a/swh/web/ui/tests/test_service.py +++ b/swh/web/ui/tests/test_service.py @@ -929,7 +929,6 @@ 'name': 'boule & bill', 'email': 'boule@bill.org', }, - 'message': 'elegant fix for bug 31415957', 'date': "2000-01-17T11:23:54+00:00", 'committer_date': "2000-01-17T11:23:54+00:00", 'synthetic': False, @@ -943,6 +942,122 @@ @patch('swh.web.ui.service.backend') @istest + def lookup_revision_msg_ok(self, mock_backend): + # given + mock_backend.revision_get.return_value = { + 'id': hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5'), + 'directory': hex_to_hash( + '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'), + 'author': { + 'name': b'bill & boule', + 'email': b'bill@boule.org', + }, + 'committer': { + 'name': b'boule & bill', + 'email': b'boule@bill.org', + }, + 'message': b'elegant fix for bug 31415957', + 'date': { + 'timestamp': datetime.datetime( + 2000, 1, 17, 11, 23, 54, + tzinfo=datetime.timezone.utc, + ).timestamp(), + 'offset': 0, + 'negative_utc': False, + }, + 'committer_date': { + 'timestamp': datetime.datetime( + 2000, 1, 17, 11, 23, 54, + tzinfo=datetime.timezone.utc, + ).timestamp(), + 'offset': 0, + 'negative_utc': False, + }, + 'synthetic': False, + 'type': 'git', + 'parents': [], + 'metadata': [], + } + + # when + rv = service.lookup_revision_message( + '18d8be353ed3480476f032475e7c233eff7371d5') + + # then + self.assertEquals(rv, {'message': 'elegant fix for bug 31415957'}) + mock_backend.revision_get.assert_called_with( + hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5')) + + @patch('swh.web.ui.service.backend') + @istest + def lookup_revision_msg_absent(self, mock_backend): + # given + mock_backend.revision_get.return_value = { + 'id': hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5'), + 'directory': hex_to_hash( + '7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'), + 'author': { + 'name': b'bill & boule', + 'email': b'bill@boule.org', + }, + 'committer': { + 'name': b'boule & bill', + 'email': b'boule@bill.org', + }, + 'date': { + 'timestamp': datetime.datetime( + 2000, 1, 17, 11, 23, 54, + tzinfo=datetime.timezone.utc, + ).timestamp(), + 'offset': 0, + 'negative_utc': False, + }, + 'committer_date': { + 'timestamp': datetime.datetime( + 2000, 1, 17, 11, 23, 54, + tzinfo=datetime.timezone.utc, + ).timestamp(), + 'offset': 0, + 'negative_utc': False, + }, + 'synthetic': False, + 'type': 'git', + 'parents': [], + 'metadata': [], + } + + # when + with self.assertRaises(NotFoundExc) as cm: + service.lookup_revision_message( + '18d8be353ed3480476f032475e7c233eff7371d5') + + # then + mock_backend.revision_get.assert_called_with( + hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5')) + self.assertEqual(cm.exception.args[0], 'No message for revision ' + 'with sha1_git ' + '18d8be353ed3480476f032475e7c233eff7371d5.') + + @patch('swh.web.ui.service.backend') + @istest + def lookup_revision_msg_norev(self, mock_backend): + # given + mock_backend.revision_get.return_value = None + + # when + with self.assertRaises(NotFoundExc) as cm: + service.lookup_revision_message( + '18d8be353ed3480476f032475e7c233eff7371d5') + + # then + mock_backend.revision_get.assert_called_with( + hex_to_hash('18d8be353ed3480476f032475e7c233eff7371d5')) + self.assertEqual(cm.exception.args[0], 'Revision with sha1_git ' + '18d8be353ed3480476f032475e7c233eff7371d5 ' + 'not found.') + + @patch('swh.web.ui.service.backend') + @istest def lookup_revision_log(self, mock_backend): # given stub_revision_log = [{ diff --git a/swh/web/ui/tests/views/test_api.py b/swh/web/ui/tests/views/test_api.py --- a/swh/web/ui/tests/views/test_api.py +++ b/swh/web/ui/tests/views/test_api.py @@ -716,6 +716,74 @@ @patch('swh.web.ui.views.api.service') @istest + def api_revision_raw_ok(self, mock_service): + # given + stub_revision = {'message': 'synthetic revision message'} + + mock_service.lookup_revision_message.return_value = stub_revision + + # when + rv = self.app.get('/api/1/revision/' + '18d8be353ed3480476f032475e7c233eff7371d5/raw/') + + # then + self.assertEquals(rv.status_code, 200) + self.assertEquals(rv.mimetype, 'application/json') + + response_data = json.loads(rv.data.decode('utf-8')) + self.assertEquals(response_data, + {'message': 'synthetic revision message'}) + + mock_service.lookup_revision_message.assert_called_once_with( + '18d8be353ed3480476f032475e7c233eff7371d5') + + @patch('swh.web.ui.views.api.service') + @istest + def api_revision_raw_ok_no_msg(self, mock_service): + # given + mock_service.lookup_revision_message.side_effect = NotFoundExc( + 'No message for revision') + + # when + rv = self.app.get('/api/1/revision/' + '18d8be353ed3480476f032475e7c233eff7371d5/raw/') + + # then + self.assertEquals(rv.status_code, 404) + self.assertEquals(rv.mimetype, 'application/json') + + response_data = json.loads(rv.data.decode('utf-8')) + self.assertEquals(response_data, { + 'error': 'No message for revision'}) + + self.assertEquals + mock_service.lookup_revision_message.assert_called_once_with( + '18d8be353ed3480476f032475e7c233eff7371d5') + + @patch('swh.web.ui.views.api.service') + @istest + def api_revision_raw_ko_no_rev(self, mock_service): + # given + mock_service.lookup_revision_message.side_effect = NotFoundExc( + 'No revision found') + + # when + rv = self.app.get('/api/1/revision/' + '18d8be353ed3480476f032475e7c233eff7371d5/raw/') + + # then + self.assertEquals(rv.status_code, 404) + self.assertEquals(rv.mimetype, 'application/json') + + response_data = json.loads(rv.data.decode('utf-8')) + self.assertEquals(response_data, { + 'error': 'No revision found'}) + + mock_service.lookup_revision_message.assert_called_once_with( + '18d8be353ed3480476f032475e7c233eff7371d5') + + @patch('swh.web.ui.views.api.service') + @istest def api_revision_with_origin_not_found(self, mock_service): mock_service.lookup_revision_by.return_value = None diff --git a/swh/web/ui/views/api.py b/swh/web/ui/views/api.py --- a/swh/web/ui/views/api.py +++ b/swh/web/ui/views/api.py @@ -492,6 +492,30 @@ enrich_fn=utils.enrich_revision) +@app.route('/api/1/revision//raw/') +def api_revision_raw_message(sha1_git): + """Return the raw data of the revision's message + + Args: + sha1_git: the revision's hash + + Returns: + The raw revision message, possibly in an illegible + format for humans, decoded in utf-8 by default. + + Raises: + BadInputExc in case of unknown algo_hash or bad hash. + NotFoundExc if the revision is not found or the revision has no + message + + Example: + GET /api/1/revision/baf18f9fc50a0b6fef50460a76c33b2ddc57486e/raw/ + + """ + + return service.lookup_revision_message(sha1_git) + + @app.route('/api/1/revision//directory/') @app.route('/api/1/revision//directory//') def api_revision_directory(sha1_git,