##// END OF EJS Templates
pull-requests: expose unresolved files in merge response.
marcink -
r4080:df62e32a default
parent child Browse files
Show More
@@ -153,7 +153,7 b' class MergeResponse(object):'
153 153 u'This pull request cannot be merged because of an unhandled exception. '
154 154 u'{exception}'),
155 155 MergeFailureReason.MERGE_FAILED: lazy_ugettext(
156 u'This pull request cannot be merged because of merge conflicts.'),
156 u'This pull request cannot be merged because of merge conflicts. {unresolved_files}'),
157 157 MergeFailureReason.PUSH_FAILED: lazy_ugettext(
158 158 u'This pull request could not be merged because push to '
159 159 u'target:`{target}@{merge_commit}` failed.'),
@@ -42,7 +42,7 b' from rhodecode.lib.vcs.backends.git.diff'
42 42 from rhodecode.lib.vcs.backends.git.inmemory import GitInMemoryCommit
43 43 from rhodecode.lib.vcs.exceptions import (
44 44 CommitDoesNotExistError, EmptyRepositoryError,
45 RepositoryError, TagAlreadyExistError, TagDoesNotExistError, VCSError)
45 RepositoryError, TagAlreadyExistError, TagDoesNotExistError, VCSError, UnresolvedFilesInRepo)
46 46
47 47
48 48 SHA_PATTERN = re.compile(r'^[[0-9a-fA-F]{12}|[0-9a-fA-F]{40}]$')
@@ -826,9 +826,10 b' class GitRepository(BaseRepository):'
826 826 return
827 827
828 828 if self.is_empty():
829 # TODO(skreft): do somehting more robust in this case.
829 # TODO(skreft): do something more robust in this case.
830 830 raise RepositoryError(
831 831 'Do not know how to merge into empty repositories yet')
832 unresolved = None
832 833
833 834 # N.B.(skreft): the --no-ff option is used to enforce the creation of a
834 835 # commit message. We also specify the user who is doing the merge.
@@ -839,9 +840,18 b' class GitRepository(BaseRepository):'
839 840 try:
840 841 output = self.run_git_command(cmd, fail_on_stderr=False)
841 842 except RepositoryError:
843 files = self.run_git_command(['diff', '--name-only', '--diff-filter', 'U'],
844 fail_on_stderr=False)[0].splitlines()
845 # NOTE(marcink): we add U notation for consistent with HG backend output
846 unresolved = ['U {}'.format(f) for f in files]
847
842 848 # Cleanup any merge leftovers
843 849 self.run_git_command(['merge', '--abort'], fail_on_stderr=False)
844 raise
850
851 if unresolved:
852 raise UnresolvedFilesInRepo(unresolved)
853 else:
854 raise
845 855
846 856 def _local_push(
847 857 self, source_branch, repository_path, target_branch,
@@ -977,8 +987,11 b' class GitRepository(BaseRepository):'
977 987 # the shadow repository.
978 988 shadow_repo.set_refs('refs/heads/pr-merge', merge_commit_id)
979 989 merge_ref = Reference('branch', 'pr-merge', merge_commit_id)
980 except RepositoryError:
990 except RepositoryError as e:
981 991 log.exception('Failure when doing local merge on git shadow repo')
992 if isinstance(e, UnresolvedFilesInRepo):
993 metadata['unresolved_files'] = 'file: ' + (', file: '.join(e.args[0]))
994
982 995 merge_possible = False
983 996 merge_failure_reason = MergeFailureReason.MERGE_FAILED
984 997
@@ -42,7 +42,7 b' from rhodecode.lib.vcs.backends.hg.diff '
42 42 from rhodecode.lib.vcs.backends.hg.inmemory import MercurialInMemoryCommit
43 43 from rhodecode.lib.vcs.exceptions import (
44 44 EmptyRepositoryError, RepositoryError, TagAlreadyExistError,
45 TagDoesNotExistError, CommitDoesNotExistError, SubrepoMergeError)
45 TagDoesNotExistError, CommitDoesNotExistError, SubrepoMergeError, UnresolvedFilesInRepo)
46 46 from rhodecode.lib.vcs.compat import configparser
47 47
48 48 hexlify = binascii.hexlify
@@ -634,6 +634,7 b' class MercurialRepository(BaseRepository'
634 634 # In this case we should force a commit message
635 635 return source_ref.commit_id, True
636 636
637 unresolved = None
637 638 if use_rebase:
638 639 try:
639 640 bookmark_name = 'rcbook%s%s' % (source_ref.commit_id,
@@ -644,17 +645,23 b' class MercurialRepository(BaseRepository'
644 645 self._remote.invalidate_vcs_cache()
645 646 self._update(bookmark_name, clean=True)
646 647 return self._identify(), True
647 except RepositoryError:
648 except RepositoryError as e:
648 649 # The rebase-abort may raise another exception which 'hides'
649 650 # the original one, therefore we log it here.
650 651 log.exception('Error while rebasing shadow repo during merge.')
652 if 'unresolved conflicts' in e.message:
653 unresolved = self._remote.get_unresolved_files()
654 log.debug('unresolved files: %s', unresolved)
651 655
652 656 # Cleanup any rebase leftovers
653 657 self._remote.invalidate_vcs_cache()
654 658 self._remote.rebase(abort=True)
655 659 self._remote.invalidate_vcs_cache()
656 660 self._remote.update(clean=True)
657 raise
661 if unresolved:
662 raise UnresolvedFilesInRepo(unresolved)
663 else:
664 raise
658 665 else:
659 666 try:
660 667 self._remote.merge(source_ref.commit_id)
@@ -664,10 +671,20 b' class MercurialRepository(BaseRepository'
664 671 username=safe_str('%s <%s>' % (user_name, user_email)))
665 672 self._remote.invalidate_vcs_cache()
666 673 return self._identify(), True
667 except RepositoryError:
674 except RepositoryError as e:
675 # The merge-abort may raise another exception which 'hides'
676 # the original one, therefore we log it here.
677 log.exception('Error while merging shadow repo during merge.')
678 if 'unresolved merge conflicts' in e.message:
679 unresolved = self._remote.get_unresolved_files()
680 log.debug('unresolved files: %s', unresolved)
681
668 682 # Cleanup any merge leftovers
669 683 self._remote.update(clean=True)
670 raise
684 if unresolved:
685 raise UnresolvedFilesInRepo(unresolved)
686 else:
687 raise
671 688
672 689 def _local_close(self, target_ref, user_name, user_email,
673 690 source_ref, close_message=''):
@@ -810,8 +827,11 b' class MercurialRepository(BaseRepository'
810 827 merge_possible = False
811 828 merge_failure_reason = MergeFailureReason.SUBREPO_MERGE_FAILED
812 829 needs_push = False
813 except RepositoryError:
830 except RepositoryError as e:
814 831 log.exception('Failure when doing local merge on hg shadow repo')
832 if isinstance(e, UnresolvedFilesInRepo):
833 metadata['unresolved_files'] = 'file: ' + (', file: '.join(e.args[0]))
834
815 835 merge_possible = False
816 836 merge_failure_reason = MergeFailureReason.MERGE_FAILED
817 837 needs_push = False
@@ -50,6 +50,10 b' class RepositoryRequirementError(Reposit'
50 50 pass
51 51
52 52
53 class UnresolvedFilesInRepo(RepositoryError):
54 pass
55
56
53 57 class VCSBackendNotSupportedError(VCSError):
54 58 """
55 59 Exception raised when VCSServer does not support requested backend
@@ -1335,6 +1335,7 b' class PullRequestModel(BaseModel):'
1335 1335 else:
1336 1336 possible = pull_request.last_merge_status == MergeFailureReason.NONE
1337 1337 metadata = {
1338 'unresolved_files': '',
1338 1339 'target_ref': pull_request.target_ref_parts,
1339 1340 'source_ref': pull_request.source_ref_parts,
1340 1341 }
@@ -191,7 +191,8 b' class TestPullRequestModel(object):'
191 191
192 192 def test_merge_status_known_failure(self, pull_request):
193 193 self.merge_mock.return_value = MergeResponse(
194 False, False, None, MergeFailureReason.MERGE_FAILED)
194 False, False, None, MergeFailureReason.MERGE_FAILED,
195 metadata={'unresolved_files': 'file1'})
195 196
196 197 assert pull_request._last_merge_source_rev is None
197 198 assert pull_request._last_merge_target_rev is None
@@ -199,7 +200,7 b' class TestPullRequestModel(object):'
199 200
200 201 status, msg = PullRequestModel().merge_status(pull_request)
201 202 assert status is False
202 assert msg == 'This pull request cannot be merged because of merge conflicts.'
203 assert msg == 'This pull request cannot be merged because of merge conflicts. file1'
203 204 self.merge_mock.assert_called_with(
204 205 self.repo_id, self.workspace_id,
205 206 pull_request.target_ref_parts,
@@ -209,13 +210,12 b' class TestPullRequestModel(object):'
209 210
210 211 assert pull_request._last_merge_source_rev == self.source_commit
211 212 assert pull_request._last_merge_target_rev == self.target_commit
212 assert (
213 pull_request.last_merge_status is MergeFailureReason.MERGE_FAILED)
213 assert pull_request.last_merge_status is MergeFailureReason.MERGE_FAILED
214 214
215 215 self.merge_mock.reset_mock()
216 216 status, msg = PullRequestModel().merge_status(pull_request)
217 217 assert status is False
218 assert msg == 'This pull request cannot be merged because of merge conflicts.'
218 assert msg == 'This pull request cannot be merged because of merge conflicts. '
219 219 assert self.merge_mock.called is False
220 220
221 221 def test_merge_status_unknown_failure(self, pull_request):
@@ -518,7 +518,7 b' def test_outdated_comments('
518 518 (MergeFailureReason.UNKNOWN,
519 519 'This pull request cannot be merged because of an unhandled exception. CRASH'),
520 520 (MergeFailureReason.MERGE_FAILED,
521 'This pull request cannot be merged because of merge conflicts.'),
521 'This pull request cannot be merged because of merge conflicts. CONFLICT_FILE'),
522 522 (MergeFailureReason.PUSH_FAILED,
523 523 'This pull request could not be merged because push to target:`some-repo@merge_commit` failed.'),
524 524 (MergeFailureReason.TARGET_IS_NOT_HEAD,
@@ -540,13 +540,15 b' def test_outdated_comments('
540 540 def test_merge_response_message(mr_type, expected_msg):
541 541 merge_ref = Reference('type', 'ref_name', '6126b7bfcc82ad2d3deaee22af926b082ce54cc6')
542 542 metadata = {
543 'unresolved_files': 'CONFLICT_FILE',
543 544 'exception': "CRASH",
544 545 'target': 'some-repo',
545 546 'merge_commit': 'merge_commit',
546 547 'target_ref': merge_ref,
547 548 'source_ref': merge_ref,
548 549 'heads': ','.join(['a', 'b', 'c']),
549 'locked_by': 'user:123'}
550 'locked_by': 'user:123'
551 }
550 552
551 553 merge_response = MergeResponse(True, True, merge_ref, mr_type, metadata=metadata)
552 554 assert merge_response.merge_status_message == expected_msg
General Comments 0
You need to be logged in to leave comments. Login now