Show More
@@ -66,113 +66,10 b' log = logging.getLogger(__name__)' | |||||
66 |
|
66 | |||
67 |
|
67 | |||
68 | class PullrequestsController(BaseRepoController): |
|
68 | class PullrequestsController(BaseRepoController): | |
|
69 | ||||
69 | def __before__(self): |
|
70 | def __before__(self): | |
70 | super(PullrequestsController, self).__before__() |
|
71 | super(PullrequestsController, self).__before__() | |
71 |
|
72 | |||
72 | def _load_compare_data(self, pull_request, inline_comments): |
|
|||
73 | """ |
|
|||
74 | Load context data needed for generating compare diff |
|
|||
75 |
|
||||
76 | :param pull_request: object related to the request |
|
|||
77 | :param enable_comments: flag to determine if comments are included |
|
|||
78 | """ |
|
|||
79 | source_repo = pull_request.source_repo |
|
|||
80 | source_ref_id = pull_request.source_ref_parts.commit_id |
|
|||
81 |
|
||||
82 | target_repo = pull_request.target_repo |
|
|||
83 | target_ref_id = pull_request.target_ref_parts.commit_id |
|
|||
84 |
|
||||
85 | # despite opening commits for bookmarks/branches/tags, we always |
|
|||
86 | # convert this to rev to prevent changes after bookmark or branch change |
|
|||
87 | c.source_ref_type = 'rev' |
|
|||
88 | c.source_ref = source_ref_id |
|
|||
89 |
|
||||
90 | c.target_ref_type = 'rev' |
|
|||
91 | c.target_ref = target_ref_id |
|
|||
92 |
|
||||
93 | c.source_repo = source_repo |
|
|||
94 | c.target_repo = target_repo |
|
|||
95 |
|
||||
96 | c.fulldiff = bool(request.GET.get('fulldiff')) |
|
|||
97 |
|
||||
98 | # diff_limit is the old behavior, will cut off the whole diff |
|
|||
99 | # if the limit is applied otherwise will just hide the |
|
|||
100 | # big files from the front-end |
|
|||
101 | diff_limit = self.cut_off_limit_diff |
|
|||
102 | file_limit = self.cut_off_limit_file |
|
|||
103 |
|
||||
104 | pre_load = ["author", "branch", "date", "message"] |
|
|||
105 |
|
||||
106 | c.commit_ranges = [] |
|
|||
107 | source_commit = EmptyCommit() |
|
|||
108 | target_commit = EmptyCommit() |
|
|||
109 | c.missing_requirements = False |
|
|||
110 | try: |
|
|||
111 | c.commit_ranges = [ |
|
|||
112 | source_repo.get_commit(commit_id=rev, pre_load=pre_load) |
|
|||
113 | for rev in pull_request.revisions] |
|
|||
114 |
|
||||
115 | c.statuses = source_repo.statuses( |
|
|||
116 | [x.raw_id for x in c.commit_ranges]) |
|
|||
117 |
|
||||
118 | target_commit = source_repo.get_commit( |
|
|||
119 | commit_id=safe_str(target_ref_id)) |
|
|||
120 | source_commit = source_repo.get_commit( |
|
|||
121 | commit_id=safe_str(source_ref_id)) |
|
|||
122 | except RepositoryRequirementError: |
|
|||
123 | c.missing_requirements = True |
|
|||
124 |
|
||||
125 | # auto collapse if we have more than limit |
|
|||
126 | collapse_limit = diffs.DiffProcessor._collapse_commits_over |
|
|||
127 | c.collapse_all_commits = len(c.commit_ranges) > collapse_limit |
|
|||
128 |
|
||||
129 | c.changes = {} |
|
|||
130 | c.missing_commits = False |
|
|||
131 | if (c.missing_requirements or |
|
|||
132 | isinstance(source_commit, EmptyCommit) or |
|
|||
133 | source_commit == target_commit): |
|
|||
134 | _parsed = [] |
|
|||
135 | c.missing_commits = True |
|
|||
136 | else: |
|
|||
137 | vcs_diff = PullRequestModel().get_diff(pull_request) |
|
|||
138 | diff_processor = diffs.DiffProcessor( |
|
|||
139 | vcs_diff, format='newdiff', diff_limit=diff_limit, |
|
|||
140 | file_limit=file_limit, show_full_diff=c.fulldiff) |
|
|||
141 |
|
||||
142 | _parsed = diff_processor.prepare() |
|
|||
143 | c.limited_diff = isinstance(_parsed, diffs.LimitedDiffContainer) |
|
|||
144 |
|
||||
145 | included_files = {} |
|
|||
146 | for f in _parsed: |
|
|||
147 | included_files[f['filename']] = f['stats'] |
|
|||
148 |
|
||||
149 | c.deleted_files = [fname for fname in inline_comments if |
|
|||
150 | fname not in included_files] |
|
|||
151 |
|
||||
152 | c.deleted_files_comments = collections.defaultdict(dict) |
|
|||
153 | for fname, per_line_comments in inline_comments.items(): |
|
|||
154 | if fname in c.deleted_files: |
|
|||
155 | c.deleted_files_comments[fname]['stats'] = 0 |
|
|||
156 | c.deleted_files_comments[fname]['comments'] = list() |
|
|||
157 | for lno, comments in per_line_comments.items(): |
|
|||
158 | c.deleted_files_comments[fname]['comments'].extend(comments) |
|
|||
159 |
|
||||
160 | def _node_getter(commit): |
|
|||
161 | def get_node(fname): |
|
|||
162 | try: |
|
|||
163 | return commit.get_node(fname) |
|
|||
164 | except NodeDoesNotExistError: |
|
|||
165 | return None |
|
|||
166 | return get_node |
|
|||
167 |
|
||||
168 | c.diffset = codeblocks.DiffSet( |
|
|||
169 | repo_name=c.repo_name, |
|
|||
170 | source_repo_name=c.source_repo.repo_name, |
|
|||
171 | source_node_getter=_node_getter(target_commit), |
|
|||
172 | target_node_getter=_node_getter(source_commit), |
|
|||
173 | comments=inline_comments |
|
|||
174 | ).render_patchset(_parsed, target_commit.raw_id, source_commit.raw_id) |
|
|||
175 |
|
||||
176 | def _extract_ordering(self, request): |
|
73 | def _extract_ordering(self, request): | |
177 | column_index = safe_int(request.GET.get('order[0][column]')) |
|
74 | column_index = safe_int(request.GET.get('order[0][column]')) | |
178 | order_dir = request.GET.get('order[0][dir]', 'desc') |
|
75 | order_dir = request.GET.get('order[0][dir]', 'desc') | |
@@ -693,71 +590,53 b' class PullrequestsController(BaseRepoCon' | |||||
693 |
|
590 | |||
694 | pull_request_display_obj = PullRequest.get_pr_display_object( |
|
591 | pull_request_display_obj = PullRequest.get_pr_display_object( | |
695 | pull_request_obj, _org_pull_request_obj) |
|
592 | pull_request_obj, _org_pull_request_obj) | |
|
593 | ||||
696 | return _org_pull_request_obj, pull_request_obj, \ |
|
594 | return _org_pull_request_obj, pull_request_obj, \ | |
697 | pull_request_display_obj, at_version |
|
595 | pull_request_display_obj, at_version | |
698 |
|
596 | |||
699 | def _get_pr_version_changes(self, version, pull_request_latest): |
|
|||
700 | """ |
|
|||
701 | Generate changes commits, and diff data based on the current pr version |
|
|||
702 | """ |
|
|||
703 |
|
||||
704 | #TODO(marcink): save those changes as JSON metadata for chaching later. |
|
|||
705 |
|
||||
706 | # fake the version to add the "initial" state object |
|
|||
707 | pull_request_initial = PullRequest.get_pr_display_object( |
|
|||
708 | pull_request_latest, pull_request_latest, |
|
|||
709 | internal_methods=['get_commit', 'versions']) |
|
|||
710 | pull_request_initial.revisions = [] |
|
|||
711 | pull_request_initial.source_repo.get_commit = types.MethodType( |
|
|||
712 | lambda *a, **k: EmptyCommit(), pull_request_initial) |
|
|||
713 | pull_request_initial.source_repo.scm_instance = types.MethodType( |
|
|||
714 | lambda *a, **k: EmptyRepository(), pull_request_initial) |
|
|||
715 |
|
||||
716 | _changes_versions = [pull_request_latest] + \ |
|
|||
717 | list(reversed(c.versions)) + \ |
|
|||
718 | [pull_request_initial] |
|
|||
719 |
|
||||
720 | if version == 'latest': |
|
|||
721 | index = 0 |
|
|||
722 | else: |
|
|||
723 | for pos, prver in enumerate(_changes_versions): |
|
|||
724 | ver = getattr(prver, 'pull_request_version_id', -1) |
|
|||
725 | if ver == safe_int(version): |
|
|||
726 | index = pos |
|
|||
727 | break |
|
|||
728 | else: |
|
|||
729 | index = 0 |
|
|||
730 |
|
||||
731 | cur_obj = _changes_versions[index] |
|
|||
732 | prev_obj = _changes_versions[index + 1] |
|
|||
733 |
|
||||
734 | old_commit_ids = set(prev_obj.revisions) |
|
|||
735 | new_commit_ids = set(cur_obj.revisions) |
|
|||
736 |
|
||||
737 | changes = PullRequestModel()._calculate_commit_id_changes( |
|
|||
738 | old_commit_ids, new_commit_ids) |
|
|||
739 |
|
||||
740 | old_diff_data, new_diff_data = PullRequestModel()._generate_update_diffs( |
|
|||
741 | cur_obj, prev_obj) |
|
|||
742 | file_changes = PullRequestModel()._calculate_file_changes( |
|
|||
743 | old_diff_data, new_diff_data) |
|
|||
744 | return changes, file_changes |
|
|||
745 |
|
||||
746 | @LoginRequired() |
|
597 | @LoginRequired() | |
747 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
598 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', | |
748 | 'repository.admin') |
|
599 | 'repository.admin') | |
749 | def show(self, repo_name, pull_request_id): |
|
600 | def show(self, repo_name, pull_request_id): | |
750 | pull_request_id = safe_int(pull_request_id) |
|
601 | pull_request_id = safe_int(pull_request_id) | |
751 | version = request.GET.get('version') |
|
602 | version = request.GET.get('version') | |
|
603 | from_version = request.GET.get('from_version') or version | |||
752 | merge_checks = request.GET.get('merge_checks') |
|
604 | merge_checks = request.GET.get('merge_checks') | |
|
605 | c.fulldiff = str2bool(request.GET.get('fulldiff')) | |||
|
606 | ||||
|
607 | # register for JS templates | |||
|
608 | c.template_context['pull_request_data']['pull_request_id'] = \ | |||
|
609 | pull_request_id | |||
753 |
|
610 | |||
754 | (pull_request_latest, |
|
611 | (pull_request_latest, | |
755 | pull_request_at_ver, |
|
612 | pull_request_at_ver, | |
756 | pull_request_display_obj, |
|
613 | pull_request_display_obj, | |
757 |
at_version) = self._get_pr_version( |
|
614 | at_version) = self._get_pr_version( | |
|
615 | pull_request_id, version=version) | |||
|
616 | versions = pull_request_display_obj.versions() | |||
|
617 | ||||
|
618 | c.at_version = at_version | |||
|
619 | c.at_version_num = (at_version | |||
|
620 | if at_version and at_version != 'latest' | |||
|
621 | else None) | |||
|
622 | c.at_version_pos = ChangesetComment.get_index_from_version( | |||
|
623 | c.at_version_num, versions) | |||
758 |
|
624 | |||
759 | c.template_context['pull_request_data']['pull_request_id'] = \ |
|
625 | (prev_pull_request_latest, | |
760 |
|
|
626 | prev_pull_request_at_ver, | |
|
627 | prev_pull_request_display_obj, | |||
|
628 | prev_at_version) = self._get_pr_version( | |||
|
629 | pull_request_id, version=from_version) | |||
|
630 | ||||
|
631 | c.from_version = prev_at_version | |||
|
632 | c.from_version_num = (prev_at_version | |||
|
633 | if prev_at_version and prev_at_version != 'latest' | |||
|
634 | else None) | |||
|
635 | c.from_version_pos = ChangesetComment.get_index_from_version( | |||
|
636 | c.from_version_num, versions) | |||
|
637 | ||||
|
638 | # define if we're in COMPARE mode or VIEW at version mode | |||
|
639 | compare = at_version != prev_at_version | |||
761 |
|
640 | |||
762 | # pull_requests repo_name we opened it against |
|
641 | # pull_requests repo_name we opened it against | |
763 | # ie. target_repo must match |
|
642 | # ie. target_repo must match | |
@@ -767,12 +646,12 b' class PullrequestsController(BaseRepoCon' | |||||
767 | c.shadow_clone_url = PullRequestModel().get_shadow_clone_url( |
|
646 | c.shadow_clone_url = PullRequestModel().get_shadow_clone_url( | |
768 | pull_request_at_ver) |
|
647 | pull_request_at_ver) | |
769 |
|
648 | |||
770 |
c.ancestor = None # |
|
649 | c.ancestor = None # empty ancestor hidden in display | |
771 | c.pull_request = pull_request_display_obj |
|
650 | c.pull_request = pull_request_display_obj | |
772 | c.pull_request_latest = pull_request_latest |
|
651 | c.pull_request_latest = pull_request_latest | |
773 |
|
652 | |||
774 | pr_closed = pull_request_latest.is_closed() |
|
653 | pr_closed = pull_request_latest.is_closed() | |
775 | if at_version and not at_version == 'latest': |
|
654 | if compare or (at_version and not at_version == 'latest'): | |
776 | c.allowed_to_change_status = False |
|
655 | c.allowed_to_change_status = False | |
777 | c.allowed_to_update = False |
|
656 | c.allowed_to_update = False | |
778 | c.allowed_to_merge = False |
|
657 | c.allowed_to_merge = False | |
@@ -789,35 +668,50 b' class PullrequestsController(BaseRepoCon' | |||||
789 | pull_request_latest, c.rhodecode_user) and not pr_closed |
|
668 | pull_request_latest, c.rhodecode_user) and not pr_closed | |
790 | c.allowed_to_comment = not pr_closed |
|
669 | c.allowed_to_comment = not pr_closed | |
791 |
|
670 | |||
792 | cc_model = CommentsModel() |
|
671 | # check merge capabilities | |
|
672 | _merge_check = MergeCheck.validate( | |||
|
673 | pull_request_latest, user=c.rhodecode_user) | |||
|
674 | c.pr_merge_errors = _merge_check.error_details | |||
|
675 | c.pr_merge_possible = not _merge_check.failed | |||
|
676 | c.pr_merge_message = _merge_check.merge_msg | |||
793 |
|
677 | |||
|
678 | if merge_checks: | |||
|
679 | return render('/pullrequests/pullrequest_merge_checks.mako') | |||
|
680 | ||||
|
681 | comments_model = CommentsModel() | |||
|
682 | ||||
|
683 | # reviewers and statuses | |||
794 | c.pull_request_reviewers = pull_request_at_ver.reviewers_statuses() |
|
684 | c.pull_request_reviewers = pull_request_at_ver.reviewers_statuses() | |
|
685 | allowed_reviewers = [x[0].user_id for x in c.pull_request_reviewers] | |||
795 | c.pull_request_review_status = pull_request_at_ver.calculated_review_status() |
|
686 | c.pull_request_review_status = pull_request_at_ver.calculated_review_status() | |
796 |
|
687 | |||
797 | c.versions = pull_request_display_obj.versions() |
|
|||
798 | c.at_version = at_version |
|
|||
799 | c.at_version_num = at_version if at_version and at_version != 'latest' else None |
|
|||
800 | c.at_version_pos = ChangesetComment.get_index_from_version( |
|
|||
801 | c.at_version_num, c.versions) |
|
|||
802 |
|
||||
803 | # GENERAL COMMENTS with versions # |
|
688 | # GENERAL COMMENTS with versions # | |
804 |
q = c |
|
689 | q = comments_model._all_general_comments_of_pull_request(pull_request_latest) | |
|
690 | q = q.order_by(ChangesetComment.comment_id.asc()) | |||
805 | general_comments = q.order_by(ChangesetComment.pull_request_version_id.asc()) |
|
691 | general_comments = q.order_by(ChangesetComment.pull_request_version_id.asc()) | |
806 |
|
692 | |||
807 | # pick comments we want to render at current version |
|
693 | # pick comments we want to render at current version | |
808 |
c.comment_versions = c |
|
694 | c.comment_versions = comments_model.aggregate_comments( | |
809 |
general_comments, |
|
695 | general_comments, versions, c.at_version_num) | |
810 | c.comments = c.comment_versions[c.at_version_num]['until'] |
|
696 | c.comments = c.comment_versions[c.at_version_num]['until'] | |
811 |
|
697 | |||
812 | # INLINE COMMENTS with versions # |
|
698 | # INLINE COMMENTS with versions # | |
813 |
q = c |
|
699 | q = comments_model._all_inline_comments_of_pull_request(pull_request_latest) | |
|
700 | q = q.order_by(ChangesetComment.comment_id.asc()) | |||
814 | inline_comments = q.order_by(ChangesetComment.pull_request_version_id.asc()) |
|
701 | inline_comments = q.order_by(ChangesetComment.pull_request_version_id.asc()) | |
815 |
c.inline_versions = c |
|
702 | c.inline_versions = comments_model.aggregate_comments( | |
816 |
inline_comments, |
|
703 | inline_comments, versions, c.at_version_num, inline=True) | |
|
704 | ||||
|
705 | # inject latest version | |||
|
706 | latest_ver = PullRequest.get_pr_display_object( | |||
|
707 | pull_request_latest, pull_request_latest) | |||
|
708 | ||||
|
709 | c.versions = versions + [latest_ver] | |||
817 |
|
710 | |||
818 | # if we use version, then do not show later comments |
|
711 | # if we use version, then do not show later comments | |
819 | # than current version |
|
712 | # than current version | |
820 |
display_inline_comments = collections.defaultdict( |
|
713 | display_inline_comments = collections.defaultdict( | |
|
714 | lambda: collections.defaultdict(list)) | |||
821 | for co in inline_comments: |
|
715 | for co in inline_comments: | |
822 | if c.at_version_num: |
|
716 | if c.at_version_num: | |
823 | # pick comments that are at least UPTO given version, so we |
|
717 | # pick comments that are at least UPTO given version, so we | |
@@ -831,17 +725,126 b' class PullrequestsController(BaseRepoCon' | |||||
831 | if should_render: |
|
725 | if should_render: | |
832 | display_inline_comments[co.f_path][co.line_no].append(co) |
|
726 | display_inline_comments[co.f_path][co.line_no].append(co) | |
833 |
|
727 | |||
834 | _merge_check = MergeCheck.validate( |
|
728 | # load diff data into template context, if we use compare mode then | |
835 | pull_request_latest, user=c.rhodecode_user) |
|
729 | # diff is calculated based on changes between versions of PR | |
836 | c.pr_merge_errors = _merge_check.error_details |
|
730 | ||
837 | c.pr_merge_possible = not _merge_check.failed |
|
731 | source_repo = pull_request_at_ver.source_repo | |
838 | c.pr_merge_message = _merge_check.merge_msg |
|
732 | source_ref_id = pull_request_at_ver.source_ref_parts.commit_id | |
|
733 | ||||
|
734 | target_repo = pull_request_at_ver.target_repo | |||
|
735 | target_ref_id = pull_request_at_ver.target_ref_parts.commit_id | |||
|
736 | ||||
|
737 | if compare: | |||
|
738 | # in compare switch the diff base to latest commit from prev version | |||
|
739 | target_ref_id = prev_pull_request_display_obj.revisions[0] | |||
|
740 | ||||
|
741 | # despite opening commits for bookmarks/branches/tags, we always | |||
|
742 | # convert this to rev to prevent changes after bookmark or branch change | |||
|
743 | c.source_ref_type = 'rev' | |||
|
744 | c.source_ref = source_ref_id | |||
|
745 | ||||
|
746 | c.target_ref_type = 'rev' | |||
|
747 | c.target_ref = target_ref_id | |||
|
748 | ||||
|
749 | c.source_repo = source_repo | |||
|
750 | c.target_repo = target_repo | |||
|
751 | ||||
|
752 | # diff_limit is the old behavior, will cut off the whole diff | |||
|
753 | # if the limit is applied otherwise will just hide the | |||
|
754 | # big files from the front-end | |||
|
755 | diff_limit = self.cut_off_limit_diff | |||
|
756 | file_limit = self.cut_off_limit_file | |||
|
757 | ||||
|
758 | c.commit_ranges = [] | |||
|
759 | source_commit = EmptyCommit() | |||
|
760 | target_commit = EmptyCommit() | |||
|
761 | c.missing_requirements = False | |||
|
762 | ||||
|
763 | # try first shadow repo, fallback to regular repo | |||
|
764 | try: | |||
|
765 | commits_source_repo = pull_request_latest.get_shadow_repo() | |||
|
766 | except Exception: | |||
|
767 | log.debug('Failed to get shadow repo', exc_info=True) | |||
|
768 | commits_source_repo = source_repo.scm_instance() | |||
|
769 | ||||
|
770 | c.commits_source_repo = commits_source_repo | |||
|
771 | commit_cache = {} | |||
|
772 | try: | |||
|
773 | pre_load = ["author", "branch", "date", "message"] | |||
|
774 | show_revs = pull_request_at_ver.revisions | |||
|
775 | for rev in show_revs: | |||
|
776 | comm = commits_source_repo.get_commit( | |||
|
777 | commit_id=rev, pre_load=pre_load) | |||
|
778 | c.commit_ranges.append(comm) | |||
|
779 | commit_cache[comm.raw_id] = comm | |||
839 |
|
780 | |||
840 | if merge_checks: |
|
781 | target_commit = commits_source_repo.get_commit( | |
841 | return render('/pullrequests/pullrequest_merge_checks.mako') |
|
782 | commit_id=safe_str(target_ref_id)) | |
|
783 | source_commit = commits_source_repo.get_commit( | |||
|
784 | commit_id=safe_str(source_ref_id)) | |||
|
785 | except CommitDoesNotExistError: | |||
|
786 | pass | |||
|
787 | except RepositoryRequirementError: | |||
|
788 | log.warning( | |||
|
789 | 'Failed to get all required data from repo', exc_info=True) | |||
|
790 | c.missing_requirements = True | |||
|
791 | ||||
|
792 | c.statuses = source_repo.statuses( | |||
|
793 | [x.raw_id for x in c.commit_ranges]) | |||
|
794 | ||||
|
795 | # auto collapse if we have more than limit | |||
|
796 | collapse_limit = diffs.DiffProcessor._collapse_commits_over | |||
|
797 | c.collapse_all_commits = len(c.commit_ranges) > collapse_limit | |||
|
798 | c.compare_mode = compare | |||
|
799 | ||||
|
800 | c.missing_commits = False | |||
|
801 | if (c.missing_requirements or isinstance(source_commit, EmptyCommit) | |||
|
802 | or source_commit == target_commit): | |||
|
803 | ||||
|
804 | c.missing_commits = True | |||
|
805 | else: | |||
|
806 | vcs_diff = PullRequestModel().get_diff( | |||
|
807 | commits_source_repo, source_ref_id, target_ref_id) | |||
|
808 | ||||
|
809 | diff_processor = diffs.DiffProcessor( | |||
|
810 | vcs_diff, format='newdiff', diff_limit=diff_limit, | |||
|
811 | file_limit=file_limit, show_full_diff=c.fulldiff) | |||
842 |
|
812 | |||
843 | # load compare data into template context |
|
813 | _parsed = diff_processor.prepare() | |
844 | self._load_compare_data(pull_request_at_ver, display_inline_comments) |
|
814 | c.limited_diff = isinstance(_parsed, diffs.LimitedDiffContainer) | |
|
815 | ||||
|
816 | def _node_getter(commit): | |||
|
817 | def get_node(fname): | |||
|
818 | try: | |||
|
819 | return commit.get_node(fname) | |||
|
820 | except NodeDoesNotExistError: | |||
|
821 | return None | |||
|
822 | ||||
|
823 | return get_node | |||
|
824 | ||||
|
825 | diffset = codeblocks.DiffSet( | |||
|
826 | repo_name=c.repo_name, | |||
|
827 | source_repo_name=c.source_repo.repo_name, | |||
|
828 | source_node_getter=_node_getter(target_commit), | |||
|
829 | target_node_getter=_node_getter(source_commit), | |||
|
830 | comments=display_inline_comments | |||
|
831 | ) | |||
|
832 | c.diffset = diffset.render_patchset( | |||
|
833 | _parsed, target_commit.raw_id, source_commit.raw_id) | |||
|
834 | ||||
|
835 | # calculate removed files that are bound to comments | |||
|
836 | comment_deleted_files = [ | |||
|
837 | fname for fname in display_inline_comments | |||
|
838 | if fname not in c.diffset.file_stats] | |||
|
839 | ||||
|
840 | c.deleted_files_comments = collections.defaultdict(dict) | |||
|
841 | for fname, per_line_comments in display_inline_comments.items(): | |||
|
842 | if fname in comment_deleted_files: | |||
|
843 | c.deleted_files_comments[fname]['stats'] = 0 | |||
|
844 | c.deleted_files_comments[fname]['comments'] = list() | |||
|
845 | for lno, comments in per_line_comments.items(): | |||
|
846 | c.deleted_files_comments[fname]['comments'].extend( | |||
|
847 | comments) | |||
845 |
|
848 | |||
846 | # this is a hack to properly display links, when creating PR, the |
|
849 | # this is a hack to properly display links, when creating PR, the | |
847 | # compare view and others uses different notation, and |
|
850 | # compare view and others uses different notation, and | |
@@ -856,21 +859,55 b' class PullrequestsController(BaseRepoCon' | |||||
856 | statuses = ChangesetStatus.STATUSES |
|
859 | statuses = ChangesetStatus.STATUSES | |
857 | c.commit_statuses = statuses |
|
860 | c.commit_statuses = statuses | |
858 |
|
861 | |||
859 |
c.changes = |
|
862 | c.show_version_changes = not pr_closed | |
860 |
c. |
|
863 | if c.show_version_changes: | |
|
864 | cur_obj = pull_request_at_ver | |||
|
865 | prev_obj = prev_pull_request_at_ver | |||
|
866 | ||||
|
867 | old_commit_ids = prev_obj.revisions | |||
|
868 | new_commit_ids = cur_obj.revisions | |||
|
869 | commit_changes = PullRequestModel()._calculate_commit_id_changes( | |||
|
870 | old_commit_ids, new_commit_ids) | |||
|
871 | c.commit_changes_summary = commit_changes | |||
|
872 | ||||
|
873 | # calculate the diff for commits between versions | |||
|
874 | c.commit_changes = [] | |||
|
875 | mark = lambda cs, fw: list( | |||
|
876 | h.itertools.izip_longest([], cs, fillvalue=fw)) | |||
|
877 | for c_type, raw_id in mark(commit_changes.added, 'a') \ | |||
|
878 | + mark(commit_changes.removed, 'r') \ | |||
|
879 | + mark(commit_changes.common, 'c'): | |||
861 |
|
880 | |||
862 | c.show_version_changes = 1 # control flag, not used yet |
|
881 | if raw_id in commit_cache: | |
|
882 | commit = commit_cache[raw_id] | |||
|
883 | else: | |||
|
884 | try: | |||
|
885 | commit = commits_source_repo.get_commit(raw_id) | |||
|
886 | except CommitDoesNotExistError: | |||
|
887 | # in case we fail extracting still use "dummy" commit | |||
|
888 | # for display in commit diff | |||
|
889 | commit = h.AttributeDict( | |||
|
890 | {'raw_id': raw_id, | |||
|
891 | 'message': 'EMPTY or MISSING COMMIT'}) | |||
|
892 | c.commit_changes.append([c_type, commit]) | |||
863 |
|
893 | |||
864 | if at_version and c.show_version_changes: |
|
894 | # current user review statuses for each version | |
865 | c.changes, c.file_changes = self._get_pr_version_changes( |
|
895 | c.review_versions = {} | |
866 | version, pull_request_latest) |
|
896 | if c.rhodecode_user.user_id in allowed_reviewers: | |
|
897 | for co in general_comments: | |||
|
898 | if co.author.user_id == c.rhodecode_user.user_id: | |||
|
899 | # each comment has a status change | |||
|
900 | status = co.status_change | |||
|
901 | if status: | |||
|
902 | _ver_pr = status[0].comment.pull_request_version_id | |||
|
903 | c.review_versions[_ver_pr] = status[0] | |||
867 |
|
904 | |||
868 | return render('/pullrequests/pullrequest_show.mako') |
|
905 | return render('/pullrequests/pullrequest_show.mako') | |
869 |
|
906 | |||
870 | @LoginRequired() |
|
907 | @LoginRequired() | |
871 | @NotAnonymous() |
|
908 | @NotAnonymous() | |
872 |
@HasRepoPermissionAnyDecorator( |
|
909 | @HasRepoPermissionAnyDecorator( | |
873 | 'repository.admin') |
|
910 | 'repository.read', 'repository.write', 'repository.admin') | |
874 | @auth.CSRFRequired() |
|
911 | @auth.CSRFRequired() | |
875 | @jsonify |
|
912 | @jsonify | |
876 | def comment(self, repo_name, pull_request_id): |
|
913 | def comment(self, repo_name, pull_request_id): |
@@ -382,6 +382,7 b' class DiffSet(object):' | |||||
382 | lines_deleted=0, |
|
382 | lines_deleted=0, | |
383 | changed_files=0, |
|
383 | changed_files=0, | |
384 | files=[], |
|
384 | files=[], | |
|
385 | file_stats={}, | |||
385 | limited_diff=isinstance(patchset, LimitedDiffContainer), |
|
386 | limited_diff=isinstance(patchset, LimitedDiffContainer), | |
386 | repo_name=self.repo_name, |
|
387 | repo_name=self.repo_name, | |
387 | source_repo_name=self.source_repo_name, |
|
388 | source_repo_name=self.source_repo_name, | |
@@ -389,6 +390,7 b' class DiffSet(object):' | |||||
389 | target_ref=target_ref, |
|
390 | target_ref=target_ref, | |
390 | )) |
|
391 | )) | |
391 | for patch in patchset: |
|
392 | for patch in patchset: | |
|
393 | diffset.file_stats[patch['filename']] = patch['stats'] | |||
392 | filediff = self.render_patch(patch) |
|
394 | filediff = self.render_patch(patch) | |
393 | filediff.diffset = diffset |
|
395 | filediff.diffset = diffset | |
394 | diffset.files.append(filediff) |
|
396 | diffset.files.append(filediff) |
@@ -37,6 +37,7 b' import time' | |||||
37 | import string |
|
37 | import string | |
38 | import hashlib |
|
38 | import hashlib | |
39 | import pygments |
|
39 | import pygments | |
|
40 | import itertools | |||
40 |
|
41 | |||
41 | from datetime import datetime |
|
42 | from datetime import datetime | |
42 | from functools import partial |
|
43 | from functools import partial |
@@ -3028,7 +3028,7 b' class ChangesetStatus(Base, BaseModel):' | |||||
3028 | pull_request = relationship('PullRequest', lazy='joined') |
|
3028 | pull_request = relationship('PullRequest', lazy='joined') | |
3029 |
|
3029 | |||
3030 | def __unicode__(self): |
|
3030 | def __unicode__(self): | |
3031 | return u"<%s('%s[%s]:%s')>" % ( |
|
3031 | return u"<%s('%s[v%s]:%s')>" % ( | |
3032 | self.__class__.__name__, |
|
3032 | self.__class__.__name__, | |
3033 | self.status, self.version, self.author |
|
3033 | self.status, self.version, self.author | |
3034 | ) |
|
3034 | ) | |
@@ -3254,7 +3254,6 b' class PullRequest(Base, _PullRequestBase' | |||||
3254 | cascade="all, delete, delete-orphan", |
|
3254 | cascade="all, delete, delete-orphan", | |
3255 | lazy='dynamic') |
|
3255 | lazy='dynamic') | |
3256 |
|
3256 | |||
3257 |
|
||||
3258 | @classmethod |
|
3257 | @classmethod | |
3259 | def get_pr_display_object(cls, pull_request_obj, org_pull_request_obj, |
|
3258 | def get_pr_display_object(cls, pull_request_obj, org_pull_request_obj, | |
3260 | internal_methods=None): |
|
3259 | internal_methods=None): | |
@@ -3290,6 +3289,10 b' class PullRequest(Base, _PullRequestBase' | |||||
3290 | def is_closed(self): |
|
3289 | def is_closed(self): | |
3291 | return pull_request_obj.is_closed() |
|
3290 | return pull_request_obj.is_closed() | |
3292 |
|
3291 | |||
|
3292 | @property | |||
|
3293 | def pull_request_version_id(self): | |||
|
3294 | return getattr(pull_request_obj, 'pull_request_version_id', None) | |||
|
3295 | ||||
3293 | attrs = StrictAttributeDict(pull_request_obj.get_api_data()) |
|
3296 | attrs = StrictAttributeDict(pull_request_obj.get_api_data()) | |
3294 |
|
3297 | |||
3295 | attrs.author = StrictAttributeDict( |
|
3298 | attrs.author = StrictAttributeDict( |
@@ -235,7 +235,7 b' class NotificationModel(BaseModel):' | |||||
235 | .filter(UserNotification.notification == notification)\ |
|
235 | .filter(UserNotification.notification == notification)\ | |
236 | .filter(UserNotification.user == user).scalar() |
|
236 | .filter(UserNotification.user == user).scalar() | |
237 |
|
237 | |||
238 | def make_description(self, notification, show_age=True): |
|
238 | def make_description(self, notification, show_age=True, translate=None): | |
239 | """ |
|
239 | """ | |
240 | Creates a human readable description based on properties |
|
240 | Creates a human readable description based on properties | |
241 | of notification object |
|
241 | of notification object | |
@@ -273,6 +273,8 b' class NotificationModel(BaseModel):' | |||||
273 | if show_age: |
|
273 | if show_age: | |
274 | template = templates[0] |
|
274 | template = templates[0] | |
275 | date_or_age = h.age(notification.created_on) |
|
275 | date_or_age = h.age(notification.created_on) | |
|
276 | if translate: | |||
|
277 | date_or_age = translate(date_or_age) | |||
276 | else: |
|
278 | else: | |
277 | template = templates[1] |
|
279 | template = templates[1] | |
278 | date_or_age = h.format_date(notification.created_on) |
|
280 | date_or_age = h.format_date(notification.created_on) |
@@ -50,7 +50,7 b' from rhodecode.model.changeset_status im' | |||||
50 | from rhodecode.model.comment import CommentsModel |
|
50 | from rhodecode.model.comment import CommentsModel | |
51 | from rhodecode.model.db import ( |
|
51 | from rhodecode.model.db import ( | |
52 | PullRequest, PullRequestReviewers, ChangesetStatus, |
|
52 | PullRequest, PullRequestReviewers, ChangesetStatus, | |
53 | PullRequestVersion, ChangesetComment) |
|
53 | PullRequestVersion, ChangesetComment, Repository) | |
54 | from rhodecode.model.meta import Session |
|
54 | from rhodecode.model.meta import Session | |
55 | from rhodecode.model.notification import NotificationModel, \ |
|
55 | from rhodecode.model.notification import NotificationModel, \ | |
56 | EmailNotificationModel |
|
56 | EmailNotificationModel | |
@@ -728,13 +728,23 b' class PullRequestModel(BaseModel):' | |||||
728 | return version |
|
728 | return version | |
729 |
|
729 | |||
730 | def _generate_update_diffs(self, pull_request, pull_request_version): |
|
730 | def _generate_update_diffs(self, pull_request, pull_request_version): | |
|
731 | ||||
731 | diff_context = ( |
|
732 | diff_context = ( | |
732 | self.DIFF_CONTEXT + |
|
733 | self.DIFF_CONTEXT + | |
733 | CommentsModel.needed_extra_diff_context()) |
|
734 | CommentsModel.needed_extra_diff_context()) | |
|
735 | ||||
|
736 | source_repo = pull_request_version.source_repo | |||
|
737 | source_ref_id = pull_request_version.source_ref_parts.commit_id | |||
|
738 | target_ref_id = pull_request_version.target_ref_parts.commit_id | |||
734 | old_diff = self._get_diff_from_pr_or_version( |
|
739 | old_diff = self._get_diff_from_pr_or_version( | |
735 |
|
|
740 | source_repo, source_ref_id, target_ref_id, context=diff_context) | |
|
741 | ||||
|
742 | source_repo = pull_request.source_repo | |||
|
743 | source_ref_id = pull_request.source_ref_parts.commit_id | |||
|
744 | target_ref_id = pull_request.target_ref_parts.commit_id | |||
|
745 | ||||
736 | new_diff = self._get_diff_from_pr_or_version( |
|
746 | new_diff = self._get_diff_from_pr_or_version( | |
737 |
|
|
747 | source_repo, source_ref_id, target_ref_id, context=diff_context) | |
738 |
|
748 | |||
739 | old_diff_data = diffs.DiffProcessor(old_diff) |
|
749 | old_diff_data = diffs.DiffProcessor(old_diff) | |
740 | old_diff_data.prepare() |
|
750 | old_diff_data.prepare() | |
@@ -768,10 +778,11 b' class PullRequestModel(BaseModel):' | |||||
768 | Session().add(comment) |
|
778 | Session().add(comment) | |
769 |
|
779 | |||
770 | def _calculate_commit_id_changes(self, old_ids, new_ids): |
|
780 | def _calculate_commit_id_changes(self, old_ids, new_ids): | |
771 |
added = new_ids |
|
781 | added = [x for x in new_ids if x not in old_ids] | |
772 | common = old_ids.intersection(new_ids) |
|
782 | common = [x for x in new_ids if x in old_ids] | |
773 |
removed = old_ids |
|
783 | removed = [x for x in old_ids if x not in new_ids] | |
774 | return ChangeTuple(added, common, removed) |
|
784 | total = new_ids | |
|
785 | return ChangeTuple(added, common, removed, total) | |||
775 |
|
786 | |||
776 | def _calculate_file_changes(self, old_diff_data, new_diff_data): |
|
787 | def _calculate_file_changes(self, old_diff_data, new_diff_data): | |
777 |
|
788 | |||
@@ -1261,20 +1272,20 b' class PullRequestModel(BaseModel):' | |||||
1261 | raise EmptyRepositoryError() |
|
1272 | raise EmptyRepositoryError() | |
1262 | return groups, selected |
|
1273 | return groups, selected | |
1263 |
|
1274 | |||
1264 |
def get_diff(self, |
|
1275 | def get_diff(self, source_repo, source_ref_id, target_ref_id, context=DIFF_CONTEXT): | |
1265 | pull_request = self.__get_pull_request(pull_request) |
|
1276 | return self._get_diff_from_pr_or_version( | |
1266 | return self._get_diff_from_pr_or_version(pull_request, context=context) |
|
1277 | source_repo, source_ref_id, target_ref_id, context=context) | |
1267 |
|
1278 | |||
1268 |
def _get_diff_from_pr_or_version( |
|
1279 | def _get_diff_from_pr_or_version( | |
1269 | source_repo = pr_or_version.source_repo |
|
1280 | self, source_repo, source_ref_id, target_ref_id, context): | |
1270 |
|
||||
1271 | # we swap org/other ref since we run a simple diff on one repo |
|
|||
1272 | target_ref_id = pr_or_version.target_ref_parts.commit_id |
|
|||
1273 | source_ref_id = pr_or_version.source_ref_parts.commit_id |
|
|||
1274 | target_commit = source_repo.get_commit( |
|
1281 | target_commit = source_repo.get_commit( | |
1275 | commit_id=safe_str(target_ref_id)) |
|
1282 | commit_id=safe_str(target_ref_id)) | |
1276 |
source_commit = source_repo.get_commit( |
|
1283 | source_commit = source_repo.get_commit( | |
1277 | vcs_repo = source_repo.scm_instance() |
|
1284 | commit_id=safe_str(source_ref_id)) | |
|
1285 | if isinstance(source_repo, Repository): | |||
|
1286 | vcs_repo = source_repo.scm_instance() | |||
|
1287 | else: | |||
|
1288 | vcs_repo = source_repo | |||
1278 |
|
1289 | |||
1279 | # TODO: johbo: In the context of an update, we cannot reach |
|
1290 | # TODO: johbo: In the context of an update, we cannot reach | |
1280 | # the old commit anymore with our normal mechanisms. It needs |
|
1291 | # the old commit anymore with our normal mechanisms. It needs | |
@@ -1403,7 +1414,7 b' class MergeCheck(object):' | |||||
1403 |
|
1414 | |||
1404 |
|
1415 | |||
1405 | ChangeTuple = namedtuple('ChangeTuple', |
|
1416 | ChangeTuple = namedtuple('ChangeTuple', | |
1406 | ['added', 'common', 'removed']) |
|
1417 | ['added', 'common', 'removed', 'total']) | |
1407 |
|
1418 | |||
1408 | FileChangeTuple = namedtuple('FileChangeTuple', |
|
1419 | FileChangeTuple = namedtuple('FileChangeTuple', | |
1409 | ['added', 'modified', 'removed']) |
|
1420 | ['added', 'modified', 'removed']) |
@@ -1393,6 +1393,14 b' table.integrations {' | |||||
1393 | } |
|
1393 | } | |
1394 | } |
|
1394 | } | |
1395 |
|
1395 | |||
|
1396 | .subtitle-compare { | |||
|
1397 | margin: -15px 0px 0px 0px; | |||
|
1398 | } | |||
|
1399 | ||||
|
1400 | .comments-summary-td { | |||
|
1401 | border-top: 1px dashed @grey5; | |||
|
1402 | } | |||
|
1403 | ||||
1396 | // new entry in group_members |
|
1404 | // new entry in group_members | |
1397 | .td-author-new-entry { |
|
1405 | .td-author-new-entry { | |
1398 | background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3); |
|
1406 | background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3); | |
@@ -1422,6 +1430,57 b' table.integrations {' | |||||
1422 | margin-left: 5px; |
|
1430 | margin-left: 5px; | |
1423 | } |
|
1431 | } | |
1424 |
|
1432 | |||
|
1433 | .compare_view_commits { | |||
|
1434 | .color-a { | |||
|
1435 | color: @alert1; | |||
|
1436 | } | |||
|
1437 | ||||
|
1438 | .color-c { | |||
|
1439 | color: @color3; | |||
|
1440 | } | |||
|
1441 | ||||
|
1442 | .color-r { | |||
|
1443 | color: @color5; | |||
|
1444 | } | |||
|
1445 | ||||
|
1446 | .color-a-bg { | |||
|
1447 | background-color: @alert1; | |||
|
1448 | } | |||
|
1449 | ||||
|
1450 | .color-c-bg { | |||
|
1451 | background-color: @alert3; | |||
|
1452 | } | |||
|
1453 | ||||
|
1454 | .color-r-bg { | |||
|
1455 | background-color: @alert2; | |||
|
1456 | } | |||
|
1457 | ||||
|
1458 | .color-a-border { | |||
|
1459 | border: 1px solid @alert1; | |||
|
1460 | } | |||
|
1461 | ||||
|
1462 | .color-c-border { | |||
|
1463 | border: 1px solid @alert3; | |||
|
1464 | } | |||
|
1465 | ||||
|
1466 | .color-r-border { | |||
|
1467 | border: 1px solid @alert2; | |||
|
1468 | } | |||
|
1469 | ||||
|
1470 | .commit-change-indicator { | |||
|
1471 | width: 15px; | |||
|
1472 | height: 15px; | |||
|
1473 | position: relative; | |||
|
1474 | left: 15px; | |||
|
1475 | } | |||
|
1476 | ||||
|
1477 | .commit-change-content { | |||
|
1478 | text-align: center; | |||
|
1479 | vertical-align: middle; | |||
|
1480 | line-height: 15px; | |||
|
1481 | } | |||
|
1482 | } | |||
|
1483 | ||||
1425 | .compare_view_files { |
|
1484 | .compare_view_files { | |
1426 | width: 100%; |
|
1485 | width: 100%; | |
1427 |
|
1486 | |||
@@ -1663,10 +1722,27 b' BIN_FILENODE = 7' | |||||
1663 | } |
|
1722 | } | |
1664 |
|
1723 | |||
1665 | .pr-versions { |
|
1724 | .pr-versions { | |
1666 | position: relative; |
|
1725 | font-size: 1.1em; | |
1667 | top: 6px; |
|
1726 | ||
|
1727 | table { | |||
|
1728 | padding: 0px 5px; | |||
|
1729 | } | |||
|
1730 | ||||
|
1731 | td { | |||
|
1732 | line-height: 15px; | |||
|
1733 | } | |||
|
1734 | ||||
|
1735 | .flag_status { | |||
|
1736 | margin: 0; | |||
|
1737 | } | |||
|
1738 | ||||
|
1739 | .compare-radio-button { | |||
|
1740 | position: relative; | |||
|
1741 | top: -3px; | |||
|
1742 | } | |||
1668 | } |
|
1743 | } | |
1669 |
|
1744 | |||
|
1745 | ||||
1670 | #close_pull_request { |
|
1746 | #close_pull_request { | |
1671 | margin-right: 0px; |
|
1747 | margin-right: 0px; | |
1672 | } |
|
1748 | } |
@@ -310,20 +310,42 b'' | |||||
310 | } |
|
310 | } | |
311 | } |
|
311 | } | |
312 |
|
312 | |||
313 | $('.expand_commit').on('click',function(e){ |
|
313 | $('.expand_commit').on('click', function (e) { | |
314 | var target_expand = $(this); |
|
314 | var target_expand = $(this); | |
315 | var cid = target_expand.data('commitId'); |
|
315 | var cid = target_expand.data('commitId'); | |
316 |
|
316 | |||
317 | if (target_expand.hasClass('open')){ |
|
317 | if (target_expand.hasClass('open')) { | |
318 | $('#c-'+cid).css({'height': '1.5em', 'white-space': 'nowrap', 'text-overflow': 'ellipsis', 'overflow':'hidden'}); |
|
318 | $('#c-' + cid).css({ | |
319 | $('#t-'+cid).css({'height': 'auto', 'line-height': '.9em', 'text-overflow': 'ellipsis', 'overflow':'hidden', 'white-space':'nowrap'}); |
|
319 | 'height': '1.5em', | |
320 | target_expand.removeClass('open'); |
|
320 | 'white-space': 'nowrap', | |
321 | } |
|
321 | 'text-overflow': 'ellipsis', | |
322 | else { |
|
322 | 'overflow': 'hidden' | |
323 | $('#c-'+cid).css({'height': 'auto', 'white-space': 'pre-line', 'text-overflow': 'initial', 'overflow':'visible'}); |
|
323 | }); | |
324 | $('#t-'+cid).css({'height': 'auto', 'max-height': 'none', 'text-overflow': 'initial', 'overflow':'visible', 'white-space':'normal'}); |
|
324 | $('#t-' + cid).css({ | |
325 | target_expand.addClass('open'); |
|
325 | 'height': 'auto', | |
326 | } |
|
326 | 'line-height': '.9em', | |
|
327 | 'text-overflow': 'ellipsis', | |||
|
328 | 'overflow': 'hidden', | |||
|
329 | 'white-space': 'nowrap' | |||
|
330 | }); | |||
|
331 | target_expand.removeClass('open'); | |||
|
332 | } | |||
|
333 | else { | |||
|
334 | $('#c-' + cid).css({ | |||
|
335 | 'height': 'auto', | |||
|
336 | 'white-space': 'pre-line', | |||
|
337 | 'text-overflow': 'initial', | |||
|
338 | 'overflow': 'visible' | |||
|
339 | }); | |||
|
340 | $('#t-' + cid).css({ | |||
|
341 | 'height': 'auto', | |||
|
342 | 'max-height': 'none', | |||
|
343 | 'text-overflow': 'initial', | |||
|
344 | 'overflow': 'visible', | |||
|
345 | 'white-space': 'normal' | |||
|
346 | }); | |||
|
347 | target_expand.addClass('open'); | |||
|
348 | } | |||
327 | // redraw the graph |
|
349 | // redraw the graph | |
328 | graph_options.height = $("#changesets").height(); |
|
350 | graph_options.height = $("#changesets").height(); | |
329 | $("canvas").remove(); |
|
351 | $("canvas").remove(); |
@@ -134,13 +134,6 b' collapse_all = len(diffset.files) > coll' | |||||
134 | '%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}} |
|
134 | '%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}} | |
135 | %endif |
|
135 | %endif | |
136 |
|
136 | |||
137 | <% at_ver = getattr(c, 'at_version_pos', None) %> |
|
|||
138 | % if at_ver: |
|
|||
139 | <div class="pull-right"> |
|
|||
140 | ${_('Showing changes at version %d') % at_ver} |
|
|||
141 | </div> |
|
|||
142 | % endif |
|
|||
143 |
|
||||
144 | </h2> |
|
137 | </h2> | |
145 | </div> |
|
138 | </div> | |
146 |
|
139 |
@@ -1,4 +1,5 b'' | |||||
1 | <%inherit file="/base/base.mako"/> |
|
1 | <%inherit file="/base/base.mako"/> | |
|
2 | <%namespace name="base" file="/base/base.mako"/> | |||
2 |
|
3 | |||
3 | <%def name="title()"> |
|
4 | <%def name="title()"> | |
4 | ${_('%s Pull Request #%s') % (c.repo_name, c.pull_request.pull_request_id)} |
|
5 | ${_('%s Pull Request #%s') % (c.repo_name, c.pull_request.pull_request_id)} | |
@@ -165,47 +166,23 b'' | |||||
165 | </div> |
|
166 | </div> | |
166 |
|
167 | |||
167 | <div class="field"> |
|
168 | <div class="field"> | |
168 |
|
|
169 | <div class="label-summary"> | |
169 |
|
|
170 | <label>${_('Versions')}:</label> | |
170 |
|
|
171 | </div> | |
|
172 | ||||
|
173 | <% outdated_comm_count_ver = len(c.inline_versions[None]['outdated']) %> | |||
|
174 | <% general_outdated_comm_count_ver = len(c.comment_versions[None]['outdated']) %> | |||
171 |
|
175 | |||
172 | <div class="pr-versions"> |
|
176 | <div class="pr-versions"> | |
173 | % if c.show_version_changes: |
|
177 | % if c.show_version_changes: | |
|
178 | <% outdated_comm_count_ver = len(c.inline_versions[c.at_version_num]['outdated']) %> | |||
|
179 | <% general_outdated_comm_count_ver = len(c.comment_versions[c.at_version_num]['outdated']) %> | |||
|
180 | <div id="show-pr-versions" class="input btn btn-link" onclick="return versionController.toggleVersionView(this)" | |||
|
181 | data-toggle-on="${ungettext('{} version available for this pull request, show it.', '{} versions available for this pull request, show them.', len(c.versions)).format(len(c.versions))}" | |||
|
182 | data-toggle-off="${_('Hide all versions of this pull request')}"> | |||
|
183 | ${ungettext('{} version available for this pull request, show it.', '{} versions available for this pull request, show them.', len(c.versions)).format(len(c.versions))} | |||
|
184 | </div> | |||
174 | <table> |
|
185 | <table> | |
175 | ## CURRENTLY SELECT PR VERSION |
|
|||
176 | <tr class="version-pr" style="display: ${'' if c.at_version_num is None else 'none'}"> |
|
|||
177 | <td> |
|
|||
178 | % if c.at_version_num is None: |
|
|||
179 | <i class="icon-ok link"></i> |
|
|||
180 | % else: |
|
|||
181 | <i class="icon-comment"></i> |
|
|||
182 | <code> |
|
|||
183 | ${len(c.comment_versions[None]['at'])}/${len(c.inline_versions[None]['at'])} |
|
|||
184 | </code> |
|
|||
185 | % endif |
|
|||
186 | </td> |
|
|||
187 | <td> |
|
|||
188 | <code> |
|
|||
189 | % if c.versions: |
|
|||
190 | <a href="${h.url.current(version='latest')}">${_('latest')}</a> |
|
|||
191 | % else: |
|
|||
192 | ${_('initial')} |
|
|||
193 | % endif |
|
|||
194 | </code> |
|
|||
195 | </td> |
|
|||
196 | <td> |
|
|||
197 | <code>${c.pull_request_latest.source_ref_parts.commit_id[:6]}</code> |
|
|||
198 | </td> |
|
|||
199 | <td> |
|
|||
200 | ${_('created')} ${h.age_component(c.pull_request_latest.updated_on)} |
|
|||
201 | </td> |
|
|||
202 | <td align="right"> |
|
|||
203 | % if c.versions and c.at_version_num in [None, 'latest']: |
|
|||
204 | <span id="show-pr-versions" class="btn btn-link" onclick="$('.version-pr').show(); $(this).hide(); return false">${_('Show all versions')}</span> |
|
|||
205 | % endif |
|
|||
206 | </td> |
|
|||
207 | </tr> |
|
|||
208 |
|
||||
209 | ## SHOW ALL VERSIONS OF PR |
|
186 | ## SHOW ALL VERSIONS OF PR | |
210 | <% ver_pr = None %> |
|
187 | <% ver_pr = None %> | |
211 |
|
188 | |||
@@ -213,46 +190,52 b'' | |||||
213 | <% ver_pos = data[0] %> |
|
190 | <% ver_pos = data[0] %> | |
214 | <% ver = data[1] %> |
|
191 | <% ver = data[1] %> | |
215 | <% ver_pr = ver.pull_request_version_id %> |
|
192 | <% ver_pr = ver.pull_request_version_id %> | |
|
193 | <% display_row = '' if c.at_version and (c.at_version_num == ver_pr or c.from_version_num == ver_pr) else 'none' %> | |||
216 |
|
194 | |||
217 |
<tr class="version-pr" style="display: ${ |
|
195 | <tr class="version-pr" style="display: ${display_row}"> | |
|
196 | <td> | |||
|
197 | <code> | |||
|
198 | <a href="${h.url.current(version=ver_pr or 'latest')}">v${ver_pos}</a> | |||
|
199 | </code> | |||
|
200 | </td> | |||
218 | <td> |
|
201 | <td> | |
219 | % if c.at_version_num == ver_pr: |
|
202 | <input ${'checked="checked"' if c.from_version_num == ver_pr else ''} class="compare-radio-button" type="radio" name="ver_source" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/> | |
220 | <i class="icon-ok link"></i> |
|
203 | <input ${'checked="checked"' if c.at_version_num == ver_pr else ''} class="compare-radio-button" type="radio" name="ver_target" value="${ver_pr or 'latest'}" data-ver-pos="${ver_pos}"/> | |
221 |
|
|
204 | </td> | |
|
205 | <td> | |||
|
206 | <% review_status = c.review_versions[ver_pr].status if ver_pr in c.review_versions else 'not_reviewed' %> | |||
|
207 | <div class="${'flag_status %s' % review_status} tooltip pull-left" title="${_('Your review status at this version')}"> | |||
|
208 | </div> | |||
|
209 | </td> | |||
|
210 | <td> | |||
|
211 | % if c.at_version_num != ver_pr: | |||
222 | <i class="icon-comment"></i> |
|
212 | <i class="icon-comment"></i> | |
223 | <code class="tooltip" title="${_('Comment from pull request version {0}, general:{1} inline{2}').format(ver_pos, len(c.comment_versions[ver_pr]['at']), len(c.inline_versions[ver_pr]['at']))}"> |
|
213 | <code class="tooltip" title="${_('Comment from pull request version {0}, general:{1} inline:{2}').format(ver_pos, len(c.comment_versions[ver_pr]['at']), len(c.inline_versions[ver_pr]['at']))}"> | |
224 | ${len(c.comment_versions[ver_pr]['at'])}/${len(c.inline_versions[ver_pr]['at'])} |
|
214 | ${len(c.comment_versions[ver_pr]['at'])}/${len(c.inline_versions[ver_pr]['at'])} | |
225 | </code> |
|
215 | </code> | |
226 | % endif |
|
216 | % endif | |
227 | </td> |
|
217 | </td> | |
228 | <td> |
|
218 | <td> | |
229 |
|
|
219 | ##<code>${ver.source_ref_parts.commit_id[:6]}</code> | |
230 | <a href="${h.url.current(version=ver_pr)}">v${ver_pos}</a> |
|
|||
231 | </code> |
|
|||
232 | </td> |
|
220 | </td> | |
233 | <td> |
|
221 | <td> | |
234 | <code>${ver.source_ref_parts.commit_id[:6]}</code> |
|
222 | ${h.age_component(ver.updated_on)} | |
235 | </td> |
|
|||
236 | <td> |
|
|||
237 | ${_('created')} ${h.age_component(ver.updated_on)} |
|
|||
238 | </td> |
|
|||
239 | <td align="right"> |
|
|||
240 | % if c.at_version_num == ver_pr: |
|
|||
241 | <span id="show-pr-versions" class="btn btn-link" onclick="$('.version-pr').show(); $(this).hide(); return false">${_('Show all versions')}</span> |
|
|||
242 | % endif |
|
|||
243 | </td> |
|
223 | </td> | |
244 | </tr> |
|
224 | </tr> | |
245 | % endfor |
|
225 | % endfor | |
246 |
|
|
226 | ||
247 | ## show comment/inline comments summary |
|
|||
248 |
|
|
227 | <tr> | |
249 | <td> |
|
228 | <td colspan="5"> | |
|
229 | <button id="show-version-diff" onclick="return versionController.showVersionDiff()" class="btn btn-sm" style="display: none" data-label-text="${_('show changes between versions')}"> | |||
|
230 | ${_('show changes between versions')} | |||
|
231 | </button> | |||
250 | </td> |
|
232 | </td> | |
|
233 | </tr> | |||
251 |
|
234 | |||
252 | <td colspan="4" style="border-top: 1px dashed #dbd9da"> |
|
235 | ## show comment/inline comments summary | |
253 | <% outdated_comm_count_ver = len(c.inline_versions[c.at_version_num]['outdated']) %> |
|
236 | <%def name="comments_summary()"> | |
254 | <% general_outdated_comm_count_ver = len(c.comment_versions[c.at_version_num]['outdated']) %> |
|
237 | <tr> | |
255 |
|
238 | <td colspan="6" class="comments-summary-td"> | ||
256 |
|
239 | |||
257 | % if c.at_version: |
|
240 | % if c.at_version: | |
258 | <% inline_comm_count_ver = len(c.inline_versions[c.at_version_num]['display']) %> |
|
241 | <% inline_comm_count_ver = len(c.inline_versions[c.at_version_num]['display']) %> | |
@@ -264,6 +247,7 b'' | |||||
264 | ${_('Comments for this pull request')}: |
|
247 | ${_('Comments for this pull request')}: | |
265 | % endif |
|
248 | % endif | |
266 |
|
249 | |||
|
250 | ||||
267 | %if general_comm_count_ver: |
|
251 | %if general_comm_count_ver: | |
268 | <a href="#comments">${_("%d General ") % general_comm_count_ver}</a> |
|
252 | <a href="#comments">${_("%d General ") % general_comm_count_ver}</a> | |
269 | %else: |
|
253 | %else: | |
@@ -285,37 +269,18 b'' | |||||
285 | %endif |
|
269 | %endif | |
286 | </td> |
|
270 | </td> | |
287 | </tr> |
|
271 | </tr> | |
288 |
|
272 | </%def> | ||
289 |
|
|
273 | ${comments_summary()} | |
290 | <td></td> |
|
|||
291 | <td colspan="4"> |
|
|||
292 | % if c.at_version: |
|
|||
293 | <pre> |
|
|||
294 | Changed commits: |
|
|||
295 | * added: ${len(c.changes.added)} |
|
|||
296 | * removed: ${len(c.changes.removed)} |
|
|||
297 |
|
||||
298 | % if not (c.file_changes.added+c.file_changes.modified+c.file_changes.removed): |
|
|||
299 | No file changes found |
|
|||
300 | % else: |
|
|||
301 | Changed files: |
|
|||
302 | %for file_name in c.file_changes.added: |
|
|||
303 | * A <a href="#${'a_' + h.FID('', file_name)}">${file_name}</a> |
|
|||
304 | %endfor |
|
|||
305 | %for file_name in c.file_changes.modified: |
|
|||
306 | * M <a href="#${'a_' + h.FID('', file_name)}">${file_name}</a> |
|
|||
307 | %endfor |
|
|||
308 | %for file_name in c.file_changes.removed: |
|
|||
309 | * R ${file_name} |
|
|||
310 | %endfor |
|
|||
311 | % endif |
|
|||
312 | </pre> |
|
|||
313 | % endif |
|
|||
314 | </td> |
|
|||
315 | </tr> |
|
|||
316 | </table> |
|
274 | </table> | |
317 | % else: |
|
275 | % else: | |
|
276 | <div class="input"> | |||
318 | ${_('Pull request versions not available')}. |
|
277 | ${_('Pull request versions not available')}. | |
|
278 | </div> | |||
|
279 | <div> | |||
|
280 | <table> | |||
|
281 | ${comments_summary()} | |||
|
282 | </table> | |||
|
283 | </div> | |||
319 | % endif |
|
284 | % endif | |
320 | </div> |
|
285 | </div> | |
321 | </div> |
|
286 | </div> | |
@@ -426,7 +391,15 b' Changed files:' | |||||
426 | </div> |
|
391 | </div> | |
427 | </div> |
|
392 | </div> | |
428 | % endif |
|
393 | % endif | |
429 | <div class="compare_view_commits_title"> |
|
394 | ||
|
395 | <div class="compare_view_commits_title"> | |||
|
396 | % if not c.compare_mode: | |||
|
397 | ||||
|
398 | % if c.at_version_pos: | |||
|
399 | <h4> | |||
|
400 | ${_('Showing changes at v%d, commenting is disabled.') % c.at_version_pos} | |||
|
401 | </h4> | |||
|
402 | % endif | |||
430 |
|
403 | |||
431 | <div class="pull-left"> |
|
404 | <div class="pull-left"> | |
432 | <div class="btn-group"> |
|
405 | <div class="btn-group"> | |
@@ -453,11 +426,113 b' Changed files:' | |||||
453 | % endif |
|
426 | % endif | |
454 |
|
427 | |||
455 | </div> |
|
428 | </div> | |
456 |
|
429 | % endif | ||
457 |
|
|
430 | </div> | |
458 |
|
431 | |||
459 | % if not c.missing_commits: |
|
432 | % if not c.missing_commits: | |
460 | <%include file="/compare/compare_commits.mako" /> |
|
433 | % if c.compare_mode: | |
|
434 | % if c.at_version: | |||
|
435 | <h4> | |||
|
436 | ${_('Commits and changes between v{ver_from} and {ver_to} of this pull request, commenting is disabled').format(ver_from=c.from_version_pos, ver_to=c.at_version_pos if c.at_version_pos else 'latest')}: | |||
|
437 | </h4> | |||
|
438 | ||||
|
439 | <div class="subtitle-compare"> | |||
|
440 | ${_('commits added: {}, removed: {}').format(len(c.commit_changes_summary.added), len(c.commit_changes_summary.removed))} | |||
|
441 | </div> | |||
|
442 | ||||
|
443 | <div class="container"> | |||
|
444 | <table class="rctable compare_view_commits"> | |||
|
445 | <tr> | |||
|
446 | <th></th> | |||
|
447 | <th>${_('Time')}</th> | |||
|
448 | <th>${_('Author')}</th> | |||
|
449 | <th>${_('Commit')}</th> | |||
|
450 | <th></th> | |||
|
451 | <th>${_('Description')}</th> | |||
|
452 | </tr> | |||
|
453 | ||||
|
454 | % for c_type, commit in c.commit_changes: | |||
|
455 | % if c_type in ['a', 'r']: | |||
|
456 | <% | |||
|
457 | if c_type == 'a': | |||
|
458 | cc_title = _('Commit added in displayed changes') | |||
|
459 | elif c_type == 'r': | |||
|
460 | cc_title = _('Commit removed in displayed changes') | |||
|
461 | else: | |||
|
462 | cc_title = '' | |||
|
463 | %> | |||
|
464 | <tr id="row-${commit.raw_id}" commit_id="${commit.raw_id}" class="compare_select"> | |||
|
465 | <td> | |||
|
466 | <div class="commit-change-indicator color-${c_type}-border"> | |||
|
467 | <div class="commit-change-content color-${c_type} tooltip" title="${cc_title}"> | |||
|
468 | ${c_type.upper()} | |||
|
469 | </div> | |||
|
470 | </div> | |||
|
471 | </td> | |||
|
472 | <td class="td-time"> | |||
|
473 | ${h.age_component(commit.date)} | |||
|
474 | </td> | |||
|
475 | <td class="td-user"> | |||
|
476 | ${base.gravatar_with_user(commit.author, 16)} | |||
|
477 | </td> | |||
|
478 | <td class="td-hash"> | |||
|
479 | <code> | |||
|
480 | <a href="${h.url('changeset_home', repo_name=c.target_repo.repo_name, revision=commit.raw_id)}"> | |||
|
481 | r${commit.revision}:${h.short_id(commit.raw_id)} | |||
|
482 | </a> | |||
|
483 | ${h.hidden('revisions', commit.raw_id)} | |||
|
484 | </code> | |||
|
485 | </td> | |||
|
486 | <td class="expand_commit" data-commit-id="${commit.raw_id}" title="${_( 'Expand commit message')}"> | |||
|
487 | <div class="show_more_col"> | |||
|
488 | <i class="show_more"></i> | |||
|
489 | </div> | |||
|
490 | </td> | |||
|
491 | <td class="mid td-description"> | |||
|
492 | <div class="log-container truncate-wrap"> | |||
|
493 | <div class="message truncate" id="c-${commit.raw_id}" data-message-raw="${commit.message}"> | |||
|
494 | ${h.urlify_commit_message(commit.message, c.repo_name)} | |||
|
495 | </div> | |||
|
496 | </div> | |||
|
497 | </td> | |||
|
498 | </tr> | |||
|
499 | % endif | |||
|
500 | % endfor | |||
|
501 | </table> | |||
|
502 | </div> | |||
|
503 | ||||
|
504 | <script> | |||
|
505 | $('.expand_commit').on('click',function(e){ | |||
|
506 | var target_expand = $(this); | |||
|
507 | var cid = target_expand.data('commitId'); | |||
|
508 | ||||
|
509 | if (target_expand.hasClass('open')){ | |||
|
510 | $('#c-'+cid).css({ | |||
|
511 | 'height': '1.5em', | |||
|
512 | 'white-space': 'nowrap', | |||
|
513 | 'text-overflow': 'ellipsis', | |||
|
514 | 'overflow':'hidden' | |||
|
515 | }); | |||
|
516 | target_expand.removeClass('open'); | |||
|
517 | } | |||
|
518 | else { | |||
|
519 | $('#c-'+cid).css({ | |||
|
520 | 'height': 'auto', | |||
|
521 | 'white-space': 'pre-line', | |||
|
522 | 'text-overflow': 'initial', | |||
|
523 | 'overflow':'visible' | |||
|
524 | }); | |||
|
525 | target_expand.addClass('open'); | |||
|
526 | } | |||
|
527 | }); | |||
|
528 | </script> | |||
|
529 | ||||
|
530 | % endif | |||
|
531 | ||||
|
532 | % else: | |||
|
533 | <%include file="/compare/compare_commits.mako" /> | |||
|
534 | % endif | |||
|
535 | ||||
461 | <div class="cs_files"> |
|
536 | <div class="cs_files"> | |
462 | <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/> |
|
537 | <%namespace name="cbdiffs" file="/codeblocks/diffs.mako"/> | |
463 | ${cbdiffs.render_diffset_menu()} |
|
538 | ${cbdiffs.render_diffset_menu()} | |
@@ -528,6 +603,107 b' Changed files:' | |||||
528 | } |
|
603 | } | |
529 | } |
|
604 | } | |
530 |
|
605 | |||
|
606 | VersionController = function() { | |||
|
607 | var self = this; | |||
|
608 | this.$verSource = $('input[name=ver_source]'); | |||
|
609 | this.$verTarget = $('input[name=ver_target]'); | |||
|
610 | ||||
|
611 | this.adjustRadioSelectors = function (curNode) { | |||
|
612 | var getVal = function(item) { | |||
|
613 | if (item == 'latest'){ | |||
|
614 | return Number.MAX_SAFE_INTEGER | |||
|
615 | } | |||
|
616 | else { | |||
|
617 | return parseInt(item) | |||
|
618 | } | |||
|
619 | }; | |||
|
620 | ||||
|
621 | var curVal = getVal($(curNode).val()); | |||
|
622 | $.each(self.$verSource, function(index, value){ | |||
|
623 | var elVal = getVal($(value).val()); | |||
|
624 | if(elVal > curVal){ | |||
|
625 | $(value).attr('disabled', 'disabled'); | |||
|
626 | $(value).removeAttr('checked'); | |||
|
627 | } | |||
|
628 | else{ | |||
|
629 | $(value).removeAttr('disabled'); | |||
|
630 | } | |||
|
631 | }); | |||
|
632 | ||||
|
633 | self.setLockAction(false, $(curNode).data('verPos')); | |||
|
634 | }; | |||
|
635 | ||||
|
636 | ||||
|
637 | this.attachVersionListener = function () { | |||
|
638 | self.$verTarget.change(function(e){ | |||
|
639 | self.adjustRadioSelectors(this) | |||
|
640 | }); | |||
|
641 | self.$verSource.change(function(e){ | |||
|
642 | self.adjustRadioSelectors(self.$verTarget.filter(':checked')) | |||
|
643 | }); | |||
|
644 | }; | |||
|
645 | ||||
|
646 | this.init = function () { | |||
|
647 | ||||
|
648 | var curNode = self.$verTarget.filter(':checked'); | |||
|
649 | self.adjustRadioSelectors(curNode); | |||
|
650 | self.setLockAction(true); | |||
|
651 | self.attachVersionListener(); | |||
|
652 | ||||
|
653 | }; | |||
|
654 | ||||
|
655 | this.setLockAction = function (state, selectedVersion) { | |||
|
656 | if(state){ | |||
|
657 | $('#show-version-diff').attr('disabled','disabled') | |||
|
658 | $('#show-version-diff').addClass('disabled') | |||
|
659 | $('#show-version-diff').html($('#show-version-diff').data('labelText')); | |||
|
660 | } | |||
|
661 | else{ | |||
|
662 | $('#show-version-diff').removeAttr('disabled'); | |||
|
663 | $('#show-version-diff').removeClass('disabled') | |||
|
664 | //$('#show-version-diff').html(_gettext('show changes for v') + selectedVersion) | |||
|
665 | } | |||
|
666 | ||||
|
667 | }; | |||
|
668 | ||||
|
669 | this.showVersionDiff = function(){ | |||
|
670 | var target = self.$verTarget.filter(':checked'); | |||
|
671 | var source = self.$verSource.filter(':checked'); | |||
|
672 | ||||
|
673 | if (target.val() && source.val()) { | |||
|
674 | var params = { | |||
|
675 | 'pull_request_id': ${c.pull_request.pull_request_id}, | |||
|
676 | 'repo_name': templateContext.repo_name, | |||
|
677 | 'version': target.val(), | |||
|
678 | 'from_version': source.val() | |||
|
679 | }; | |||
|
680 | window.location = pyroutes.url('pullrequest_show', params) | |||
|
681 | } | |||
|
682 | ||||
|
683 | return false; | |||
|
684 | }; | |||
|
685 | ||||
|
686 | this.toggleVersionView = function (elem) { | |||
|
687 | ||||
|
688 | if ($('#show-version-diff').is(':visible')) { | |||
|
689 | $('.version-pr').hide(); | |||
|
690 | $('#show-version-diff').hide(); | |||
|
691 | $(elem).html($(elem).data('toggleOn')) | |||
|
692 | } else { | |||
|
693 | $('.version-pr').show(); | |||
|
694 | $('#show-version-diff').show(); | |||
|
695 | $(elem).html($(elem).data('toggleOff')) | |||
|
696 | } | |||
|
697 | ||||
|
698 | return false | |||
|
699 | } | |||
|
700 | ||||
|
701 | }; | |||
|
702 | ||||
|
703 | versionController = new VersionController(); | |||
|
704 | versionController.init(); | |||
|
705 | ||||
|
706 | ||||
531 | $(function(){ |
|
707 | $(function(){ | |
532 | ReviewerAutoComplete('user'); |
|
708 | ReviewerAutoComplete('user'); | |
533 | // custom code mirror |
|
709 | // custom code mirror |
General Comments 0
You need to be logged in to leave comments.
Login now