Show More
@@ -0,0 +1,37 b'' | |||
|
1 | ||
|
2 | <div class="pull-request-wrap"> | |
|
3 | ||
|
4 | <ul> | |
|
5 | % for pr_check_type, pr_check_msg in c.pr_merge_checks: | |
|
6 | <li> | |
|
7 | <span class="merge-message ${pr_check_type}" data-role="merge-message"> | |
|
8 | % if pr_check_type in ['success']: | |
|
9 | <i class="icon-true"></i> | |
|
10 | % else: | |
|
11 | <i class="icon-false"></i> | |
|
12 | % endif | |
|
13 | ${pr_check_msg} | |
|
14 | </span> | |
|
15 | </li> | |
|
16 | % endfor | |
|
17 | </ul> | |
|
18 | ||
|
19 | <div class="pull-request-merge-actions"> | |
|
20 | % if c.allowed_to_merge: | |
|
21 | <div class="pull-right"> | |
|
22 | ${h.secure_form(url('pullrequest_merge', repo_name=c.repo_name, pull_request_id=c.pull_request.pull_request_id), id='merge_pull_request_form')} | |
|
23 | <% merge_disabled = ' disabled' if c.pr_merge_status is False else '' %> | |
|
24 | <a class="btn" href="#" onclick="refreshMergeChecks(); return false;">${_('refresh checks')}</a> | |
|
25 | <input type="submit" id="merge_pull_request" value="${_('Merge Pull Request')}" class="btn${merge_disabled}"${merge_disabled}> | |
|
26 | ${h.end_form()} | |
|
27 | </div> | |
|
28 | % elif c.rhodecode_user.username != h.DEFAULT_USER: | |
|
29 | <a class="btn" href="#" onclick="refreshMergeChecks(); return false;">${_('refresh checks')}</a> | |
|
30 | <input type="submit" value="${_('Merge Pull Request')}" class="btn disabled" disabled="disabled" title="${_('You are not allowed to merge this pull request.')}"> | |
|
31 | % else: | |
|
32 | <input type="submit" value="${_('Login to Merge this Pull Request')}" class="btn disabled" disabled="disabled"> | |
|
33 | % endif | |
|
34 | </div> | |
|
35 | ||
|
36 | </div> | |
|
37 |
@@ -633,6 +633,18 b' class PullrequestsController(BaseRepoCon' | |||
|
633 | 633 | msg = _('Pull request reviewer approval is pending.') |
|
634 | 634 | h.flash(msg, category='error') |
|
635 | 635 | return False |
|
636 | ||
|
637 | todos = CommentsModel().get_unresolved_todos(pull_request) | |
|
638 | if todos: | |
|
639 | log.debug("Cannot merge, unresolved todos left.") | |
|
640 | if len(todos) == 1: | |
|
641 | msg = _('Cannot merge, {} todo still not resolved.').format( | |
|
642 | len(todos)) | |
|
643 | else: | |
|
644 | msg = _('Cannot merge, {} todos still not resolved.').format( | |
|
645 | len(todos)) | |
|
646 | h.flash(msg, category='error') | |
|
647 | return False | |
|
636 | 648 | return True |
|
637 | 649 | |
|
638 | 650 | def _merge_pull_request(self, pull_request, user, extras): |
@@ -761,6 +773,7 b' class PullrequestsController(BaseRepoCon' | |||
|
761 | 773 | def show(self, repo_name, pull_request_id): |
|
762 | 774 | pull_request_id = safe_int(pull_request_id) |
|
763 | 775 | version = request.GET.get('version') |
|
776 | merge_checks = request.GET.get('merge_checks') | |
|
764 | 777 | |
|
765 | 778 | (pull_request_latest, |
|
766 | 779 | pull_request_at_ver, |
@@ -778,6 +791,10 b' class PullrequestsController(BaseRepoCon' | |||
|
778 | 791 | c.shadow_clone_url = PullRequestModel().get_shadow_clone_url( |
|
779 | 792 | pull_request_at_ver) |
|
780 | 793 | |
|
794 | c.ancestor = None # TODO: add ancestor here | |
|
795 | c.pull_request = pull_request_display_obj | |
|
796 | c.pull_request_latest = pull_request_latest | |
|
797 | ||
|
781 | 798 | pr_closed = pull_request_latest.is_closed() |
|
782 | 799 | if at_version and not at_version == 'latest': |
|
783 | 800 | c.allowed_to_change_status = False |
@@ -800,12 +817,6 b' class PullrequestsController(BaseRepoCon' | |||
|
800 | 817 | |
|
801 | 818 | c.pull_request_reviewers = pull_request_at_ver.reviewers_statuses() |
|
802 | 819 | c.pull_request_review_status = pull_request_at_ver.calculated_review_status() |
|
803 | c.pr_merge_status, c.pr_merge_msg = PullRequestModel().merge_status( | |
|
804 | pull_request_at_ver) | |
|
805 | c.approval_msg = None | |
|
806 | if c.pull_request_review_status != ChangesetStatus.STATUS_APPROVED: | |
|
807 | c.approval_msg = _('Reviewer approval is pending.') | |
|
808 | c.pr_merge_status = False | |
|
809 | 820 | |
|
810 | 821 | c.versions = pull_request_display_obj.versions() |
|
811 | 822 | c.at_version = at_version |
@@ -830,7 +841,7 b' class PullrequestsController(BaseRepoCon' | |||
|
830 | 841 | |
|
831 | 842 | # if we use version, then do not show later comments |
|
832 | 843 | # than current version |
|
833 |
pat |
|
|
844 | display_inline_comments = collections.defaultdict(lambda: collections.defaultdict(list)) | |
|
834 | 845 | for co in inline_comments: |
|
835 | 846 | if c.at_version_num: |
|
836 | 847 | # pick comments that are at least UPTO given version, so we |
@@ -842,11 +853,32 b' class PullrequestsController(BaseRepoCon' | |||
|
842 | 853 | should_render = True |
|
843 | 854 | |
|
844 | 855 | if should_render: |
|
845 |
pat |
|
|
846 | inline_comments = paths | |
|
856 | display_inline_comments[co.f_path][co.line_no].append(co) | |
|
857 | ||
|
858 | c.pr_merge_checks = [] | |
|
859 | c.pr_merge_status, c.pr_merge_msg = PullRequestModel().merge_status( | |
|
860 | pull_request_at_ver) | |
|
861 | c.pr_merge_checks.append(['warning' if not c.pr_merge_status else 'success', c.pr_merge_msg]) | |
|
862 | ||
|
863 | if c.pull_request_review_status != ChangesetStatus.STATUS_APPROVED: | |
|
864 | approval_msg = _('Reviewer approval is pending.') | |
|
865 | c.pr_merge_status = False | |
|
866 | c.pr_merge_checks.append(['warning', approval_msg]) | |
|
867 | ||
|
868 | todos = cc_model.get_unresolved_todos(pull_request_latest) | |
|
869 | if todos: | |
|
870 | c.pr_merge_status = False | |
|
871 | if len(todos) == 1: | |
|
872 | msg = _('{} todo still not resolved.').format(len(todos)) | |
|
873 | else: | |
|
874 | msg = _('{} todos still not resolved.').format(len(todos)) | |
|
875 | c.pr_merge_checks.append(['warning', msg]) | |
|
876 | ||
|
877 | if merge_checks: | |
|
878 | return render('/pullrequests/pullrequest_merge_checks.mako') | |
|
847 | 879 | |
|
848 | 880 | # load compare data into template context |
|
849 | self._load_compare_data(pull_request_at_ver, inline_comments) | |
|
881 | self._load_compare_data(pull_request_at_ver, display_inline_comments) | |
|
850 | 882 | |
|
851 | 883 | # this is a hack to properly display links, when creating PR, the |
|
852 | 884 | # compare view and others uses different notation, and |
@@ -861,10 +893,6 b' class PullrequestsController(BaseRepoCon' | |||
|
861 | 893 | statuses = ChangesetStatus.STATUSES |
|
862 | 894 | c.commit_statuses = statuses |
|
863 | 895 | |
|
864 | c.ancestor = None # TODO: add ancestor here | |
|
865 | c.pull_request = pull_request_display_obj | |
|
866 | c.pull_request_latest = pull_request_latest | |
|
867 | ||
|
868 | 896 | c.changes = None |
|
869 | 897 | c.file_changes = None |
|
870 | 898 |
@@ -129,6 +129,18 b' class CommentsModel(BaseModel):' | |||
|
129 | 129 | |
|
130 | 130 | return comment_versions |
|
131 | 131 | |
|
132 | def get_unresolved_todos(self, pull_request): | |
|
133 | ||
|
134 | todos = Session().query(ChangesetComment) \ | |
|
135 | .filter(ChangesetComment.pull_request == pull_request) \ | |
|
136 | .filter(ChangesetComment.resolved_by == None) \ | |
|
137 | .filter(ChangesetComment.comment_type | |
|
138 | == ChangesetComment.COMMENT_TYPE_TODO) \ | |
|
139 | .filter(coalesce(ChangesetComment.display_state, '') != | |
|
140 | ChangesetComment.COMMENT_OUTDATED).all() | |
|
141 | ||
|
142 | return todos | |
|
143 | ||
|
132 | 144 | def create(self, text, repo, user, commit_id=None, pull_request=None, |
|
133 | 145 | f_path=None, line_no=None, status_change=None, |
|
134 | 146 | status_change_type=None, comment_type=None, |
@@ -2972,6 +2972,10 b' class ChangesetComment(Base, BaseModel):' | |||
|
2972 | 2972 | def resolved(self): |
|
2973 | 2973 | return self.resolved_by[0] if self.resolved_by else None |
|
2974 | 2974 | |
|
2975 | @property | |
|
2976 | def is_todo(self): | |
|
2977 | return self.comment_type == self.COMMENT_TYPE_TODO | |
|
2978 | ||
|
2975 | 2979 | def get_index_version(self, versions): |
|
2976 | 2980 | return self.get_index_from_version( |
|
2977 | 2981 | self.pull_request_version_id, versions) |
@@ -1610,19 +1610,53 b' BIN_FILENODE = 7' | |||
|
1610 | 1610 | } |
|
1611 | 1611 | |
|
1612 | 1612 | .pull-request-merge { |
|
1613 | padding: 10px 0; | |
|
1613 | border: 1px solid @grey5; | |
|
1614 | padding: 10px 0px 20px; | |
|
1614 | 1615 | margin-top: 10px; |
|
1615 | 1616 | margin-bottom: 20px; |
|
1616 | 1617 | } |
|
1617 | 1618 | |
|
1619 | .pull-request-merge ul { | |
|
1620 | padding: 0px 0px; | |
|
1621 | } | |
|
1622 | ||
|
1623 | .pull-request-merge li:before{ | |
|
1624 | content:none; | |
|
1625 | } | |
|
1626 | ||
|
1618 | 1627 | .pull-request-merge .pull-request-wrap { |
|
1619 |
height: |
|
|
1620 |
padding: |
|
|
1628 | height: auto; | |
|
1629 | padding: 0px 0px; | |
|
1630 | text-align: right; | |
|
1621 | 1631 | } |
|
1622 | 1632 | |
|
1623 | 1633 | .pull-request-merge span { |
|
1624 |
margin-right: |
|
|
1634 | margin-right: 5px; | |
|
1635 | } | |
|
1636 | ||
|
1637 | .pull-request-merge-actions { | |
|
1638 | height: 30px; | |
|
1639 | padding: 0px 0px; | |
|
1640 | } | |
|
1641 | ||
|
1642 | .merge-message { | |
|
1643 | font-size: 1.2em | |
|
1625 | 1644 | } |
|
1645 | .merge-message li{ | |
|
1646 | text-decoration: none; | |
|
1647 | } | |
|
1648 | ||
|
1649 | .merge-message.success i { | |
|
1650 | color:@alert1; | |
|
1651 | } | |
|
1652 | .merge-message.warning i { | |
|
1653 | color: @alert3; | |
|
1654 | } | |
|
1655 | .merge-message.error i { | |
|
1656 | color:@alert2; | |
|
1657 | } | |
|
1658 | ||
|
1659 | ||
|
1626 | 1660 | |
|
1627 | 1661 | .pr-versions { |
|
1628 | 1662 | position: relative; |
@@ -240,7 +240,12 b' var bindToggleButtons = function() {' | |||
|
240 | 240 | $(this.statusChange).select2('readonly', false); |
|
241 | 241 | }; |
|
242 | 242 | |
|
243 |
this.globalSubmitSuccessCallback = function(){ |
|
|
243 | this.globalSubmitSuccessCallback = function(){ | |
|
244 | // default behaviour is to call GLOBAL hook, if it's registered. | |
|
245 | if (window.commentFormGlobalSubmitSuccessCallback !== undefined){ | |
|
246 | commentFormGlobalSubmitSuccessCallback() | |
|
247 | } | |
|
248 | }; | |
|
244 | 249 | |
|
245 | 250 | this.submitAjaxPOST = function(url, postData, successHandler, failHandler) { |
|
246 | 251 | failHandler = failHandler || function() {}; |
@@ -300,7 +305,8 b' var bindToggleButtons = function() {' | |||
|
300 | 305 | } |
|
301 | 306 | |
|
302 | 307 | var submitSuccessCallback = function(o) { |
|
303 | if (status) { | |
|
308 | // reload page if we change status for single commit. | |
|
309 | if (status && self.commitId) { | |
|
304 | 310 | location.reload(true); |
|
305 | 311 | } else { |
|
306 | 312 | $('#injected_page_comments').append(o.rendered_text); |
@@ -170,29 +170,6 b'' | |||
|
170 | 170 | |
|
171 | 171 | <%def name="comments(post_url, cur_status, is_pull_request=False, is_compare=False, change_status=True, form_extras=None)"> |
|
172 | 172 | |
|
173 | ## merge status, and merge action | |
|
174 | %if is_pull_request: | |
|
175 | <div class="pull-request-merge"> | |
|
176 | %if c.allowed_to_merge: | |
|
177 | <div class="pull-request-wrap"> | |
|
178 | <div class="pull-right"> | |
|
179 | ${h.secure_form(url('pullrequest_merge', repo_name=c.repo_name, pull_request_id=c.pull_request.pull_request_id), id='merge_pull_request_form')} | |
|
180 | <span data-role="merge-message">${c.pr_merge_msg} ${c.approval_msg if c.approval_msg else ''}</span> | |
|
181 | <% merge_disabled = ' disabled' if c.pr_merge_status is False else '' %> | |
|
182 | <input type="submit" id="merge_pull_request" value="${_('Merge Pull Request')}" class="btn${merge_disabled}"${merge_disabled}> | |
|
183 | ${h.end_form()} | |
|
184 | </div> | |
|
185 | </div> | |
|
186 | %else: | |
|
187 | <div class="pull-request-wrap"> | |
|
188 | <div class="pull-right"> | |
|
189 | <span>${c.pr_merge_msg} ${c.approval_msg if c.approval_msg else ''}</span> | |
|
190 | </div> | |
|
191 | </div> | |
|
192 | %endif | |
|
193 | </div> | |
|
194 | %endif | |
|
195 | ||
|
196 | 173 | <div class="comments"> |
|
197 | 174 | <% |
|
198 | 175 | if is_pull_request: |
@@ -482,23 +482,28 b' Changed files:' | |||
|
482 | 482 | |
|
483 | 483 | <div id="comment-tr-show"> |
|
484 | 484 | <div class="comment"> |
|
485 | % if general_outdated_comm_count_ver: | |
|
485 | 486 | <div class="meta"> |
|
486 | % if general_outdated_comm_count_ver: | |
|
487 | % if general_outdated_comm_count_ver == 1: | |
|
488 | ${_('there is {num} general comment from older versions').format(num=general_outdated_comm_count_ver)}, | |
|
489 | <a href="#" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show it')}</a> | |
|
490 | % else: | |
|
491 | ${_('there are {num} general comments from older versions').format(num=general_outdated_comm_count_ver)}, | |
|
492 | <a href="#" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show them')}</a> | |
|
493 | % endif | |
|
487 | % if general_outdated_comm_count_ver == 1: | |
|
488 | ${_('there is {num} general comment from older versions').format(num=general_outdated_comm_count_ver)}, | |
|
489 | <a href="#" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show it')}</a> | |
|
490 | % else: | |
|
491 | ${_('there are {num} general comments from older versions').format(num=general_outdated_comm_count_ver)}, | |
|
492 | <a href="#" onclick="$('.comment-general.comment-outdated').show(); $(this).parent().hide(); return false;">${_('show them')}</a> | |
|
494 | 493 | % endif |
|
495 | 494 | </div> |
|
495 | % endif | |
|
496 | 496 | </div> |
|
497 | 497 | </div> |
|
498 | 498 | |
|
499 | 499 | ${comment.generate_comments(c.comments, include_pull_request=True, is_pull_request=True)} |
|
500 | 500 | |
|
501 | 501 | % if not c.pull_request.is_closed(): |
|
502 | ## merge status, and merge action | |
|
503 | <div class="pull-request-merge"> | |
|
504 | <%include file="/pullrequests/pullrequest_merge_checks.mako"/> | |
|
505 | </div> | |
|
506 | ||
|
502 | 507 | ## main comment form and it status |
|
503 | 508 |
|
|
504 | 509 | pull_request_id=c.pull_request.pull_request_id), |
@@ -603,6 +608,16 b' Changed files:' | |||
|
603 | 608 | $('.showOutdatedComments').show(); |
|
604 | 609 | }; |
|
605 | 610 | |
|
611 | refreshMergeChecks = function(){ | |
|
612 | var loadUrl = "${h.url.current(merge_checks=1)}"; | |
|
613 | $('.pull-request-merge').css('opacity', 0.3); | |
|
614 | $('.pull-request-merge').load( | |
|
615 | loadUrl,function() { | |
|
616 | $('.pull-request-merge').css('opacity', 1); | |
|
617 | } | |
|
618 | ); | |
|
619 | }; | |
|
620 | ||
|
606 | 621 | $('#show-outdated-comments').on('click', function(e){ |
|
607 | 622 | var button = $(this); |
|
608 | 623 | var outdated = $('.comment-outdated'); |
@@ -683,6 +698,12 b' Changed files:' | |||
|
683 | 698 | button.addClass("comments-visible"); |
|
684 | 699 | } |
|
685 | 700 | }); |
|
701 | ||
|
702 | // register submit callback on commentForm form to track TODOs | |
|
703 | window.commentFormGlobalSubmitSuccessCallback = function(){ | |
|
704 | refreshMergeChecks(); | |
|
705 | }; | |
|
706 | ||
|
686 | 707 | }) |
|
687 | 708 | </script> |
|
688 | 709 |
General Comments 0
You need to be logged in to leave comments.
Login now