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
@@ -253,9 +253,9 @@
'Only sha1_git is supported.')
return sha1_git_bin
- sha1_bin_list = map(to_sha1_bin, sha1_git_list)
+ sha1_bin_list = (to_sha1_bin(x) for x in sha1_git_list)
revisions = backend.revision_get_multiple(sha1_bin_list)
- return map(converters.from_revision, revisions)
+ return (converters.from_revision(x) for x in revisions)
def lookup_revision_message(rev_sha1_git):
diff --git a/swh/web/ui/templates/revision-log.html b/swh/web/ui/templates/revision-log.html
--- a/swh/web/ui/templates/revision-log.html
+++ b/swh/web/ui/templates/revision-log.html
@@ -39,6 +39,13 @@
{% endif %}
+ {% if revision['history_context_url'] is not none %}
+
directory
diff --git a/swh/web/ui/tests/test_utils.py b/swh/web/ui/tests/test_utils.py
--- a/swh/web/ui/tests/test_utils.py
+++ b/swh/web/ui/tests/test_utils.py
@@ -476,6 +476,19 @@
call('api_entity_by_uuid',
uuid='uuid-parent')])
+ @nottest
+ def _url_for_context_test(self, fn, **data):
+ if fn == 'api_revision':
+ if 'context' in data and data['context'] is not None:
+ return '/api/revision/%s/prev/%s/' % (data['sha1_git'], data['context']) # noqa
+ else:
+ return '/api/revision/%s/' % data['sha1_git']
+ elif fn == 'api_revision_log':
+ if 'prev_sha1s' in data:
+ return '/api/revision/%s/prev/%s/log/' % (data['sha1_git'], data['prev_sha1s']) # noqa
+ else:
+ return '/api/revision/%s/log/' % data['sha1_git']
+
@patch('swh.web.ui.utils.flask')
@istest
def enrich_revision_without_children_or_parent(self, mock_flask):
@@ -500,8 +513,7 @@
'committer': {'id': '2'},
})
- # then
- self.assertEqual(actual_revision, {
+ expected_revision = {
'id': 'rev-id',
'directory': '123',
'url': '/api/revision/rev-id/',
@@ -511,70 +523,205 @@
'author_url': '/api/person/1/',
'committer': {'id': '2'},
'committer_url': '/api/person/2/'
- })
+ }
+
+ # then
+ self.assertEqual(actual_revision, expected_revision)
- mock_flask.url_for.assert_has_calls([call('api_revision',
- sha1_git='rev-id'),
- call('api_revision_log',
- sha1_git='rev-id'),
- call('api_person',
- person_id='1'),
- call('api_person',
- person_id='2'),
- call('api_directory',
- sha1_git='123')])
+ mock_flask.url_for.assert_has_calls(
+ [call('api_revision',
+ sha1_git='rev-id'),
+ call('api_revision_log',
+ sha1_git='rev-id'),
+ call('api_person',
+ person_id='1'),
+ call('api_person',
+ person_id='2'),
+ call('api_directory',
+ sha1_git='123')])
@patch('swh.web.ui.utils.flask')
@istest
def enrich_revision_with_children_and_parent_no_dir(self,
mock_flask):
# given
- def url_for_test(fn, **data):
- if fn == 'api_revision':
- return '/api/revision/' + data['sha1_git'] + '/'
- elif fn == 'api_revision_log':
- return '/api/revision/' + data['sha1_git'] + '/log/'
- else:
- return '/api/revision/' + data['sha1_git_root'] + '/history/' + data['sha1_git'] + '/' # noqa
+ mock_flask.url_for.side_effect = self._url_for_context_test
- mock_flask.url_for.side_effect = url_for_test
+ # when
+ actual_revision = utils.enrich_revision({
+ 'id': 'rev-id',
+ 'parents': ['123'],
+ 'children': ['456'],
+ }, context='prev-rev')
+
+ expected_revision = {
+ 'id': 'rev-id',
+ 'url': '/api/revision/rev-id/',
+ 'history_url': '/api/revision/rev-id/log/',
+ 'history_context_url': '/api/revision/rev-id/prev/prev-rev/log/',
+ 'parents': ['123'],
+ 'parent_urls': ['/api/revision/123/prev/prev-rev/rev-id/'],
+ 'children': ['456'],
+ 'children_urls': ['/api/revision/456/',
+ '/api/revision/prev-rev/'],
+ }
+
+ # then
+ self.assertEqual(actual_revision, expected_revision)
+
+ mock_flask.url_for.assert_has_calls(
+ [call('api_revision',
+ sha1_git='prev-rev'),
+ call('api_revision',
+ sha1_git='rev-id'),
+ call('api_revision_log',
+ sha1_git='rev-id'),
+ call('api_revision_log',
+ sha1_git='rev-id',
+ prev_sha1s='prev-rev'),
+ call('api_revision',
+ sha1_git='123',
+ context='prev-rev/rev-id'),
+ call('api_revision',
+ sha1_git='456')])
+
+ @patch('swh.web.ui.utils.flask')
+ @istest
+ def enrich_revision_no_context(self, mock_flask):
+ # given
+ mock_flask.url_for.side_effect = self._url_for_context_test
# when
actual_revision = utils.enrich_revision({
'id': 'rev-id',
'parents': ['123'],
'children': ['456'],
- }, context='sha1_git_root')
+ })
+
+ expected_revision = {
+ 'id': 'rev-id',
+ 'url': '/api/revision/rev-id/',
+ 'history_url': '/api/revision/rev-id/log/',
+ 'parents': ['123'],
+ 'parent_urls': ['/api/revision/123/prev/rev-id/'],
+ 'children': ['456'],
+ 'children_urls': ['/api/revision/456/']
+ }
+
+ # then
+ self.assertEqual(actual_revision, expected_revision)
+
+ mock_flask.url_for.assert_has_calls(
+ [call('api_revision',
+ sha1_git='rev-id'),
+ call('api_revision_log',
+ sha1_git='rev-id'),
+ call('api_revision',
+ sha1_git='123',
+ context='rev-id'),
+ call('api_revision',
+ sha1_git='456')])
+
+ @patch('swh.web.ui.utils.flask')
+ @istest
+ def enrich_revision_context_empty_prev_list(self, mock_flask):
+ # given
+ mock_flask.url_for.side_effect = self._url_for_context_test
+
+ # when
+ expected_revision = {
+ 'id': 'rev-id',
+ 'url': '/api/revision/rev-id/',
+ 'history_url': '/api/revision/rev-id/log/',
+ 'history_context_url': ('/api/revision/rev-id/'
+ 'prev/prev-rev/log/'),
+ 'parents': ['123'],
+ 'parent_urls': ['/api/revision/123/prev/prev-rev/rev-id/'],
+ 'children': ['456'],
+ 'children_urls': ['/api/revision/456/', '/api/revision/prev-rev/'],
+ }
+
+ actual_revision = utils.enrich_revision({
+ 'id': 'rev-id',
+ 'url': '/api/revision/rev-id/',
+ 'parents': ['123'],
+ 'children': ['456']}, context='prev-rev')
# then
- self.assertEqual(actual_revision, {
+ self.assertEqual(actual_revision, expected_revision)
+ mock_flask.url_for.assert_has_calls(
+ [call('api_revision',
+ sha1_git='prev-rev'),
+ call('api_revision',
+ sha1_git='rev-id'),
+ call('api_revision_log',
+ sha1_git='rev-id'),
+ call('api_revision_log',
+ sha1_git='rev-id',
+ prev_sha1s='prev-rev'),
+ call('api_revision',
+ sha1_git='123',
+ context='prev-rev/rev-id'),
+ call('api_revision',
+ sha1_git='456')])
+
+ @patch('swh.web.ui.utils.flask')
+ @istest
+ def enrich_revision_context_some_prev_list(self, mock_flask):
+ # given
+ mock_flask.url_for.side_effect = self._url_for_context_test
+
+ # when
+ expected_revision = {
'id': 'rev-id',
'url': '/api/revision/rev-id/',
'history_url': '/api/revision/rev-id/log/',
+ 'history_context_url': ('/api/revision/rev-id/'
+ 'prev/prev1-rev/prev0-rev/log/'),
'parents': ['123'],
- 'parent_urls': ['/api/revision/sha1_git_root/history/123/'],
+ 'parent_urls': ['/api/revision/123/prev/'
+ 'prev1-rev/prev0-rev/rev-id/'],
'children': ['456'],
- 'children_urls': ['/api/revision/sha1_git_root/history/456/'],
- })
+ 'children_urls': ['/api/revision/456/',
+ '/api/revision/prev0-rev/prev/prev1-rev/'],
+ }
+
+ actual_revision = utils.enrich_revision({
+ 'id': 'rev-id',
+ 'parents': ['123'],
+ 'children': ['456']}, context='prev1-rev/prev0-rev')
+ # then
+ self.assertEqual(actual_revision, expected_revision)
mock_flask.url_for.assert_has_calls(
[call('api_revision',
+ sha1_git='prev0-rev',
+ context='prev1-rev'),
+ call('api_revision',
sha1_git='rev-id'),
call('api_revision_log',
sha1_git='rev-id'),
- call('api_revision_history',
- sha1_git_root='sha1_git_root',
- sha1_git='123'),
- call('api_revision_history',
- sha1_git_root='sha1_git_root',
+ call('api_revision_log',
+ sha1_git='rev-id',
+ prev_sha1s='prev1-rev/prev0-rev'),
+ call('api_revision',
+ sha1_git='123',
+ context='prev1-rev/prev0-rev/rev-id'),
+ call('api_revision',
sha1_git='456')])
@nottest
def _url_for_rev_message_test(self, fn, **data):
if fn == 'api_revision':
- return '/api/revision/' + data['sha1_git'] + '/'
+ if 'context' in data and data['context'] is not None:
+ return '/api/revision/%s/prev/%s/' % (data['sha1_git'], data['context']) # noqa
+ else:
+ return '/api/revision/%s/' % data['sha1_git']
elif fn == 'api_revision_log':
- return '/api/revision/' + data['sha1_git'] + '/log/'
+ if 'prev_sha1s' in data and data['prev_sha1s'] is not None:
+ return '/api/revision/%s/prev/%s/log/' % (data['sha1_git'], data['prev_sha1s']) # noqa
+ else:
+ return '/api/revision/%s/log/' % data['sha1_git']
elif fn == 'api_revision_raw_message':
return '/api/revision/' + data['sha1_git'] + '/raw/'
else:
@@ -587,35 +734,43 @@
mock_flask.url_for.side_effect = self._url_for_rev_message_test
# when
- actual_revision = utils.enrich_revision({
+ expected_revision = {
'id': 'rev-id',
+ 'url': '/api/revision/rev-id/',
+ 'history_url': '/api/revision/rev-id/log/',
+ 'history_context_url': ('/api/revision/rev-id/'
+ 'prev/prev-rev/log/'),
'message': None,
'parents': ['123'],
+ 'parent_urls': ['/api/revision/123/prev/prev-rev/rev-id/'],
'children': ['456'],
- }, context='sha1_git_root')
+ 'children_urls': ['/api/revision/456/', '/api/revision/prev-rev/'],
+ }
- # then
- self.assertEqual(actual_revision, {
+ actual_revision = utils.enrich_revision({
'id': 'rev-id',
- 'url': '/api/revision/rev-id/',
'message': None,
- 'history_url': '/api/revision/rev-id/log/',
'parents': ['123'],
- 'parent_urls': ['/api/revision/sha1_git_root/history/123/'],
'children': ['456'],
- 'children_urls': ['/api/revision/sha1_git_root/history/456/'],
- })
+ }, context='prev-rev')
+
+ # then
+ self.assertEqual(actual_revision, expected_revision)
mock_flask.url_for.assert_has_calls(
[call('api_revision',
+ sha1_git='prev-rev'),
+ call('api_revision',
sha1_git='rev-id'),
call('api_revision_log',
sha1_git='rev-id'),
- call('api_revision_history',
- sha1_git_root='sha1_git_root',
- sha1_git='123'),
- call('api_revision_history',
- sha1_git_root='sha1_git_root',
+ call('api_revision_log',
+ sha1_git='rev-id',
+ prev_sha1s='prev-rev'),
+ call('api_revision',
+ sha1_git='123',
+ context='prev-rev/rev-id'),
+ call('api_revision',
sha1_git='456')])
@patch('swh.web.ui.utils.flask')
@@ -631,30 +786,38 @@
'message_decoding_failed': True,
'parents': ['123'],
'children': ['456'],
- }, context='sha1_git_root')
+ }, context='prev-rev')
- # then
- self.assertEqual(actual_revision, {
+ expected_revision = {
'id': 'rev-id',
'url': '/api/revision/rev-id/',
+ 'history_url': '/api/revision/rev-id/log/',
+ 'history_context_url': ('/api/revision/rev-id/'
+ 'prev/prev-rev/log/'),
'message': None,
'message_decoding_failed': True,
'message_url': '/api/revision/rev-id/raw/',
- 'history_url': '/api/revision/rev-id/log/',
'parents': ['123'],
- 'parent_urls': ['/api/revision/sha1_git_root/history/123/'],
+ 'parent_urls': ['/api/revision/123/prev/prev-rev/rev-id/'],
'children': ['456'],
- 'children_urls': ['/api/revision/sha1_git_root/history/456/'],
- })
+ 'children_urls': ['/api/revision/456/', '/api/revision/prev-rev/'],
+ }
+
+ # then
+ self.assertEqual(actual_revision, expected_revision)
mock_flask.url_for.assert_has_calls(
[call('api_revision',
+ sha1_git='prev-rev'),
+ call('api_revision',
sha1_git='rev-id'),
call('api_revision_log',
sha1_git='rev-id'),
- call('api_revision_history',
- sha1_git_root='sha1_git_root',
- sha1_git='123'),
- call('api_revision_history',
- sha1_git_root='sha1_git_root',
+ call('api_revision_log',
+ sha1_git='rev-id',
+ prev_sha1s='prev-rev'),
+ call('api_revision',
+ sha1_git='123',
+ context='prev-rev/rev-id'),
+ call('api_revision',
sha1_git='456')])
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
@@ -679,8 +679,8 @@
'8734ef7e7c357ce2af928115c6c6a42b7e2a44e7'
],
'parent_urls': [
- '/api/1/revision/18d8be353ed3480476f032475e7c233eff7371d5'
- '/history/8734ef7e7c357ce2af928115c6c6a42b7e2a44e7/'
+ '/api/1/revision/8734ef7e7c357ce2af928115c6c6a42b7e2a44e7'
+ '/prev/18d8be353ed3480476f032475e7c233eff7371d5/'
],
'type': 'tar',
'synthetic': True,
@@ -1416,8 +1416,8 @@
'7834ef7e7c357ce2af928115c6c6a42b7e2a4345'
],
'parent_urls': [
- '/api/1/revision/18d8be353ed3480476f032475e7c233eff7371d5'
- '/history/7834ef7e7c357ce2af928115c6c6a42b7e2a4345/'
+ '/api/1/revision/7834ef7e7c357ce2af928115c6c6a42b7e2a4345'
+ '/prev/18d8be353ed3480476f032475e7c233eff7371d5/'
],
'type': 'tar',
'synthetic': True,
@@ -1521,8 +1521,8 @@
'committer_date_offset': 0,
'parents': ['adc83b19e793491b1c6ea0fd8b46cd9f32e592fc'],
'parent_urls': [
- '/api/1/revision/7834ef7e7c357ce2af928115c6c6a42b7e2a44e6'
- '/history/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc/'
+ '/api/1/revision/adc83b19e793491b1c6ea0fd8b46cd9f32e592fc'
+ '/prev/7834ef7e7c357ce2af928115c6c6a42b7e2a44e6/'
],
'type': 'tar',
'synthetic': True,
@@ -1545,8 +1545,8 @@
'committer_date_offset': 0,
'parents': ['7834ef7e7c357ce2af928115c6c6a42b7e2a4345'],
'parent_urls': [
- '/api/1/revision/18d8be353ed3480476f032475e7c233eff7371d5'
- '/history/7834ef7e7c357ce2af928115c6c6a42b7e2a4345/'
+ '/api/1/revision/7834ef7e7c357ce2af928115c6c6a42b7e2a4345'
+ '/prev/18d8be353ed3480476f032475e7c233eff7371d5/'
],
'type': 'tar',
'synthetic': True,
@@ -1596,8 +1596,8 @@
'7834ef7e7c357ce2af928115c6c6a42b7e2a4345'
],
'parent_urls': [
- '/api/1/revision/18d8be353ed3480476f032475e7c233eff7371d5'
- '/history/7834ef7e7c357ce2af928115c6c6a42b7e2a4345/'
+ '/api/1/revision/7834ef7e7c357ce2af928115c6c6a42b7e2a4345'
+ '/prev/18d8be353ed3480476f032475e7c233eff7371d5/'
],
'type': 'tar',
'synthetic': True,
@@ -1680,10 +1680,10 @@
'directory': '272'
}
- mock_service.lookup_revision_with_context.return_value = stub_revision
+ mock_service.lookup_revision.return_value = stub_revision
# then
- rv = self.app.get('/api/1/revision/666/history/883/')
+ rv = self.app.get('/api/1/revision/883/prev/999/')
self.assertEquals(rv.status_code, 200)
self.assertEquals(rv.mimetype, 'application/json')
@@ -1693,17 +1693,17 @@
'id': '883',
'url': '/api/1/revision/883/',
'history_url': '/api/1/revision/883/log/',
+ 'history_context_url': '/api/1/revision/883/prev/999/log/',
'children': ['777', '999'],
- 'children_urls': ['/api/1/revision/666/history/777/',
- '/api/1/revision/666/history/999/'],
+ 'children_urls': ['/api/1/revision/777/',
+ '/api/1/revision/999/'],
'parents': [],
'parent_urls': [],
'directory': '272',
'directory_url': '/api/1/directory/272/'
})
- mock_service.lookup_revision_with_context.assert_called_once_with(
- '666', '883', 100)
+ mock_service.lookup_revision.assert_called_once_with('883')
@patch('swh.web.ui.views.api._revision_directory_by')
@istest
diff --git a/swh/web/ui/tests/views/test_browse.py b/swh/web/ui/tests/views/test_browse.py
--- a/swh/web/ui/tests/views/test_browse.py
+++ b/swh/web/ui/tests/views/test_browse.py
@@ -760,7 +760,7 @@
'Not found!')
self.assertIsNone(self.get_context_variable('revision'))
- mock_api.api_revision.assert_called_once_with('1')
+ mock_api.api_revision.assert_called_once_with('1', None)
@patch('swh.web.ui.views.browse.api')
@istest
@@ -780,7 +780,7 @@
'wrong input!')
self.assertIsNone(self.get_context_variable('revision'))
- mock_api.api_revision.assert_called_once_with('426')
+ mock_api.api_revision.assert_called_once_with('426', None)
@patch('swh.web.ui.views.browse.api')
@istest
@@ -842,7 +842,7 @@
expected_revision)
self.assertIsNone(self.get_context_variable('message'))
- mock_api.api_revision.assert_called_once_with('426')
+ mock_api.api_revision.assert_called_once_with('426', None)
@patch('swh.web.ui.views.browse.api')
@istest
@@ -875,7 +875,7 @@
'Not found!')
self.assertEqual(self.get_context_variable('revisions'), [])
- mock_api.api_revision_log.assert_called_once_with('sha1')
+ mock_api.api_revision_log.assert_called_once_with('sha1', None)
@patch('swh.web.ui.views.browse.api')
@istest
@@ -895,7 +895,7 @@
'wrong input!')
self.assertEqual(self.get_context_variable('revisions'), [])
- mock_api.api_revision_log.assert_called_once_with('426')
+ mock_api.api_revision_log.assert_called_once_with('426', None)
@patch('swh.web.ui.views.browse.api')
@istest
@@ -935,7 +935,7 @@
isinstance(self.get_context_variable('revisions'), map))
self.assertIsNone(self.get_context_variable('message'))
- mock_api.api_revision_log.assert_called_once_with('426')
+ mock_api.api_revision_log.assert_called_once_with('426', None)
@patch('swh.web.ui.views.browse.api')
@istest
@@ -976,7 +976,7 @@
'wrong input!')
self.assertEqual(self.get_context_variable('revisions'), [])
- mock_api.api_revision_log.assert_called_once_with('abcd')
+ mock_api.api_revision_log.assert_called_once_with('abcd', None)
@patch('swh.web.ui.views.browse.api')
@istest
diff --git a/swh/web/ui/utils.py b/swh/web/ui/utils.py
--- a/swh/web/ui/utils.py
+++ b/swh/web/ui/utils.py
@@ -198,16 +198,102 @@
return entity
+def _get_path_list(path_string):
+ """Helper for enrich_revision: get a list of the sha1 id of the navigation
+ breadcrumbs, ordered from the oldest to the most recent.
+
+ Args:
+ path_string: the path as a '/'-separated string
+
+ Returns:
+ The navigation context as a list of sha1 revision ids
+ """
+ return path_string.split('/')
+
+
+def _get_revision_contexts(rev_id, context):
+ """Helper for enrich_revision: retrieve for the revision id and potentially
+ the navigation breadcrumbs the context to pass to parents and children of
+ of the revision.
+
+ Args:
+ rev_id: the revision's sha1 id
+ context: the current navigation context
+
+ Returns:
+ The context for parents, children and the url of the direct child as a
+ tuple in that order.
+ """
+ context_for_parents = None
+ context_for_children = None
+ url_direct_child = None
+
+ if not context:
+ return (rev_id, None, None)
+
+ path_list = _get_path_list(context)
+ context_for_parents = '%s/%s' % (context, rev_id)
+ prev_for_children = path_list[:-1]
+ if len(prev_for_children) > 0:
+ context_for_children = '/'.join(prev_for_children)
+ child_id = path_list[-1]
+ # This commit is not the first commit in the path
+ if context_for_children:
+ url_direct_child = flask.url_for(
+ 'api_revision',
+ sha1_git=child_id,
+ context=context_for_children)
+ # This commit is the first commit in the path
+ else:
+ url_direct_child = flask.url_for(
+ 'api_revision',
+ sha1_git=child_id)
+
+ return (context_for_parents, context_for_children, url_direct_child)
+
+
+def _make_child_url(rev_children, context):
+ """Helper for enrich_revision: retrieve the list of urls corresponding
+ to the children of the current revision according to the navigation
+ breadcrumbs.
+
+ Args:
+ rev_children: a list of revision id
+ context: the '/'-separated navigation breadcrumbs
+
+ Returns:
+ the list of the children urls according to the context
+ """
+ children = []
+ for child in rev_children:
+ if context and child != _get_path_list(context)[-1]:
+ children.append(flask.url_for('api_revision', sha1_git=child))
+ elif not context:
+ children.append(flask.url_for('api_revision', sha1_git=child))
+ return children
+
+
def enrich_revision(revision, context=None):
"""Enrich revision with links where it makes sense (directory, parents).
+ Keep track of the navigation breadcrumbs if they are specified.
+ Args:
+ revision: the revision as a dict
+ context: the navigation breadcrumbs as a /-separated string of revision
+ sha1_git
"""
- if not context:
- context = revision['id']
+
+ ctx_parents, ctx_children, url_direct_child = _get_revision_contexts(
+ revision['id'], context)
revision['url'] = flask.url_for('api_revision', sha1_git=revision['id'])
revision['history_url'] = flask.url_for('api_revision_log',
sha1_git=revision['id'])
+ if context:
+ revision['history_context_url'] = flask.url_for(
+ 'api_revision_log',
+ sha1_git=revision['id'],
+ prev_sha1s=context)
if 'author' in revision:
author = revision['author']
@@ -227,20 +313,19 @@
if 'parents' in revision:
parents = []
for parent in revision['parents']:
- parents.append(flask.url_for('api_revision_history',
- sha1_git_root=context,
- sha1_git=parent))
-
+ parents.append(flask.url_for('api_revision',
+ sha1_git=parent,
+ context=ctx_parents))
revision['parent_urls'] = parents
if 'children' in revision:
- children = []
- for child in revision['children']:
- children.append(flask.url_for('api_revision_history',
- sha1_git_root=context,
- sha1_git=child))
-
+ children = _make_child_url(revision['children'], context)
+ if url_direct_child:
+ children.append(url_direct_child)
revision['children_urls'] = children
+ else:
+ if url_direct_child:
+ revision['children_urls'] = [url_direct_child]
if 'message_decoding_failed' in revision:
revision['message_url'] = flask.url_for(
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
@@ -507,7 +507,8 @@
@app.route('/api/1/revision/')
@app.route('/api/1/revision/
/')
-def api_revision(sha1_git):
+@app.route('/api/1/revision//prev//')
+def api_revision(sha1_git, context=None):
"""Return information about revision with id sha1_git.
Args:
@@ -522,14 +523,15 @@
Example:
GET /api/1/revision/baf18f9fc50a0b6fef50460a76c33b2ddc57486e
-
"""
+ def _enrich_revision(revision, context=context):
+ return utils.enrich_revision(revision, context)
+
return _api_lookup(
sha1_git,
- lookup_fn=service.lookup_revision,
- error_msg_if_not_found='Revision with sha1_git %s not'
- ' found.' % sha1_git,
- enrich_fn=utils.enrich_revision)
+ service.lookup_revision,
+ 'Revision with sha1_git %s not found.' % sha1_git,
+ _enrich_revision)
@app.route('/api/1/revision//raw/')
diff --git a/swh/web/ui/views/browse.py b/swh/web/ui/views/browse.py
--- a/swh/web/ui/views/browse.py
+++ b/swh/web/ui/views/browse.py
@@ -298,17 +298,32 @@
@app.route('/browse/revision/')
@app.route('/browse/revision//')
+@app.route('/browse/revision//prev//')
@set_renderers(HTMLRenderer)
-def browse_revision(sha1_git):
- """Browse revision with sha1_git.
+def browse_revision(sha1_git, prev_sha1s=None):
+ """Browse the revision with git SHA1 sha1_git_cur, while optionally keeping
+ the context from which we came as a list of previous (i.e. later)
+ revisions' sha1s.
+ Args:
+ sha1_git: the requested revision's sha1_git.
+ prev_sha1s: an optional string of /-separated sha1s representing our
+ context, ordered by descending revision date.
+
+ Returns:
+ Information about revision of git SHA1 sha1_git_cur, with relevant URLS
+ pointing to the context augmented with sha1_git_cur.
+
+ Example:
+ GET /browse/revision/
"""
+
env = {'sha1_git': sha1_git,
'message': None,
'revision': None}
try:
- rev = api.api_revision(sha1_git)
+ rev = api.api_revision(sha1_git, prev_sha1s)
env['revision'] = utils.prepare_data_for_view(rev)
except (NotFoundExc, BadInputExc) as e:
env['message'] = str(e)
@@ -325,10 +340,17 @@
@app.route('/browse/revision//log/')
+@app.route('/browse/revision//prev//log/')
@set_renderers(HTMLRenderer)
-def browse_revision_log(sha1_git):
- """Browse revision with sha1_git's log.
+def browse_revision_log(sha1_git, prev_sha1s=None):
+ """Browse revision with sha1_git's log. If the navigation path through the
+ commit tree is specified, we intersect the earliest revision's log with the
+ revisions the user browsed through - ie the path taken to the specified
+ revision.
+ Args:
+ sha1_git: the current revision's SHA1_git checksum
+ prev_sha1s: optionally, the path through which we want log information
"""
env = {'sha1_git': sha1_git,
'sha1_url': '/browse/revision/%s/' % sha1_git,
@@ -336,7 +358,7 @@
'revisions': []}
try:
- revisions = api.api_revision_log(sha1_git)
+ revisions = api.api_revision_log(sha1_git, prev_sha1s)
env['revisions'] = map(utils.prepare_data_for_view, revisions)
except (NotFoundExc, BadInputExc) as e:
env['message'] = str(e)
@@ -392,6 +414,38 @@
return render_template('revision-log.html', **env)
+@app.route('/browse/revision//prev//')
+@set_renderers(HTMLRenderer)
+def browse_with_rev_context(sha1_git_cur, sha1s):
+ """Browse the revision with git SHA1 sha1_git_cur, while keeping the context
+ from which we came as a list of previous (i.e. later) revisions' sha1s.
+
+ Args:
+ sha1_git_cur: the requested revision's sha1_git.
+ sha1s: a string of /-separated sha1s representing our context, ordered
+ by descending revision date.
+
+ Returns:
+ Information about revision of git SHA1 sha1_git_cur, with relevant URLS
+ pointing to the context augmented with sha1_git_cur.
+
+ Example:
+ GET /browse/revision/
+ """
+ env = {'sha1_git': sha1_git_cur,
+ 'message': None,
+ 'revision': None}
+
+ try:
+ revision = api.api_revision(
+ sha1_git_cur, sha1s)
+ env['revision'] = utils.prepare_data_for_view(revision)
+ except (BadInputExc, NotFoundExc) as e:
+ env['message'] = str(e)
+
+ return render_template('revision.html', **env)
+
+
@app.route('/browse/revision//history//')
@set_renderers(HTMLRenderer)
def browse_revision_history(sha1_git_root, sha1_git):