##// END OF EJS Templates
pull-requests: increase stability of concurrent pull requests creation by flushing prematurly the statuses of commits....
pull-requests: increase stability of concurrent pull requests creation by flushing prematurly the statuses of commits. This is required to increase the versions on each concurrent call. Otherwise we could get into an integrity errors of commitsha+version+repo

File last commit:

r3363:f08e98b1 default
r3408:2a133f7e stable
Show More
repo_changelog.py
358 lines | 13.6 KiB | text/x-python | PythonLexer
changelog: ported to pyramid views.
r1931 # -*- coding: utf-8 -*-
release: update copyright year to 2018
r2487 # Copyright (C) 2010-2018 RhodeCode GmbH
changelog: ported to pyramid views.
r1931 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import logging
from pyramid.httpexceptions import HTTPNotFound, HTTPFound
from pyramid.view import view_config
from pyramid.renderers import render
from pyramid.response import Response
from rhodecode.apps._base import RepoAppView
import rhodecode.lib.helpers as h
from rhodecode.lib.auth import (
LoginRequired, HasRepoPermissionAnyDecorator)
from rhodecode.lib.ext_json import json
from rhodecode.lib.graphmod import _colored, _dagwalker
from rhodecode.lib.helpers import RepoPage
commits: hide evolve commits. Fixes #5392
r2144 from rhodecode.lib.utils2 import safe_int, safe_str, str2bool
changelog: ported to pyramid views.
r1931 from rhodecode.lib.vcs.exceptions import (
RepositoryError, CommitDoesNotExistError,
CommitError, NodeDoesNotExistError, EmptyRepositoryError)
log = logging.getLogger(__name__)
DEFAULT_CHANGELOG_SIZE = 20
class RepoChangelogView(RepoAppView):
def _get_commit_or_redirect(self, commit_id, redirect_after=True):
"""
This is a safe way to get commit. If an error occurs it redirects to
tip with proper message
:param commit_id: id of commit to fetch
:param redirect_after: toggle redirection
"""
_ = self.request.translate
try:
return self.rhodecode_vcs_repo.get_commit(commit_id)
except EmptyRepositoryError:
if not redirect_after:
return None
h.flash(h.literal(
_('There are no commits yet')), category='warning')
raise HTTPFound(
h.route_path('repo_summary', repo_name=self.db_repo_name))
except (CommitDoesNotExistError, LookupError):
msg = _('No such commit exists for this repository')
h.flash(msg, category='error')
raise HTTPNotFound()
except RepositoryError as e:
h.flash(safe_str(h.escape(e)), category='error')
raise HTTPNotFound()
def _graph(self, repo, commits, prev_data=None, next_data=None):
"""
Generates a DAG graph for repo
:param repo: repo instance
:param commits: list of commits
"""
if not commits:
changelog: fix consistency of returned data to 2 element tuple.
r2132 return json.dumps([]), json.dumps([])
changelog: ported to pyramid views.
r1931
def serialize(commit, parents=True):
data = dict(
raw_id=commit.raw_id,
idx=commit.idx,
changelog: escape the graph branch name to prevent XSS.
r2994 branch=h.escape(commit.branch),
changelog: ported to pyramid views.
r1931 )
if parents:
data['parents'] = [
serialize(x, parents=False) for x in commit.parents]
return data
prev_data = prev_data or []
next_data = next_data or []
current = [serialize(x) for x in commits]
commits = prev_data + current + next_data
dag = _dagwalker(repo, commits)
data = [[commit_id, vtx, edges, branch]
for commit_id, vtx, edges, branch in _colored(dag)]
return json.dumps(data), json.dumps(current)
def _check_if_valid_branch(self, branch_name, repo_name, f_path):
if branch_name not in self.rhodecode_vcs_repo.branches_all:
h.flash('Branch {} is not found.'.format(h.escape(branch_name)),
category='warning')
redirect_url = h.route_path(
'repo_changelog_file', repo_name=repo_name,
commit_id=branch_name, f_path=f_path or '')
raise HTTPFound(redirect_url)
def _load_changelog_data(
self, c, collection, page, chunk_size, branch_name=None,
changelog: fix url generation for file changelog and ensure...
r2124 dynamic=False, f_path=None, commit_id=None):
changelog: ported to pyramid views.
r1931
def url_generator(**kw):
query_params = {}
query_params.update(kw)
changelog: fix url generation for file changelog and ensure...
r2124 if f_path:
# changelog for file
return h.route_path(
'repo_changelog_file',
repo_name=c.rhodecode_db_repo.repo_name,
commit_id=commit_id, f_path=f_path,
_query=query_params)
else:
return h.route_path(
'repo_changelog',
repo_name=c.rhodecode_db_repo.repo_name, _query=query_params)
changelog: ported to pyramid views.
r1931
c.total_cs = len(collection)
c.showing_commits = min(chunk_size, c.total_cs)
c.pagination = RepoPage(collection, page=page, item_count=c.total_cs,
items_per_page=chunk_size, branch=branch_name,
url=url_generator)
c.next_page = c.pagination.next_page
c.prev_page = c.pagination.previous_page
if dynamic:
if self.request.GET.get('chunk') != 'next':
c.next_page = None
if self.request.GET.get('chunk') != 'prev':
c.prev_page = None
page_commit_ids = [x.raw_id for x in c.pagination]
c.comments = c.rhodecode_db_repo.get_comments(page_commit_ids)
c.statuses = c.rhodecode_db_repo.statuses(page_commit_ids)
def load_default_context(self):
c = self._get_local_tmpl_context(include_app_defaults=True)
c.rhodecode_repo = self.rhodecode_vcs_repo
pylons: remove pylons as dependency...
r2351
changelog: ported to pyramid views.
r1931 return c
changelog: fix and optimize loading of chunks for file history....
r2130 def _get_preload_attrs(self):
pre_load = ['author', 'branch', 'date', 'message', 'parents',
'obsolete', 'phase', 'hidden']
return pre_load
changelog: ported to pyramid views.
r1931 @LoginRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@view_config(
route_name='repo_changelog', request_method='GET',
renderer='rhodecode:templates/changelog/changelog.mako')
@view_config(
route_name='repo_changelog_file', request_method='GET',
renderer='rhodecode:templates/changelog/changelog.mako')
def repo_changelog(self):
c = self.load_default_context()
commit_id = self.request.matchdict.get('commit_id')
f_path = self._get_f_path(self.request.matchdict)
commits: hide evolve commits. Fixes #5392
r2144 show_hidden = str2bool(self.request.GET.get('evolve'))
changelog: ported to pyramid views.
r1931
chunk_size = 20
c.branch_name = branch_name = self.request.GET.get('branch') or ''
c.book_name = book_name = self.request.GET.get('bookmark') or ''
changelog: fix and optimize loading of chunks for file history....
r2130 c.f_path = f_path
c.commit_id = commit_id
commits: hide evolve commits. Fixes #5392
r2144 c.show_hidden = show_hidden
changelog: ported to pyramid views.
r1931 hist_limit = safe_int(self.request.GET.get('limit')) or None
p = safe_int(self.request.GET.get('page', 1), 1)
c.selected_name = branch_name or book_name
if not commit_id and branch_name:
self._check_if_valid_branch(branch_name, self.db_repo_name, f_path)
c.changelog_for_path = f_path
changelog: fix and optimize loading of chunks for file history....
r2130 pre_load = self._get_preload_attrs()
changelog: ported to pyramid views.
r1931
partial_xhr = self.request.environ.get('HTTP_X_PARTIAL_XHR')
try:
if f_path:
log.debug('generating changelog for path %s', f_path)
# get the history for the file !
base_commit = self.rhodecode_vcs_repo.get_commit(commit_id)
changelog: fix and optimize loading of chunks for file history....
r2130
changelog: ported to pyramid views.
r1931 try:
vcs: rename get_file_history to get_path_history as it better reflects what it does.
r3275 collection = base_commit.get_path_history(
changelog: ported to pyramid views.
r1931 f_path, limit=hist_limit, pre_load=pre_load)
if collection and partial_xhr:
# for ajax call we remove first one since we're looking
# at it right now in the context of a file commit
collection.pop(0)
except (NodeDoesNotExistError, CommitError):
# this node is not present at tip!
try:
commit = self._get_commit_or_redirect(commit_id)
vcs: rename get_file_history to get_path_history as it better reflects what it does.
r3275 collection = commit.get_path_history(f_path)
changelog: ported to pyramid views.
r1931 except RepositoryError as e:
h.flash(safe_str(e), category='warning')
redirect_url = h.route_path(
'repo_changelog', repo_name=self.db_repo_name)
raise HTTPFound(redirect_url)
collection = list(reversed(collection))
else:
collection = self.rhodecode_vcs_repo.get_commits(
commits: hide evolve commits. Fixes #5392
r2144 branch_name=branch_name, show_hidden=show_hidden,
pre_load=pre_load)
changelog: ported to pyramid views.
r1931
self._load_changelog_data(
changelog: fix url generation for file changelog and ensure...
r2124 c, collection, p, chunk_size, c.branch_name,
f_path=f_path, commit_id=commit_id)
changelog: ported to pyramid views.
r1931
except EmptyRepositoryError as e:
h.flash(safe_str(h.escape(e)), category='warning')
raise HTTPFound(
h.route_path('repo_summary', repo_name=self.db_repo_name))
changelog: fix url generation for file changelog and ensure...
r2124 except HTTPFound:
raise
changelog: ported to pyramid views.
r1931 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
log.exception(safe_str(e))
h.flash(safe_str(h.escape(e)), category='error')
raise HTTPFound(
h.route_path('repo_changelog', repo_name=self.db_repo_name))
if partial_xhr or self.request.environ.get('HTTP_X_PJAX'):
changelog: fix and optimize loading of chunks for file history....
r2130 # case when loading dynamic file history in file view
changelog: ported to pyramid views.
r1931 # loading from ajax, we don't want the first result, it's popped
# in the code above
html = render(
'rhodecode:templates/changelog/changelog_file_history.mako',
self._get_template_context(c), self.request)
return Response(html)
changelog: only load graph data when showing changelog for both commit and commit loaded via ajax chunks.
r2131 commit_ids = []
changelog: ported to pyramid views.
r1931 if not f_path:
changelog: only load graph data when showing changelog for both commit and commit loaded via ajax chunks.
r2131 # only load graph data when not in file history mode
changelog: ported to pyramid views.
r1931 commit_ids = c.pagination
c.graph_data, c.graph_commits = self._graph(
self.rhodecode_vcs_repo, commit_ids)
return self._get_template_context(c)
@LoginRequired()
@HasRepoPermissionAnyDecorator(
'repository.read', 'repository.write', 'repository.admin')
@view_config(
route_name='repo_changelog_elements', request_method=('GET', 'POST'),
renderer='rhodecode:templates/changelog/changelog_elements.mako',
xhr=True)
changelog: fix and optimize loading of chunks for file history....
r2130 @view_config(
route_name='repo_changelog_elements_file', request_method=('GET', 'POST'),
renderer='rhodecode:templates/changelog/changelog_elements.mako',
xhr=True)
changelog: ported to pyramid views.
r1931 def repo_changelog_elements(self):
c = self.load_default_context()
changelog: fix and optimize loading of chunks for file history....
r2130 commit_id = self.request.matchdict.get('commit_id')
f_path = self._get_f_path(self.request.matchdict)
commits: hide evolve commits. Fixes #5392
r2144 show_hidden = str2bool(self.request.GET.get('evolve'))
changelog: ported to pyramid views.
r1931 chunk_size = 20
changelog: fix and optimize loading of chunks for file history....
r2130 hist_limit = safe_int(self.request.GET.get('limit')) or None
changelog: ported to pyramid views.
r1931
def wrap_for_error(err):
html = '<tr>' \
'<td colspan="9" class="alert alert-error">ERROR: {}</td>' \
'</tr>'.format(err)
return Response(html)
c.branch_name = branch_name = self.request.GET.get('branch') or ''
c.book_name = book_name = self.request.GET.get('bookmark') or ''
changelog: fix and optimize loading of chunks for file history....
r2130 c.f_path = f_path
c.commit_id = commit_id
commits: hide evolve commits. Fixes #5392
r2144 c.show_hidden = show_hidden
changelog: ported to pyramid views.
r1931
c.selected_name = branch_name or book_name
if branch_name and branch_name not in self.rhodecode_vcs_repo.branches_all:
return wrap_for_error(
safe_str('Branch: {} is not valid'.format(branch_name)))
changelog: fix and optimize loading of chunks for file history....
r2130 pre_load = self._get_preload_attrs()
if f_path:
changelog: prevent from 500 errors on changelog when fetching certain commits.
r2151 try:
base_commit = self.rhodecode_vcs_repo.get_commit(commit_id)
except (RepositoryError, CommitDoesNotExistError, Exception) as e:
log.exception(safe_str(e))
raise HTTPFound(
h.route_path('repo_changelog', repo_name=self.db_repo_name))
vcs: rename get_file_history to get_path_history as it better reflects what it does.
r3275 collection = base_commit.get_path_history(
changelog: fix and optimize loading of chunks for file history....
r2130 f_path, limit=hist_limit, pre_load=pre_load)
collection = list(reversed(collection))
else:
collection = self.rhodecode_vcs_repo.get_commits(
commits: hide evolve commits. Fixes #5392
r2144 branch_name=branch_name, show_hidden=show_hidden, pre_load=pre_load)
changelog: ported to pyramid views.
r1931
p = safe_int(self.request.GET.get('page', 1), 1)
try:
self._load_changelog_data(
changelog: fix and optimize loading of chunks for file history....
r2130 c, collection, p, chunk_size, dynamic=True,
f_path=f_path, commit_id=commit_id)
changelog: ported to pyramid views.
r1931 except EmptyRepositoryError as e:
return wrap_for_error(safe_str(e))
except (RepositoryError, CommitDoesNotExistError, Exception) as e:
log.exception('Failed to fetch commits')
return wrap_for_error(safe_str(e))
prev_data = None
next_data = None
changelog: prevent from 500 errors on changelog when fetching certain commits.
r2151 try:
prev_graph = json.loads(self.request.POST.get('graph') or '{}')
except json.JSONDecodeError:
prev_graph = {}
changelog: ported to pyramid views.
r1931
if self.request.GET.get('chunk') == 'prev':
next_data = prev_graph
elif self.request.GET.get('chunk') == 'next':
prev_data = prev_graph
changelog: only load graph data when showing changelog for both commit and commit loaded via ajax chunks.
r2131 commit_ids = []
if not f_path:
# only load graph data when not in file history mode
commit_ids = c.pagination
changelog: ported to pyramid views.
r1931 c.graph_data, c.graph_commits = self._graph(
changelog: only load graph data when showing changelog for both commit and commit loaded via ajax chunks.
r2131 self.rhodecode_vcs_repo, commit_ids,
changelog: ported to pyramid views.
r1931 prev_data=prev_data, next_data=next_data)
return self._get_template_context(c)