Name | Revision | Message | Date |
---|---|---|---|
{{ branch.name }} | {{ branch.revision|slice:":7" }} | {{ branch.date }} | {% endfor %}
This web application aims to provide HTML views to easily navigate in the Software Heritage archive. This is an ongoing development and new features and improvements will be progressively added over the time.
The current URI scheme of that web application is described below and depends on the type of Software Heritage object to browse. Its exhaustive documentation can be consulted from the official Software Heritage development documentation
Context-independent URLs provide information about SWH objects (e.g., revisions, directories, contents, persons, …), independently of the contexts where they have been found (e.g., specific software origins, branches, commits, …).
Below are some examples of endpoints used to just render the corresponding information for user consumption:
Where hyperlinks are created when browsing these kind of endpoints, they always point to other context-independent browsing URLs.
Context-dependent URLs provide information about SWH objects, limited to specific contexts where the objects have been found.
Currently, browsing the Software Heritage objects in the context of an origin is available. Below are some examples of such endpoints:
{{ release_note_header }}
{{ release_note_body }}
Name | -Type | +Target | Message | Date |
---|---|---|---|---|
{{ release.name }} | {{ release.target_type }} | {{ release.date }} | {% endfor %}
Revision | Author | Message | Date | |
---|---|---|---|---|
{{ log.revision }} | {{ log.author }} | {{ log.date }} | {{ log.directory }} |
{{ message_body }}
Computing file changes ...
%s' % origin_info_test_data['type']) self.assertContains(resp, '
%s' % (origin_info_test_data['url'], origin_info_test_data['url'])) self.assertContains(resp, '
' % content_language)
self.assertContains(resp, escape(content_data))
split_path = content_path.split('/')
filename = split_path[-1]
path = content_path.replace(filename, '')[:-1]
path_info = gen_path_info(path)
del url_args['path']
if timestamp:
url_args['timestamp'] = \
format_utc_iso_date(parse_timestamp(timestamp).isoformat(),
'%Y-%m-%dT%H:%M:%S')
root_dir_url = reverse('browse-origin-directory',
kwargs=url_args,
query_params=query_params)
self.assertContains(resp, '',
count=len(path_info)+1)
self.assertContains(resp, '%s' %
(root_dir_url, root_dir_sha1[:7]))
for p in path_info:
url_args['path'] = p['path']
dir_url = reverse('browse-origin-directory',
kwargs=url_args,
query_params=query_params)
self.assertContains(resp, '%s' %
(dir_url, p['name']))
self.assertContains(resp, ' %s ' % filename)
query_string = 'sha1_git:' + content_sha1
url_raw = reverse('browse-content-raw',
kwargs={'query_string': query_string},
query_params={'filename': filename})
self.assertContains(resp, url_raw)
del url_args['path']
origin_branches_url = \
reverse('browse-origin-branches',
kwargs=url_args,
query_params=query_params)
self.assertContains(resp, 'Branches (%s)' %
(origin_branches_url, len(origin_branches)))
origin_releases_url = \
reverse('browse-origin-releases',
kwargs=url_args,
query_params=query_params)
self.assertContains(resp, 'Releases (%s)' %
(origin_releases_url, len(origin_releases)))
self.assertContains(resp, '',
count=len(origin_branches))
url_args['path'] = content_path
for branch in origin_branches:
query_params['branch'] = branch['name']
root_dir_branch_url = \
reverse('browse-origin-content',
kwargs=url_args,
query_params=query_params)
self.assertContains(resp, '' % root_dir_branch_url)
self.assertContains(resp, '',
count=len(origin_releases))
query_params['branch'] = None
for release in origin_releases:
query_params['release'] = release['name']
root_dir_release_url = \
reverse('browse-origin-content',
kwargs=url_args,
query_params=query_params)
self.assertContains(resp, '' % root_dir_release_url)
@patch('swh.web.browse.utils.get_origin_visits')
@patch('swh.web.browse.utils.get_origin_visit_snapshot')
- @patch('swh.web.browse.views.origin.service')
+ @patch('swh.web.browse.views.utils.snapshot_context.service')
@patch('swh.web.browse.utils.service')
- @patch('swh.web.browse.views.origin.request_content')
+ @patch('swh.web.browse.views.utils.snapshot_context.request_content')
@istest
def origin_content_view(self, mock_request_content, mock_utils_service,
mock_service, mock_get_origin_visit_snapshot,
mock_get_origin_visits):
stub_content_text_sha1 = stub_content_text_data['checksums']['sha1']
mock_get_origin_visits.return_value = stub_content_origin_visits
mock_get_origin_visit_snapshot.return_value = stub_content_origin_snapshot
mock_service.lookup_directory_with_path.return_value = \
{'target': stub_content_text_sha1}
mock_request_content.return_value = stub_content_text_data
mock_utils_service.lookup_origin.return_value = stub_content_origin_info
self.origin_content_view_test(stub_content_origin_info,
stub_content_origin_visits,
stub_content_origin_snapshot[0],
stub_content_origin_snapshot[1],
stub_content_origin_branch,
stub_content_root_dir,
stub_content_text_sha1,
stub_content_text_path,
stub_content_text_data['raw_data'],
'cpp')
self.origin_content_view_test(stub_content_origin_info,
stub_content_origin_visits,
stub_content_origin_snapshot[0],
stub_content_origin_snapshot[1],
stub_content_origin_branch,
stub_content_root_dir,
stub_content_text_sha1,
stub_content_text_path,
stub_content_text_data['raw_data'],
'cpp',
visit_id=stub_content_origin_visit_id)
self.origin_content_view_test(stub_content_origin_info,
stub_content_origin_visits,
stub_content_origin_snapshot[0],
stub_content_origin_snapshot[1],
stub_content_origin_branch,
stub_content_root_dir,
stub_content_text_sha1,
stub_content_text_path,
stub_content_text_data['raw_data'],
'cpp',
timestamp=stub_content_origin_visit_unix_ts)
self.origin_content_view_test(stub_content_origin_info,
stub_content_origin_visits,
stub_content_origin_snapshot[0],
stub_content_origin_snapshot[1],
stub_content_origin_branch,
stub_content_root_dir,
stub_content_text_sha1,
stub_content_text_path,
stub_content_text_data['raw_data'],
'cpp',
timestamp=stub_content_origin_visit_iso_date)
@nottest
def origin_directory_view(self, origin_info, origin_visits,
origin_branches, origin_releases, origin_branch,
root_directory_sha1, directory_entries,
visit_id=None, timestamp=None, path=None):
dirs = [e for e in directory_entries
if e['type'] == 'dir']
files = [e for e in directory_entries
if e['type'] == 'file']
if not visit_id:
visit_id = origin_visits[-1]['visit']
url_args = {'origin_type': origin_info['type'],
'origin_url': origin_info['url']}
query_params = {}
if timestamp:
url_args['timestamp'] = timestamp
else:
query_params['visit_id'] = visit_id
if path:
url_args['path'] = path
url = reverse('browse-origin-directory',
kwargs=url_args,
query_params=query_params)
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('directory.html')
self.assertContains(resp, '',
count=len(dirs))
self.assertContains(resp, ' ',
count=len(files))
if timestamp:
url_args['timestamp'] = \
format_utc_iso_date(parse_timestamp(timestamp).isoformat(),
'%Y-%m-%dT%H:%M:%S')
for d in dirs:
dir_path = d['name']
if path:
dir_path = "%s/%s" % (path, d['name'])
dir_url_args = dict(url_args)
dir_url_args['path'] = dir_path
dir_url = reverse('browse-origin-directory',
kwargs=dir_url_args,
query_params=query_params)
self.assertContains(resp, dir_url)
for f in files:
file_path = f['name']
if path:
file_path = "%s/%s" % (path, f['name'])
file_url_args = dict(url_args)
file_url_args['path'] = file_path
file_url = reverse('browse-origin-content',
kwargs=file_url_args,
query_params=query_params)
self.assertContains(resp, file_url)
if 'path' in url_args:
del url_args['path']
root_dir_branch_url = \
reverse('browse-origin-directory',
kwargs=url_args,
query_params=query_params)
nb_bc_paths = 1
if path:
nb_bc_paths = len(path.split('/')) + 1
self.assertContains(resp, '', count=nb_bc_paths)
self.assertContains(resp, '%s' %
(root_dir_branch_url,
root_directory_sha1[:7]))
origin_branches_url = \
reverse('browse-origin-branches',
kwargs=url_args,
query_params=query_params)
self.assertContains(resp, 'Branches (%s)' %
(origin_branches_url, len(origin_branches)))
origin_releases_url = \
reverse('browse-origin-releases',
kwargs=url_args,
query_params=query_params)
self.assertContains(resp, 'Releases (%s)' %
(origin_releases_url, len(origin_releases)))
if path:
url_args['path'] = path
self.assertContains(resp, ' ',
count=len(origin_branches))
for branch in origin_branches:
query_params['branch'] = branch['name']
root_dir_branch_url = \
reverse('browse-origin-directory',
kwargs=url_args,
query_params=query_params)
self.assertContains(resp, '' % root_dir_branch_url)
self.assertContains(resp, '',
count=len(origin_releases))
query_params['branch'] = None
for release in origin_releases:
query_params['release'] = release['name']
root_dir_release_url = \
reverse('browse-origin-directory',
kwargs=url_args,
query_params=query_params)
self.assertContains(resp, '' % root_dir_release_url)
self.assertContains(resp, 'vault-cook-directory')
self.assertContains(resp, 'vault-cook-revision')
@patch('swh.web.browse.utils.get_origin_visits')
@patch('swh.web.browse.utils.get_origin_visit_snapshot')
@patch('swh.web.browse.utils.service')
@patch('swh.web.browse.views.origin.service')
@istest
def origin_root_directory_view(self, mock_origin_service,
mock_utils_service,
mock_get_origin_visit_snapshot,
mock_get_origin_visits):
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_snapshot.return_value = stub_origin_snapshot
mock_utils_service.lookup_directory.return_value = \
stub_origin_root_directory_entries
mock_utils_service.lookup_origin.return_value = stub_origin_info
self.origin_directory_view(stub_origin_info, stub_origin_visits,
stub_origin_snapshot[0],
stub_origin_snapshot[1],
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_root_directory_entries)
self.origin_directory_view(stub_origin_info, stub_origin_visits,
stub_origin_snapshot[0],
stub_origin_snapshot[1],
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_root_directory_entries,
visit_id=stub_visit_id)
self.origin_directory_view(stub_origin_info, stub_origin_visits,
stub_origin_snapshot[0],
stub_origin_snapshot[1],
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_root_directory_entries,
timestamp=stub_visit_unix_ts)
self.origin_directory_view(stub_origin_info, stub_origin_visits,
stub_origin_snapshot[0],
stub_origin_snapshot[1],
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_root_directory_entries,
timestamp=stub_visit_iso_date)
@patch('swh.web.browse.utils.get_origin_visits')
@patch('swh.web.browse.utils.get_origin_visit_snapshot')
@patch('swh.web.browse.utils.service')
- @patch('swh.web.browse.views.origin.service')
+ @patch('swh.web.browse.views.utils.snapshot_context.service')
@istest
def origin_sub_directory_view(self, mock_origin_service,
mock_utils_service,
mock_get_origin_visit_snapshot,
mock_get_origin_visits):
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_snapshot.return_value = stub_origin_snapshot
mock_utils_service.lookup_directory.return_value = \
stub_origin_sub_directory_entries
mock_origin_service.lookup_directory_with_path.return_value = \
{'target': '120c39eeb566c66a77ce0e904d29dfde42228adb'}
mock_utils_service.lookup_origin.return_value = stub_origin_info
self.origin_directory_view(stub_origin_info, stub_origin_visits,
stub_origin_snapshot[0],
stub_origin_snapshot[1],
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_sub_directory_entries,
path=stub_origin_sub_directory_path)
self.origin_directory_view(stub_origin_info, stub_origin_visits,
stub_origin_snapshot[0],
stub_origin_snapshot[1],
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_sub_directory_entries,
visit_id=stub_visit_id,
path=stub_origin_sub_directory_path)
self.origin_directory_view(stub_origin_info, stub_origin_visits,
stub_origin_snapshot[0],
stub_origin_snapshot[1],
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_sub_directory_entries,
timestamp=stub_visit_unix_ts,
path=stub_origin_sub_directory_path)
self.origin_directory_view(stub_origin_info, stub_origin_visits,
stub_origin_snapshot[0],
stub_origin_snapshot[1],
stub_origin_master_branch,
stub_origin_root_directory_sha1,
stub_origin_sub_directory_entries,
timestamp=stub_visit_iso_date,
path=stub_origin_sub_directory_path)
- @patch('swh.web.browse.views.origin.request_content')
+ @patch('swh.web.browse.views.utils.snapshot_context.request_content')
@patch('swh.web.browse.utils.get_origin_visits')
@patch('swh.web.browse.utils.get_origin_visit_snapshot')
@patch('swh.web.browse.utils.service')
@patch('swh.web.browse.views.origin.service')
+ @patch('swh.web.browse.views.utils.snapshot_context.service')
@istest
- def origin_request_errors(self, mock_origin_service,
+ def origin_request_errors(self, mock_snapshot_service,
+ mock_origin_service,
mock_utils_service,
mock_get_origin_visit_snapshot,
mock_get_origin_visits,
mock_request_content):
mock_origin_service.lookup_origin.side_effect = \
NotFoundExc('origin not found')
url = reverse('browse-origin',
kwargs={'origin_type': 'foo',
'origin_url': 'bar'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
- self.assertContains(resp, "origin not found", status_code=404)
+ self.assertContains(resp, 'origin not found', status_code=404)
mock_utils_service.lookup_origin.side_effect = None
mock_utils_service.lookup_origin.return_value = origin_info_test_data
mock_get_origin_visits.return_value = []
url = reverse('browse-origin-directory',
kwargs={'origin_type': 'foo',
'origin_url': 'bar'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, "No SWH visit", status_code=404)
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_snapshot.side_effect = \
NotFoundExc('visit not found')
url = reverse('browse-origin-directory',
kwargs={'origin_type': 'foo',
'origin_url': 'bar'},
query_params={'visit_id': len(stub_origin_visits)+1})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertRegex(resp.content.decode('utf-8'), 'Visit.*not found')
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_snapshot.side_effect = None
mock_get_origin_visit_snapshot.return_value = ([], [])
url = reverse('browse-origin-directory',
kwargs={'origin_type': 'foo',
'origin_url': 'bar'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertRegex(resp.content.decode('utf-8'),
'Origin.*has an empty list of branches')
mock_get_origin_visit_snapshot.return_value = stub_origin_snapshot
mock_utils_service.lookup_directory.side_effect = \
NotFoundExc('Directory not found')
url = reverse('browse-origin-directory',
kwargs={'origin_type': 'foo',
'origin_url': 'bar'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, 'Directory not found', status_code=404)
mock_origin_service.lookup_origin.side_effect = None
mock_origin_service.lookup_origin.return_value = origin_info_test_data
mock_get_origin_visits.return_value = []
url = reverse('browse-origin-content',
kwargs={'origin_type': 'foo',
'origin_url': 'bar',
'path': 'foo'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, "No SWH visit", status_code=404)
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_snapshot.side_effect = \
NotFoundExc('visit not found')
url = reverse('browse-origin-content',
kwargs={'origin_type': 'foo',
'origin_url': 'bar',
'path': 'foo'},
query_params={'visit_id': len(stub_origin_visits)+1})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertRegex(resp.content.decode('utf-8'), 'Visit.*not found')
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_snapshot.side_effect = None
mock_get_origin_visit_snapshot.return_value = ([], [])
url = reverse('browse-origin-content',
kwargs={'origin_type': 'foo',
'origin_url': 'bar',
'path': 'baz'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertRegex(resp.content.decode('utf-8'),
'Origin.*has an empty list of branches')
mock_get_origin_visit_snapshot.return_value = stub_origin_snapshot
- mock_origin_service.lookup_directory_with_path.return_value = \
+ mock_snapshot_service.lookup_directory_with_path.return_value = \
{'target': stub_content_text_data['checksums']['sha1']}
mock_request_content.side_effect = \
NotFoundExc('Content not found')
url = reverse('browse-origin-content',
kwargs={'origin_type': 'foo',
'origin_url': 'bar',
'path': 'baz'})
resp = self.client.get(url)
self.assertEquals(resp.status_code, 404)
self.assertTemplateUsed('error.html')
self.assertContains(resp, 'Content not found', status_code=404)
@patch('swh.web.browse.utils.get_origin_visits')
@patch('swh.web.browse.utils.get_origin_visit_snapshot')
@patch('swh.web.browse.utils.service')
@patch('swh.web.browse.views.origin.service')
@istest
def origin_branches(self, mock_origin_service,
mock_utils_service,
mock_get_origin_visit_snapshot,
mock_get_origin_visits):
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_snapshot.return_value = stub_origin_snapshot
mock_utils_service.lookup_origin.return_value = stub_origin_info
url_args = {'origin_type': stub_origin_info['type'],
'origin_url': stub_origin_info['url']}
url = reverse('browse-origin-branches',
kwargs=url_args)
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('branches.html')
origin_branches = stub_origin_snapshot[0]
origin_releases = stub_origin_snapshot[1]
origin_branches_url = \
reverse('browse-origin-branches',
kwargs=url_args)
self.assertContains(resp, 'Branches (%s)' %
(origin_branches_url, len(origin_branches)))
origin_releases_url = \
reverse('browse-origin-releases',
kwargs=url_args)
self.assertContains(resp, 'Releases (%s)' %
(origin_releases_url, len(origin_releases)))
self.assertContains(resp, '',
count=len(origin_branches))
for branch in origin_branches:
browse_branch_url = reverse('browse-origin-directory',
kwargs={'origin_type': stub_origin_info['type'],
'origin_url': stub_origin_info['url']},
query_params={'branch': branch['name']})
self.assertContains(resp, '%s' % (escape(browse_branch_url), branch['name']))
browse_revision_url = reverse('browse-revision',
kwargs={'sha1_git': branch['revision']},
query_params={'origin_type': stub_origin_info['type'],
'origin_url': stub_origin_info['url']})
self.assertContains(resp, '%s' % (escape(browse_revision_url), branch['revision'][:7]))
@patch('swh.web.browse.utils.get_origin_visits')
@patch('swh.web.browse.utils.get_origin_visit_snapshot')
@patch('swh.web.browse.utils.service')
@patch('swh.web.browse.views.origin.service')
@istest
def origin_releases(self, mock_origin_service,
mock_utils_service,
mock_get_origin_visit_snapshot,
mock_get_origin_visits):
mock_get_origin_visits.return_value = stub_origin_visits
mock_get_origin_visit_snapshot.return_value = stub_origin_snapshot
mock_utils_service.lookup_origin.return_value = stub_origin_info
url_args = {'origin_type': stub_origin_info['type'],
'origin_url': stub_origin_info['url']}
url = reverse('browse-origin-releases',
kwargs=url_args)
resp = self.client.get(url)
self.assertEquals(resp.status_code, 200)
self.assertTemplateUsed('releases.html')
origin_branches = stub_origin_snapshot[0]
origin_releases = stub_origin_snapshot[1]
origin_branches_url = \
reverse('browse-origin-branches',
kwargs=url_args)
self.assertContains(resp, 'Branches (%s)' %
(origin_branches_url, len(origin_branches)))
origin_releases_url = \
reverse('browse-origin-releases',
kwargs=url_args)
self.assertContains(resp, 'Releases (%s)' %
(origin_releases_url, len(origin_releases)))
self.assertContains(resp, ' ',
count=len(origin_releases))
for release in origin_releases:
browse_release_url = reverse('browse-release',
kwargs={'sha1_git': release['id']},
query_params={'origin_type': stub_origin_info['type'],
'origin_url': stub_origin_info['url']})
self.assertContains(resp, '%s' % (escape(browse_release_url), release['name']))
diff --git a/version.txt b/version.txt
index df728450..db8e8a77 100644
--- a/version.txt
+++ b/version.txt
@@ -1 +1 @@
-v0.0.119-0-g2226418
\ No newline at end of file
+v0.0.120-0-g947d0ba
\ No newline at end of file