changeset 5776:3f646f7bac39

pullrequests: handle missing revisions - especially after Git GC (Issue #176)
author domruf <dominikruf@gmail.com>
date Tue, 16 Feb 2016 22:15:30 +0100
parents 35508e2d7557
children 7e67883ee300
files kallithea/controllers/pullrequests.py
diffstat 1 files changed, 64 insertions(+), 54 deletions(-) [+]
line wrap: on
line diff
--- a/kallithea/controllers/pullrequests.py	Tue Mar 08 09:09:50 2016 +0000
+++ b/kallithea/controllers/pullrequests.py	Tue Feb 16 22:15:30 2016 +0100
@@ -45,7 +45,7 @@
 from kallithea.lib.exceptions import UserInvalidException
 from kallithea.lib.utils import action_logger, jsonify
 from kallithea.lib.vcs.utils import safe_str
-from kallithea.lib.vcs.exceptions import EmptyRepositoryError
+from kallithea.lib.vcs.exceptions import EmptyRepositoryError, ChangesetDoesNotExistError
 from kallithea.lib.diffs import LimitedDiffContainer
 from kallithea.model.db import PullRequest, ChangesetStatus, ChangesetComment, \
     PullRequestReviewers, User
@@ -563,7 +563,11 @@
 
         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]
+        try:
+            c.cs_ranges = [org_scm_instance.get_changeset(x)
+                           for x in c.pull_request.revisions]
+        except ChangesetDoesNotExistError:
+            c.cs_ranges = []
         c.cs_ranges_org = None # not stored and not important and moving target - could be calculated ...
         revs = [ctx.revision for ctx in reversed(c.cs_ranges)]
         c.jsdata = json.dumps(graph_data(org_scm_instance, revs))
@@ -581,58 +585,62 @@
         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 ?
-            c.a_branch_name = c.a_ref_name
-            if c.a_ref_type != 'branch':
-                try:
-                    c.a_branch_name = other_scm_instance.get_changeset(c.a_ref_name).branch # use ref_type ?
-                except EmptyRepositoryError:
-                    c.a_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 descendant of target ref name
-            if not c.is_range and other_scm_instance._repo.revs('present(%s)::&%s', c.cs_ranges[-1].raw_id, c.a_branch_name):
-                c.update_msg = _('This pull request has already been merged to %s.') % c.a_branch_name
-            elif c.pull_request.is_closed():
-                c.update_msg = _('This pull request has been closed and can not be updated.')
-            else: # look for descendants of PR head on source branch in org repo
-                avail_revs = org_scm_instance._repo.revs('%s:: & branch(%s)',
-                                                         revs[0], c.cs_branch_name)
-                if len(avail_revs) > 1: # more than just revs[0]
-                    # also show changesets that not are descendants but would be merged in
-                    targethead = other_scm_instance.get_changeset(c.a_branch_name).raw_id
-                    if org_scm_instance.path != other_scm_instance.path:
-                        # Note: org_scm_instance.path must come first so all
-                        # valid revision numbers are 100% org_scm compatible
-                        # - both for avail_revs and for revset results
-                        hgrepo = unionrepo.unionrepository(org_scm_instance.baseui,
-                                                           org_scm_instance.path,
-                                                           other_scm_instance.path)
+        try:
+            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 ?
+                c.a_branch_name = c.a_ref_name
+                if c.a_ref_type != 'branch':
+                    try:
+                        c.a_branch_name = other_scm_instance.get_changeset(c.a_ref_name).branch # use ref_type ?
+                    except EmptyRepositoryError:
+                        c.a_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 descendant of target ref name
+                if not c.is_range and other_scm_instance._repo.revs('present(%s)::&%s', c.cs_ranges[-1].raw_id, c.a_branch_name):
+                    c.update_msg = _('This pull request has already been merged to %s.') % c.a_branch_name
+                elif c.pull_request.is_closed():
+                    c.update_msg = _('This pull request has been closed and can not be updated.')
+                else: # look for descendants of PR head on source branch in org repo
+                    avail_revs = org_scm_instance._repo.revs('%s:: & branch(%s)',
+                                                             revs[0], c.cs_branch_name)
+                    if len(avail_revs) > 1: # more than just revs[0]
+                        # also show changesets that not are descendants but would be merged in
+                        targethead = other_scm_instance.get_changeset(c.a_branch_name).raw_id
+                        if org_scm_instance.path != other_scm_instance.path:
+                            # Note: org_scm_instance.path must come first so all
+                            # valid revision numbers are 100% org_scm compatible
+                            # - both for avail_revs and for revset results
+                            hgrepo = unionrepo.unionrepository(org_scm_instance.baseui,
+                                                               org_scm_instance.path,
+                                                               other_scm_instance.path)
+                        else:
+                            hgrepo = org_scm_instance._repo
+                        show = set(hgrepo.revs('::%ld & !::parents(%s) & !::%s',
+                                               avail_revs, revs[0], targethead))
+                        c.update_msg = _('The following changes are available on %s:') % c.cs_branch_name
                     else:
-                        hgrepo = org_scm_instance._repo
-                    show = set(hgrepo.revs('::%ld & !::parents(%s) & !::%s',
-                                           avail_revs, revs[0], targethead))
-                    c.update_msg = _('The following changes are available on %s:') % c.cs_branch_name
-                else:
-                    show = set()
-                    avail_revs = set() # drop revs[0]
-                    c.update_msg = _('No changesets found for updating this pull request.')
+                        show = set()
+                        avail_revs = set() # drop revs[0]
+                        c.update_msg = _('No changesets found for updating this pull request.')
 
-                # TODO: handle branch heads that not are tip-most
-                brevs = org_scm_instance._repo.revs('%s - %ld - %s', c.cs_branch_name, avail_revs, revs[0])
-                if brevs:
-                    # also show changesets that are on branch but neither ancestors nor descendants
-                    show.update(org_scm_instance._repo.revs('::%ld - ::%ld - ::%s', brevs, avail_revs, c.a_branch_name))
-                    show.add(revs[0]) # make sure graph shows this so we can see how they relate
-                    c.update_msg_other = _('Note: Branch %s has another head: %s.') % (c.cs_branch_name,
-                        h.short_id(org_scm_instance.get_changeset((max(brevs))).raw_id))
+                    # TODO: handle branch heads that not are tip-most
+                    brevs = org_scm_instance._repo.revs('%s - %ld - %s', c.cs_branch_name, avail_revs, revs[0])
+                    if brevs:
+                        # also show changesets that are on branch but neither ancestors nor descendants
+                        show.update(org_scm_instance._repo.revs('::%ld - ::%ld - ::%s', brevs, avail_revs, c.a_branch_name))
+                        show.add(revs[0]) # make sure graph shows this so we can see how they relate
+                        c.update_msg_other = _('Note: Branch %s has another head: %s.') % (c.cs_branch_name,
+                            h.short_id(org_scm_instance.get_changeset((max(brevs))).raw_id))
 
-                avail_show = sorted(show, reverse=True)
+                    avail_show = sorted(show, reverse=True)
 
-        elif org_scm_instance.alias == 'git':
-            c.update_msg = _("Git pull requests don't support updates yet.")
+            elif org_scm_instance.alias == 'git':
+                c.cs_repo.scm_instance.get_changeset(c.cs_rev) # check it exists - raise ChangesetDoesNotExistError if not
+                c.update_msg = _("Git pull requests don't support updates yet.")
+        except ChangesetDoesNotExistError:
+            c.update_msg = _('Error: revision %s was not found. Please create a new pull request!') % c.cs_rev
 
         c.avail_revs = avail_revs
         c.avail_cs = [org_scm_instance.get_changeset(r) for r in avail_show]
@@ -652,10 +660,12 @@
         # we swap org/other ref since we run a simple diff on one repo
         log.debug('running diff between %s and %s in %s',
                   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),
-                                      ignore_whitespace=ignore_whitespace,
-                                      context=line_context)
-
+        try:
+            txtdiff = org_scm_instance.get_diff(rev1=safe_str(c.a_rev), rev2=safe_str(c.cs_rev),
+                                                ignore_whitespace=ignore_whitespace,
+                                                context=line_context)
+        except ChangesetDoesNotExistError:
+            txtdiff =  _("The diff can't be shown - the PR revisions could not be found.")
         diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
                                              diff_limit=diff_limit)
         _parsed = diff_processor.prepare()