@@ -165,97 +165,98 @@ class CompareController(BaseRepoControll
# List changesets that are ancestors of other but not of org.
# New changesets in org is thus ignored.
# Diff will be from common ancestor, and merges of org to other will thus be ignored.
# If merge is False:
# Make a raw diff from org to other, no matter if related or not.
# Changesets in one and not in the other will be ignored
merge = bool(request.GET.get('merge'))
# fulldiff disables cut_off_limit
c.fulldiff = request.GET.get('fulldiff')
# partial uses compare_cs.html template directly
partial = request.environ.get('HTTP_X_PARTIAL_XHR')
# as_form puts hidden input field with changeset revisions
c.as_form = partial and request.GET.get('as_form')
# swap url for compare_diff page - never partial and never as_form
c.swap_url = h.url('compare_url',
repo_name=other_repo,
org_ref_type=other_ref_type, org_ref_name=other_ref_name,
other_repo=org_repo,
other_ref_type=org_ref_type, other_ref_name=org_ref_name,
merge=merge or '')
# set callbacks for generating markup for icons
c.ignorews_url = _ignorews_url
c.context_url = _context_url
ignore_whitespace = request.GET.get('ignorews') == '1'
line_context = request.GET.get('context', 3)
org_repo = Repository.get_by_repo_name(org_repo)
other_repo = Repository.get_by_repo_name(other_repo)
if org_repo is None:
msg = 'Could not find org repo %s' % org_repo
log.error(msg)
h.flash(msg, category='error')
return redirect(url('compare_home', repo_name=c.repo_name))
if other_repo is None:
msg = 'Could not find other repo %s' % other_repo
if org_repo.scm_instance.alias != other_repo.scm_instance.alias:
msg = 'compare of two different kind of remote repos not available'
c.a_rev = self._get_ref_rev(org_repo, org_ref_type, org_ref_name)
c.a_rev = self._get_ref_rev(org_repo, org_ref_type, org_ref_name,
returnempty=True)
c.cs_rev = self._get_ref_rev(other_repo, other_ref_type, other_ref_name)
c.compare_home = False
c.a_repo = org_repo
c.a_ref_name = org_ref_name
c.a_ref_type = org_ref_type
c.cs_repo = other_repo
c.cs_ref_name = other_ref_name
c.cs_ref_type = other_ref_type
c.cs_ranges, c.cs_ranges_org, c.ancestor = self._get_changesets(
org_repo.scm_instance.alias, org_repo.scm_instance, c.a_rev,
other_repo.scm_instance, c.cs_rev)
raw_ids = [x.raw_id for x in c.cs_ranges]
c.cs_comments = other_repo.get_comments(raw_ids)
c.statuses = other_repo.statuses(raw_ids)
revs = [ctx.revision for ctx in reversed(c.cs_ranges)]
c.jsdata = json.dumps(graph_data(c.cs_repo.scm_instance, revs))
if partial:
return render('compare/compare_cs.html')
if merge and c.ancestor:
# case we want a simple diff without incoming changesets,
# previewing what will be merged.
# Make the diff on the other repo (which is known to have other_rev)
log.debug('Using ancestor %s as rev1 instead of %s'
% (c.ancestor, c.a_rev))
rev1 = c.ancestor
org_repo = other_repo
else: # comparing tips, not necessarily linearly related
if merge:
log.error('Unable to find ancestor revision')
if org_repo != other_repo:
# TODO: we could do this by using hg unionrepo
log.error('cannot compare across repos %s and %s', org_repo, other_repo)
h.flash(_('Cannot compare repositories without using common ancestor'), category='error')
raise HTTPBadRequest
rev1 = c.a_rev
diff_limit = self.cut_off_limit if not c.fulldiff else None
log.debug('running diff between %s and %s in %s'
% (rev1, c.cs_rev, org_repo.scm_instance.path))
txtdiff = org_repo.scm_instance.get_diff(rev1=rev1, rev2=c.cs_rev,
ignore_whitespace=ignore_whitespace,
context=line_context)
@@ -535,97 +535,100 @@ class PullrequestsController(BaseRepoCon
return redirect(url('my_pullrequests'))
raise HTTPForbidden()
@LoginRequired()
@HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
'repository.admin')
def show(self, repo_name, pull_request_id, extra=None):
repo_model = RepoModel()
c.users_array = repo_model.get_users_js()
c.user_groups_array = repo_model.get_user_groups_js()
c.pull_request = PullRequest.get_or_404(pull_request_id)
c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request)
cc_model = ChangesetCommentsModel()
cs_model = ChangesetStatusModel()
# pull_requests repo_name we opened it against
# ie. other_repo must match
if repo_name != c.pull_request.other_repo.repo_name:
raise HTTPNotFound
# load compare data into template context
c.cs_repo = c.pull_request.org_repo
(c.cs_ref_type,
c.cs_ref_name,
c.cs_rev) = c.pull_request.org_ref.split(':')
c.a_repo = c.pull_request.other_repo
(c.a_ref_type,
c.a_ref_name,
c.a_rev) = c.pull_request.other_ref.split(':') # other_rev is ancestor
org_scm_instance = c.cs_repo.scm_instance # property with expensive cache invalidation check!!!
c.cs_repo = c.cs_repo
c.cs_ranges = [org_scm_instance.get_changeset(x) for x in c.pull_request.revisions]
c.cs_ranges_org = None # not stored and not important and moving target - could be calculated ...
c.jsdata = json.dumps(graph_data(org_scm_instance, revs))
c.available = []
c.cs_branch_name = c.cs_ref_name
other_scm_instance = c.a_repo.scm_instance
c.update_msg = ""
c.update_msg_other = ""
if org_scm_instance.alias == 'hg' and c.a_ref_name != 'ancestor':
if c.cs_ref_type != 'branch':
c.cs_branch_name = org_scm_instance.get_changeset(c.cs_ref_name).branch # use ref_type ?
other_branch_name = c.a_ref_name
if c.a_ref_type != 'branch':
other_branch_name = other_scm_instance.get_changeset(c.a_ref_name).branch # use ref_type ?
try:
except EmptyRepositoryError:
other_branch_name = 'null' # not a branch name ... but close enough
# candidates: descendants of old head that are on the right branch
# and not are the old head itself ...
# and nothing at all if old head is a descendent of target ref name
if other_scm_instance._repo.revs('present(%s)::&%s', c.cs_ranges[-1].raw_id, other_branch_name):
c.update_msg = _('This pull request has already been merged to %s.') % other_branch_name
else: # look for children of PR head on source branch in org repo
arevs = org_scm_instance._repo.revs('%s:: & branch(%s) - %s',
revs[0], c.cs_branch_name, revs[0])
if arevs:
if c.pull_request.is_closed():
c.update_msg = _('This pull request has been closed and can not be updated with descendent changes on %s:') % c.cs_branch_name
else:
c.update_msg = _('This pull request can be updated with descendent changes on %s:') % c.cs_branch_name
c.available = [org_scm_instance.get_changeset(x) for x in arevs]
c.update_msg = _('No changesets found for updating this pull request.')
revs = org_scm_instance._repo.revs('head() & not (%s::) & branch(%s) & !closed()', revs[0], c.cs_branch_name)
if revs:
c.update_msg_other = _('Note: Branch %s also contains unrelated changes, such as %s.') % (c.cs_branch_name,
h.short_id(org_scm_instance.get_changeset((max(revs))).raw_id))
c.update_msg_other = _('Branch %s does not contain other changes.') % c.cs_branch_name
elif org_scm_instance.alias == 'git':
c.update_msg = _("Git pull requests don't support updates yet.")
c.cs_comments = c.cs_repo.get_comments(raw_ids)
c.statuses = c.cs_repo.statuses(raw_ids)
# we swap org/other ref since we run a simple diff on one repo
% (c.a_rev, c.cs_rev, org_scm_instance.path))
txtdiff = org_scm_instance.get_diff(rev1=safe_str(c.a_rev), rev2=safe_str(c.cs_rev),
diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
diff_limit=diff_limit)
_parsed = diff_processor.prepare()
@@ -391,67 +391,69 @@ class BaseRepoController(BaseController)
repository loaded items are
c.db_repo_scm_instance: instance of scm repository
c.db_repo: instance of db
c.repository_followers: number of followers
c.repository_forks: number of forks
c.repository_following: weather the current user is following the current repo
"""
def __before__(self):
super(BaseRepoController, self).__before__()
if c.repo_name: # extracted from routes
_dbr = Repository.get_by_repo_name(c.repo_name)
if not _dbr:
return
log.debug('Found repository in database %s with state `%s`'
% (safe_unicode(_dbr), safe_unicode(_dbr.repo_state)))
route = getattr(request.environ.get('routes.route'), 'name', '')
# allow to delete repos that are somehow damages in filesystem
if route in ['delete_repo']:
if _dbr.repo_state in [Repository.STATE_PENDING]:
if route in ['repo_creating_home']:
check_url = url('repo_creating_home', repo_name=c.repo_name)
return redirect(check_url)
dbr = c.db_repo = _dbr
c.db_repo_scm_instance = c.db_repo.scm_instance
if c.db_repo_scm_instance is None:
log.error('%s this repository is present in database but it '
'cannot be created as an scm instance', c.repo_name)
from kallithea.lib import helpers as h
h.flash(h.literal(_('Repository not found in the filesystem')),
category='error')
raise paste.httpexceptions.HTTPNotFound()
# some globals counter for menu
c.repository_followers = self.scm_model.get_followers(dbr)
c.repository_forks = self.scm_model.get_forks(dbr)
c.repository_pull_requests = self.scm_model.get_pull_requests(dbr)
c.repository_following = self.scm_model.is_following_repo(
c.repo_name, self.authuser.user_id)
@staticmethod
def _get_ref_rev(repo, ref_type, ref_name):
def _get_ref_rev(repo, ref_type, ref_name, returnempty=False):
Safe way to get changeset. If error occurs show error.
return repo.scm_instance.get_ref_revision(ref_type, ref_name)
except EmptyRepositoryError as e:
if returnempty:
return repo.scm_instance.EMPTY_CHANGESET
h.flash(h.literal(_('There are no changesets yet')),
raise webob.exc.HTTPNotFound()
except ChangesetDoesNotExistError as e:
h.flash(h.literal(_('Changeset not found')),
except RepositoryError as e:
log.error(traceback.format_exc())
h.flash(safe_str(e), category='error')
raise webob.exc.HTTPBadRequest()
Status change: