##// END OF EJS Templates
pull-request-api: updated logic of closing a PR via API call....
marcink -
r1792:a62f3dac default
parent child Browse files
Show More
@@ -43,6 +43,7 b' class TestClosePullRequest(object):'
43 response = api_call(self.app, params)
43 response = api_call(self.app, params)
44 expected = {
44 expected = {
45 'pull_request_id': pull_request_id,
45 'pull_request_id': pull_request_id,
46 'close_status': 'Rejected',
46 'closed': True,
47 'closed': True,
47 }
48 }
48 assert_ok(id_, expected, response.body)
49 assert_ok(id_, expected, response.body)
@@ -21,6 +21,7 b''
21
21
22 import logging
22 import logging
23
23
24 from rhodecode import events
24 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCValidationError
25 from rhodecode.api import jsonrpc_method, JSONRPCError, JSONRPCValidationError
25 from rhodecode.api.utils import (
26 from rhodecode.api.utils import (
26 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
27 has_superadmin_permission, Optional, OAttr, get_repo_or_error,
@@ -35,8 +36,8 b' from rhodecode.model.db import Session, '
35 from rhodecode.model.pull_request import PullRequestModel, MergeCheck
36 from rhodecode.model.pull_request import PullRequestModel, MergeCheck
36 from rhodecode.model.settings import SettingsModel
37 from rhodecode.model.settings import SettingsModel
37 from rhodecode.model.validation_schema import Invalid
38 from rhodecode.model.validation_schema import Invalid
38 from rhodecode.model.validation_schema.schemas.reviewer_schema import \
39 from rhodecode.model.validation_schema.schemas.reviewer_schema import(
39 ReviewerListSchema
40 ReviewerListSchema)
40
41
41 log = logging.getLogger(__name__)
42 log = logging.getLogger(__name__)
42
43
@@ -227,8 +228,9 b' def get_pull_requests(request, apiuser, '
227
228
228
229
229 @jsonrpc_method()
230 @jsonrpc_method()
230 def merge_pull_request(request, apiuser, repoid, pullrequestid,
231 def merge_pull_request(
231 userid=Optional(OAttr('apiuser'))):
232 request, apiuser, repoid, pullrequestid,
233 userid=Optional(OAttr('apiuser'))):
232 """
234 """
233 Merge the pull request specified by `pullrequestid` into its target
235 Merge the pull request specified by `pullrequestid` into its target
234 repository.
236 repository.
@@ -308,63 +310,6 b' def merge_pull_request(request, apiuser,'
308
310
309
311
310 @jsonrpc_method()
312 @jsonrpc_method()
311 def close_pull_request(request, apiuser, repoid, pullrequestid,
312 userid=Optional(OAttr('apiuser'))):
313 """
314 Close the pull request specified by `pullrequestid`.
315
316 :param apiuser: This is filled automatically from the |authtoken|.
317 :type apiuser: AuthUser
318 :param repoid: Repository name or repository ID to which the pull
319 request belongs.
320 :type repoid: str or int
321 :param pullrequestid: ID of the pull request to be closed.
322 :type pullrequestid: int
323 :param userid: Close the pull request as this user.
324 :type userid: Optional(str or int)
325
326 Example output:
327
328 .. code-block:: bash
329
330 "id": <id_given_in_input>,
331 "result": {
332 "pull_request_id": "<int>",
333 "closed": "<bool>"
334 },
335 "error": null
336
337 """
338 repo = get_repo_or_error(repoid)
339 if not isinstance(userid, Optional):
340 if (has_superadmin_permission(apiuser) or
341 HasRepoPermissionAnyApi('repository.admin')(
342 user=apiuser, repo_name=repo.repo_name)):
343 apiuser = get_user_or_error(userid)
344 else:
345 raise JSONRPCError('userid is not the same as your user')
346
347 pull_request = get_pull_request_or_error(pullrequestid)
348 if not PullRequestModel().check_user_update(
349 pull_request, apiuser, api=True):
350 raise JSONRPCError(
351 'pull request `%s` close failed, no permission to close.' % (
352 pullrequestid,))
353 if pull_request.is_closed():
354 raise JSONRPCError(
355 'pull request `%s` is already closed' % (pullrequestid,))
356
357 PullRequestModel().close_pull_request(
358 pull_request.pull_request_id, apiuser)
359 Session().commit()
360 data = {
361 'pull_request_id': pull_request.pull_request_id,
362 'closed': True,
363 }
364 return data
365
366
367 @jsonrpc_method()
368 def comment_pull_request(
313 def comment_pull_request(
369 request, apiuser, repoid, pullrequestid, message=Optional(None),
314 request, apiuser, repoid, pullrequestid, message=Optional(None),
370 commit_id=Optional(None), status=Optional(None),
315 commit_id=Optional(None), status=Optional(None),
@@ -610,7 +555,7 b' def create_pull_request('
610 def update_pull_request(
555 def update_pull_request(
611 request, apiuser, repoid, pullrequestid, title=Optional(''),
556 request, apiuser, repoid, pullrequestid, title=Optional(''),
612 description=Optional(''), reviewers=Optional(None),
557 description=Optional(''), reviewers=Optional(None),
613 update_commits=Optional(None), close_pull_request=Optional(None)):
558 update_commits=Optional(None)):
614 """
559 """
615 Updates a pull request.
560 Updates a pull request.
616
561
@@ -632,8 +577,6 b' def update_pull_request('
632
577
633 :param update_commits: Trigger update of commits for this pull request
578 :param update_commits: Trigger update of commits for this pull request
634 :type: update_commits: Optional(bool)
579 :type: update_commits: Optional(bool)
635 :param close_pull_request: Close this pull request with rejected state
636 :type: close_pull_request: Optional(bool)
637
580
638 Example output:
581 Example output:
639
582
@@ -675,7 +618,6 b' def update_pull_request('
675 'pull request `%s` update failed, pull request is closed' % (
618 'pull request `%s` update failed, pull request is closed' % (
676 pullrequestid,))
619 pullrequestid,))
677
620
678
679 reviewer_objects = Optional.extract(reviewers) or []
621 reviewer_objects = Optional.extract(reviewers) or []
680 if reviewer_objects:
622 if reviewer_objects:
681 schema = ReviewerListSchema()
623 schema = ReviewerListSchema()
@@ -718,11 +660,6 b' def update_pull_request('
718 [get_user_or_error(n).username for n in removed_reviewers])
660 [get_user_or_error(n).username for n in removed_reviewers])
719 Session().commit()
661 Session().commit()
720
662
721 if str2bool(Optional.extract(close_pull_request)):
722 PullRequestModel().close_pull_request_with_comment(
723 pull_request, apiuser, repo)
724 Session().commit()
725
726 data = {
663 data = {
727 'msg': 'Updated pull request `{}`'.format(
664 'msg': 'Updated pull request `{}`'.format(
728 pull_request.pull_request_id),
665 pull_request.pull_request_id),
@@ -732,3 +669,80 b' def update_pull_request('
732 }
669 }
733
670
734 return data
671 return data
672
673
674 @jsonrpc_method()
675 def close_pull_request(
676 request, apiuser, repoid, pullrequestid,
677 userid=Optional(OAttr('apiuser')), message=Optional('')):
678 """
679 Close the pull request specified by `pullrequestid`.
680
681 :param apiuser: This is filled automatically from the |authtoken|.
682 :type apiuser: AuthUser
683 :param repoid: Repository name or repository ID to which the pull
684 request belongs.
685 :type repoid: str or int
686 :param pullrequestid: ID of the pull request to be closed.
687 :type pullrequestid: int
688 :param userid: Close the pull request as this user.
689 :type userid: Optional(str or int)
690 :param message: Optional message to close the Pull Request with. If not
691 specified it will be generated automatically.
692 :type message: Optional(str)
693
694 Example output:
695
696 .. code-block:: bash
697
698 "id": <id_given_in_input>,
699 "result": {
700 "pull_request_id": "<int>",
701 "close_status": "<str:status_lbl>,
702 "closed": "<bool>"
703 },
704 "error": null
705
706 """
707 _ = request.translate
708
709 repo = get_repo_or_error(repoid)
710 if not isinstance(userid, Optional):
711 if (has_superadmin_permission(apiuser) or
712 HasRepoPermissionAnyApi('repository.admin')(
713 user=apiuser, repo_name=repo.repo_name)):
714 apiuser = get_user_or_error(userid)
715 else:
716 raise JSONRPCError('userid is not the same as your user')
717
718 pull_request = get_pull_request_or_error(pullrequestid)
719
720 if pull_request.is_closed():
721 raise JSONRPCError(
722 'pull request `%s` is already closed' % (pullrequestid,))
723
724 # only owner or admin or person with write permissions
725 allowed_to_close = PullRequestModel().check_user_update(
726 pull_request, apiuser, api=True)
727
728 if not allowed_to_close:
729 raise JSONRPCError(
730 'pull request `%s` close failed, no permission to close.' % (
731 pullrequestid,))
732
733 # message we're using to close the PR, else it's automatically generated
734 message = Optional.extract(message)
735
736 # finally close the PR, with proper message comment
737 comment, status = PullRequestModel().close_pull_request_with_comment(
738 pull_request, apiuser, repo, message=message)
739 status_lbl = ChangesetStatus.get_status_lbl(status)
740
741 Session().commit()
742
743 data = {
744 'pull_request_id': pull_request.pull_request_id,
745 'close_status': status_lbl,
746 'closed': True,
747 }
748 return data
@@ -368,7 +368,6 b' class ChangesetController(BaseRepoContro'
368 comment_type=comment_type,
368 comment_type=comment_type,
369 resolves_comment_id=resolves_comment_id
369 resolves_comment_id=resolves_comment_id
370 )
370 )
371 c.inline_comment = True if comment.line_no else False
372
371
373 # get status if set !
372 # get status if set !
374 if status:
373 if status:
@@ -306,8 +306,6 b' class PullrequestsController(BaseRepoCon'
306 pull_request.reviewer_data)
306 pull_request.reviewer_data)
307 elif str2bool(request.POST.get('update_commits', 'false')):
307 elif str2bool(request.POST.get('update_commits', 'false')):
308 self._update_commits(pull_request)
308 self._update_commits(pull_request)
309 elif str2bool(request.POST.get('close_pull_request', 'false')):
310 self._reject_close(pull_request)
311 elif str2bool(request.POST.get('edit_pull_request', 'false')):
309 elif str2bool(request.POST.get('edit_pull_request', 'false')):
312 self._edit_pull_request(pull_request)
310 self._edit_pull_request(pull_request)
313 else:
311 else:
@@ -462,14 +460,6 b' class PullrequestsController(BaseRepoCon'
462 h.flash(_('Pull request reviewers updated.'), category='success')
460 h.flash(_('Pull request reviewers updated.'), category='success')
463 Session().commit()
461 Session().commit()
464
462
465 def _reject_close(self, pull_request):
466 if pull_request.is_closed():
467 raise HTTPForbidden()
468
469 PullRequestModel().close_pull_request_with_comment(
470 pull_request, c.rhodecode_user, c.rhodecode_db_repo)
471 Session().commit()
472
473 @LoginRequired()
463 @LoginRequired()
474 @NotAnonymous()
464 @NotAnonymous()
475 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
465 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
@@ -888,6 +878,7 b' class PullrequestsController(BaseRepoCon'
888 pull_request_id = safe_int(pull_request_id)
878 pull_request_id = safe_int(pull_request_id)
889 pull_request = PullRequest.get_or_404(pull_request_id)
879 pull_request = PullRequest.get_or_404(pull_request_id)
890 if pull_request.is_closed():
880 if pull_request.is_closed():
881 log.debug('comment: forbidden because pull request is closed')
891 raise HTTPForbidden()
882 raise HTTPForbidden()
892
883
893 status = request.POST.get('changeset_status', None)
884 status = request.POST.get('changeset_status', None)
@@ -896,83 +887,78 b' class PullrequestsController(BaseRepoCon'
896 resolves_comment_id = request.POST.get('resolves_comment_id', None)
887 resolves_comment_id = request.POST.get('resolves_comment_id', None)
897 close_pull_request = request.POST.get('close_pull_request')
888 close_pull_request = request.POST.get('close_pull_request')
898
889
899 close_pr = False
890 # the logic here should work like following, if we submit close
900 # only owner or admin or person with write permissions
891 # pr comment, use `close_pull_request_with_comment` function
901 allowed_to_close = PullRequestModel().check_user_update(
892 # else handle regular comment logic
902 pull_request, c.rhodecode_user)
893 user = c.rhodecode_user
894 repo = c.rhodecode_db_repo
903
895
904 if close_pull_request and allowed_to_close:
896 if close_pull_request:
905 close_pr = True
897 # only owner or admin or person with write permissions
906 pull_request_review_status = pull_request.calculated_review_status()
898 allowed_to_close = PullRequestModel().check_user_update(
907 if pull_request_review_status == ChangesetStatus.STATUS_APPROVED:
899 pull_request, c.rhodecode_user)
908 # approved only if we have voting consent
900 if not allowed_to_close:
909 status = ChangesetStatus.STATUS_APPROVED
901 log.debug('comment: forbidden because not allowed to close '
910 else:
902 'pull request %s', pull_request_id)
911 status = ChangesetStatus.STATUS_REJECTED
903 raise HTTPForbidden()
904 comment, status = PullRequestModel().close_pull_request_with_comment(
905 pull_request, user, repo, message=text)
906 Session().flush()
907 events.trigger(
908 events.PullRequestCommentEvent(pull_request, comment))
912
909
913 allowed_to_change_status = PullRequestModel().check_user_change_status(
910 else:
914 pull_request, c.rhodecode_user)
911 # regular comment case, could be inline, or one with status.
912 # for that one we check also permissions
913
914 allowed_to_change_status = PullRequestModel().check_user_change_status(
915 pull_request, c.rhodecode_user)
916
917 if status and allowed_to_change_status:
918 message = (_('Status change %(transition_icon)s %(status)s')
919 % {'transition_icon': '>',
920 'status': ChangesetStatus.get_status_lbl(status)})
921 text = text or message
915
922
916 if status and allowed_to_change_status:
923 comment = CommentsModel().create(
917 message = (_('Status change %(transition_icon)s %(status)s')
924 text=text,
918 % {'transition_icon': '>',
925 repo=c.rhodecode_db_repo.repo_id,
919 'status': ChangesetStatus.get_status_lbl(status)})
926 user=c.rhodecode_user.user_id,
920 if close_pr:
927 pull_request=pull_request_id,
921 message = _('Closing with') + ' ' + message
928 f_path=request.POST.get('f_path'),
922 text = text or message
929 line_no=request.POST.get('line'),
923 comm = CommentsModel().create(
930 status_change=(ChangesetStatus.get_status_lbl(status)
924 text=text,
931 if status and allowed_to_change_status else None),
925 repo=c.rhodecode_db_repo.repo_id,
932 status_change_type=(status
926 user=c.rhodecode_user.user_id,
933 if status and allowed_to_change_status else None),
927 pull_request=pull_request_id,
934 comment_type=comment_type,
928 f_path=request.POST.get('f_path'),
935 resolves_comment_id=resolves_comment_id
929 line_no=request.POST.get('line'),
936 )
930 status_change=(ChangesetStatus.get_status_lbl(status)
937
931 if status and allowed_to_change_status else None),
938 if allowed_to_change_status:
932 status_change_type=(status
939 # calculate old status before we change it
933 if status and allowed_to_change_status else None),
940 old_calculated_status = pull_request.calculated_review_status()
934 closing_pr=close_pr,
935 comment_type=comment_type,
936 resolves_comment_id=resolves_comment_id
937 )
938
941
939 if allowed_to_change_status:
942 # get status if set !
940 old_calculated_status = pull_request.calculated_review_status()
943 if status:
941 # get status if set !
944 ChangesetStatusModel().set_status(
942 if status:
945 c.rhodecode_db_repo.repo_id,
943 ChangesetStatusModel().set_status(
946 status,
944 c.rhodecode_db_repo.repo_id,
947 c.rhodecode_user.user_id,
945 status,
948 comment,
946 c.rhodecode_user.user_id,
949 pull_request=pull_request_id
947 comm,
950 )
948 pull_request=pull_request_id
949 )
950
951
951 Session().flush()
952 Session().flush()
952 events.trigger(events.PullRequestCommentEvent(pull_request, comm))
953 events.trigger(
953 # we now calculate the status of pull request, and based on that
954 events.PullRequestCommentEvent(pull_request, comment))
954 # calculation we set the commits status
955 calculated_status = pull_request.calculated_review_status()
956 if old_calculated_status != calculated_status:
957 PullRequestModel()._trigger_pull_request_hook(
958 pull_request, c.rhodecode_user, 'review_status_change')
959
960 calculated_status_lbl = ChangesetStatus.get_status_lbl(
961 calculated_status)
962
955
963 if close_pr:
956 # we now calculate the status of pull request, and based on that
964 status_completed = (
957 # calculation we set the commits status
965 calculated_status in [ChangesetStatus.STATUS_APPROVED,
958 calculated_status = pull_request.calculated_review_status()
966 ChangesetStatus.STATUS_REJECTED])
959 if old_calculated_status != calculated_status:
967 if close_pull_request or status_completed:
960 PullRequestModel()._trigger_pull_request_hook(
968 PullRequestModel().close_pull_request(
961 pull_request, c.rhodecode_user, 'review_status_change')
969 pull_request_id, c.rhodecode_user)
970 else:
971 h.flash(_('Closing pull request on other statuses than '
972 'rejected or approved is forbidden. '
973 'Calculated status from all reviewers '
974 'is currently: %s') % calculated_status_lbl,
975 category='warning')
976
962
977 Session().commit()
963 Session().commit()
978
964
@@ -983,12 +969,11 b' class PullrequestsController(BaseRepoCon'
983 data = {
969 data = {
984 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
970 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
985 }
971 }
986 if comm:
972 if comment:
987 c.co = comm
973 c.co = comment
988 c.inline_comment = True if comm.line_no else False
974 rendered_comment = render('changeset/changeset_comment_block.mako')
989 data.update(comm.get_dict())
975 data.update(comment.get_dict())
990 data.update({'rendered_text':
976 data.update({'rendered_text': rendered_comment})
991 render('changeset/changeset_comment_block.mako')})
992
977
993 return data
978 return data
994
979
@@ -3107,6 +3107,10 b' class ChangesetComment(Base, BaseModel):'
3107 def is_todo(self):
3107 def is_todo(self):
3108 return self.comment_type == self.COMMENT_TYPE_TODO
3108 return self.comment_type == self.COMMENT_TYPE_TODO
3109
3109
3110 @property
3111 def is_inline(self):
3112 return self.line_no and self.f_path
3113
3110 def get_index_version(self, versions):
3114 def get_index_version(self, versions):
3111 return self.get_index_from_version(
3115 return self.get_index_from_version(
3112 self.pull_request_version_id, versions)
3116 self.pull_request_version_id, versions)
@@ -34,6 +34,7 b' from pylons.i18n.translation import lazy'
34 from pyramid.threadlocal import get_current_request
34 from pyramid.threadlocal import get_current_request
35 from sqlalchemy import or_
35 from sqlalchemy import or_
36
36
37 from rhodecode import events
37 from rhodecode.lib import helpers as h, hooks_utils, diffs
38 from rhodecode.lib import helpers as h, hooks_utils, diffs
38 from rhodecode.lib.compat import OrderedDict
39 from rhodecode.lib.compat import OrderedDict
39 from rhodecode.lib.hooks_daemon import prepare_callback_daemon
40 from rhodecode.lib.hooks_daemon import prepare_callback_daemon
@@ -1064,42 +1065,61 b' class PullRequestModel(BaseModel):'
1064 pull_request, pull_request.author, 'close')
1065 pull_request, pull_request.author, 'close')
1065 self._log_action('user_closed_pull_request', user, pull_request)
1066 self._log_action('user_closed_pull_request', user, pull_request)
1066
1067
1067 def close_pull_request_with_comment(self, pull_request, user, repo,
1068 def close_pull_request_with_comment(
1068 message=None):
1069 self, pull_request, user, repo, message=None):
1069 status = ChangesetStatus.STATUS_REJECTED
1070
1071 pull_request_review_status = pull_request.calculated_review_status()
1070
1072
1071 if not message:
1073 if pull_request_review_status == ChangesetStatus.STATUS_APPROVED:
1072 message = (
1074 # approved only if we have voting consent
1073 _('Status change %(transition_icon)s %(status)s') % {
1075 status = ChangesetStatus.STATUS_APPROVED
1074 'transition_icon': '>',
1076 else:
1075 'status': ChangesetStatus.get_status_lbl(status)})
1077 status = ChangesetStatus.STATUS_REJECTED
1078 status_lbl = ChangesetStatus.get_status_lbl(status)
1076
1079
1077 internal_message = _('Closing with') + ' ' + message
1080 default_message = (
1081 _('Closing with status change {transition_icon} {status}.')
1082 ).format(transition_icon='>', status=status_lbl)
1083 text = message or default_message
1078
1084
1079 comm = CommentsModel().create(
1085 # create a comment, and link it to new status
1080 text=internal_message,
1086 comment = CommentsModel().create(
1087 text=text,
1081 repo=repo.repo_id,
1088 repo=repo.repo_id,
1082 user=user.user_id,
1089 user=user.user_id,
1083 pull_request=pull_request.pull_request_id,
1090 pull_request=pull_request.pull_request_id,
1084 f_path=None,
1091 status_change=status_lbl,
1085 line_no=None,
1086 status_change=ChangesetStatus.get_status_lbl(status),
1087 status_change_type=status,
1092 status_change_type=status,
1088 closing_pr=True
1093 closing_pr=True
1089 )
1094 )
1090
1095
1096 # calculate old status before we change it
1097 old_calculated_status = pull_request.calculated_review_status()
1091 ChangesetStatusModel().set_status(
1098 ChangesetStatusModel().set_status(
1092 repo.repo_id,
1099 repo.repo_id,
1093 status,
1100 status,
1094 user.user_id,
1101 user.user_id,
1095 comm,
1102 comment=comment,
1096 pull_request=pull_request.pull_request_id
1103 pull_request=pull_request.pull_request_id
1097 )
1104 )
1105
1098 Session().flush()
1106 Session().flush()
1107 events.trigger(events.PullRequestCommentEvent(pull_request, comment))
1108 # we now calculate the status of pull request again, and based on that
1109 # calculation trigger status change. This might happen in cases
1110 # that non-reviewer admin closes a pr, which means his vote doesn't
1111 # change the status, while if he's a reviewer this might change it.
1112 calculated_status = pull_request.calculated_review_status()
1113 if old_calculated_status != calculated_status:
1114 self._trigger_pull_request_hook(
1115 pull_request, user, 'review_status_change')
1099
1116
1117 # finally close the PR
1100 PullRequestModel().close_pull_request(
1118 PullRequestModel().close_pull_request(
1101 pull_request.pull_request_id, user)
1119 pull_request.pull_request_id, user)
1102
1120
1121 return comment, status
1122
1103 def merge_status(self, pull_request):
1123 def merge_status(self, pull_request):
1104 if not self._is_merge_enabled(pull_request):
1124 if not self._is_merge_enabled(pull_request):
1105 return False, _('Server-side pull request merging is disabled.')
1125 return False, _('Server-side pull request merging is disabled.')
@@ -96,6 +96,7 b' function registerRCRoutes() {'
96 pyroutes.register('goto_switcher_data', '/_goto_data', []);
96 pyroutes.register('goto_switcher_data', '/_goto_data', []);
97 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
97 pyroutes.register('repo_summary_explicit', '/%(repo_name)s/summary', ['repo_name']);
98 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
98 pyroutes.register('repo_summary_commits', '/%(repo_name)s/summary-commits', ['repo_name']);
99 pyroutes.register('repo_commit', '/%(repo_name)s/changeset/%(commit_id)s', ['repo_name', 'commit_id']);
99 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
100 pyroutes.register('repo_refs_data', '/%(repo_name)s/refs-data', ['repo_name']);
100 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
101 pyroutes.register('repo_refs_changelog_data', '/%(repo_name)s/refs-data-changelog', ['repo_name']);
101 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
102 pyroutes.register('repo_stats', '/%(repo_name)s/repo_stats/%(commit_id)s', ['repo_name', 'commit_id']);
@@ -368,16 +368,6 b' var _updatePullRequest = function(repo_n'
368 };
368 };
369
369
370 /**
370 /**
371 * PULL REQUEST reject & close
372 */
373 var closePullRequest = function(repo_name, pull_request_id) {
374 var postData = {
375 '_method': 'put',
376 'close_pull_request': true};
377 _updatePullRequest(repo_name, pull_request_id, postData);
378 };
379
380 /**
381 * PULL REQUEST update commits
371 * PULL REQUEST update commits
382 */
372 */
383 var updateCommits = function(repo_name, pull_request_id) {
373 var updateCommits = function(repo_name, pull_request_id) {
@@ -1,4 +1,4 b''
1 ## this is a dummy html file for partial rendering on server and sending
1 ## this is a dummy html file for partial rendering on server and sending
2 ## generated output via ajax after comment submit
2 ## generated output via ajax after comment submit
3 <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
3 <%namespace name="comment" file="/changeset/changeset_file_comment.mako"/>
4 ${comment.comment_block(c.co, inline=c.inline_comment)}
4 ${comment.comment_block(c.co, inline=c.co.is_inline)}
@@ -949,9 +949,6 b''
949 updateCommits("rhodecode-momentum", "720");
949 updateCommits("rhodecode-momentum", "720");
950 });
950 });
951
951
952 $('#close_pull_request').on('click', function(e){
953 closePullRequest("rhodecode-momentum", "720");
954 });
955 })
952 })
956 </script>
953 </script>
957
954
@@ -825,11 +825,6 b''
825 // fixing issue with caches on firefox
825 // fixing issue with caches on firefox
826 $('#update_commits').removeAttr("disabled");
826 $('#update_commits').removeAttr("disabled");
827
827
828 $('#close_pull_request').on('click', function(e){
829 closePullRequest(
830 "${c.repo_name}", "${c.pull_request.pull_request_id}");
831 });
832
833 $('.show-inline-comments').on('click', function(e){
828 $('.show-inline-comments').on('click', function(e){
834 var boxid = $(this).attr('data-comment-id');
829 var boxid = $(this).attr('data-comment-id');
835 var button = $(this);
830 var button = $(this);
@@ -237,7 +237,9 b' class TestPullrequestsController(object)'
237 assertr.element_contains(
237 assertr.element_contains(
238 'span[data-role="merge-message"]', str(expected_msg))
238 'span[data-role="merge-message"]', str(expected_msg))
239
239
240 def test_comment_and_close_pull_request(self, pr_util, csrf_token):
240 def test_comment_and_close_pull_request_custom_message_approved(
241 self, pr_util, csrf_token, xhr_header):
242
241 pull_request = pr_util.create_pull_request(approved=True)
243 pull_request = pr_util.create_pull_request(approved=True)
242 pull_request_id = pull_request.pull_request_id
244 pull_request_id = pull_request.pull_request_id
243 author = pull_request.user_id
245 author = pull_request.user_id
@@ -249,11 +251,10 b' class TestPullrequestsController(object)'
249 repo_name=pull_request.target_repo.scm_instance().name,
251 repo_name=pull_request.target_repo.scm_instance().name,
250 pull_request_id=str(pull_request_id)),
252 pull_request_id=str(pull_request_id)),
251 params={
253 params={
252 'changeset_status': ChangesetStatus.STATUS_APPROVED,
253 'close_pull_request': '1',
254 'close_pull_request': '1',
254 'text': 'Closing a PR',
255 'text': 'Closing a PR',
255 'csrf_token': csrf_token},
256 'csrf_token': csrf_token},
256 status=302)
257 extra_environ=xhr_header,)
257
258
258 action = 'user_closed_pull_request:%d' % pull_request_id
259 action = 'user_closed_pull_request:%d' % pull_request_id
259 journal = UserLog.query()\
260 journal = UserLog.query()\
@@ -270,45 +271,26 b' class TestPullrequestsController(object)'
270 status = ChangesetStatusModel().get_status(
271 status = ChangesetStatusModel().get_status(
271 pull_request.source_repo, pull_request=pull_request)
272 pull_request.source_repo, pull_request=pull_request)
272 assert status == ChangesetStatus.STATUS_APPROVED
273 assert status == ChangesetStatus.STATUS_APPROVED
273
274 assert pull_request.comments[-1].text == 'Closing a PR'
274 def test_reject_and_close_pull_request(self, pr_util, csrf_token):
275 pull_request = pr_util.create_pull_request()
276 pull_request_id = pull_request.pull_request_id
277 response = self.app.post(
278 url(controller='pullrequests',
279 action='update',
280 repo_name=pull_request.target_repo.scm_instance().name,
281 pull_request_id=str(pull_request.pull_request_id)),
282 params={'close_pull_request': 'true', '_method': 'put',
283 'csrf_token': csrf_token})
284
275
285 pull_request = PullRequest.get(pull_request_id)
276 def test_comment_force_close_pull_request_rejected(
286
277 self, pr_util, csrf_token, xhr_header):
287 assert response.json is True
288 assert pull_request.is_closed()
289
290 # check only the latest status, not the review status
291 status = ChangesetStatusModel().get_status(
292 pull_request.source_repo, pull_request=pull_request)
293 assert status == ChangesetStatus.STATUS_REJECTED
294
295 def test_comment_force_close_pull_request(self, pr_util, csrf_token):
296 pull_request = pr_util.create_pull_request()
278 pull_request = pr_util.create_pull_request()
297 pull_request_id = pull_request.pull_request_id
279 pull_request_id = pull_request.pull_request_id
298 PullRequestModel().update_reviewers(
280 PullRequestModel().update_reviewers(
299 pull_request_id, [(1, ['reason'], False), (2, ['reason2'], False)])
281 pull_request_id, [(1, ['reason'], False), (2, ['reason2'], False)])
300 author = pull_request.user_id
282 author = pull_request.user_id
301 repo = pull_request.target_repo.repo_id
283 repo = pull_request.target_repo.repo_id
284
302 self.app.post(
285 self.app.post(
303 url(controller='pullrequests',
286 url(controller='pullrequests',
304 action='comment',
287 action='comment',
305 repo_name=pull_request.target_repo.scm_instance().name,
288 repo_name=pull_request.target_repo.scm_instance().name,
306 pull_request_id=str(pull_request_id)),
289 pull_request_id=str(pull_request_id)),
307 params={
290 params={
308 'changeset_status': 'rejected',
309 'close_pull_request': '1',
291 'close_pull_request': '1',
310 'csrf_token': csrf_token},
292 'csrf_token': csrf_token},
311 status=302)
293 extra_environ=xhr_header)
312
294
313 pull_request = PullRequest.get(pull_request_id)
295 pull_request = PullRequest.get(pull_request_id)
314
296
@@ -324,6 +306,31 b' class TestPullrequestsController(object)'
324 pull_request.source_repo, pull_request=pull_request)
306 pull_request.source_repo, pull_request=pull_request)
325 assert status == ChangesetStatus.STATUS_REJECTED
307 assert status == ChangesetStatus.STATUS_REJECTED
326
308
309 def test_comment_and_close_pull_request(
310 self, pr_util, csrf_token, xhr_header):
311 pull_request = pr_util.create_pull_request()
312 pull_request_id = pull_request.pull_request_id
313
314 response = self.app.post(
315 url(controller='pullrequests',
316 action='comment',
317 repo_name=pull_request.target_repo.scm_instance().name,
318 pull_request_id=str(pull_request.pull_request_id)),
319 params={
320 'close_pull_request': 'true',
321 'csrf_token': csrf_token},
322 extra_environ=xhr_header)
323
324 assert response.json
325
326 pull_request = PullRequest.get(pull_request_id)
327 assert pull_request.is_closed()
328
329 # check only the latest status, not the review status
330 status = ChangesetStatusModel().get_status(
331 pull_request.source_repo, pull_request=pull_request)
332 assert status == ChangesetStatus.STATUS_REJECTED
333
327 def test_create_pull_request(self, backend, csrf_token):
334 def test_create_pull_request(self, backend, csrf_token):
328 commits = [
335 commits = [
329 {'message': 'ancestor'},
336 {'message': 'ancestor'},
General Comments 0
You need to be logged in to leave comments. Login now