def comment(self, repo_name, revision): comm = ChangesetCommentsModel().create( text=request.POST.get('text'), repo_id=c.rhodecode_db_repo.repo_id, user_id=c.rhodecode_user.user_id, revision=revision, f_path=request.POST.get('f_path'), line_no=request.POST.get('line')) Session.commit() if not request.environ.get('HTTP_X_PARTIAL_XHR'): return redirect( h.url('changeset_home', repo_name=repo_name, revision=revision)) data = { 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), } if comm: c.co = comm data.update(comm.get_dict()) data.update({ 'rendered_text': render('changeset/changeset_comment_block.html') }) return data
def show(self, repo_name, pull_request_id): repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() c.pull_request = PullRequest.get_or_404(pull_request_id) c.allowed_to_change_status = self._get_is_allowed_change_status(c.pull_request) cc_model = ChangesetCommentsModel() cs_model = ChangesetStatusModel() _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo, pull_request=c.pull_request, with_revisions=True) cs_statuses = defaultdict(list) for st in _cs_statuses: cs_statuses[st.author.username] += [st] c.pull_request_reviewers = [] c.pull_request_pending_reviewers = [] for o in c.pull_request.reviewers: st = cs_statuses.get(o.user.username, None) if st: sorter = lambda k: k.version st = [(x, list(y)[0]) for x, y in (groupby(sorted(st, key=sorter), sorter))] else: c.pull_request_pending_reviewers.append(o.user) c.pull_request_reviewers.append([o.user, st]) # pull_requests repo_name we opened it against # ie. other_repo must match if repo_name != c.pull_request.other_repo.repo_name: raise HTTPNotFound # load compare data into template context enable_comments = not c.pull_request.is_closed() self._load_compare_data(c.pull_request, enable_comments=enable_comments) # inline comments c.inline_cnt = 0 c.inline_comments = cc_model.get_inline_comments( c.rhodecode_db_repo.repo_id, pull_request=pull_request_id) # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) # comments c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id, pull_request=pull_request_id) # (badly named) pull-request status calculation based on reviewer votes c.current_changeset_status = cs_model.calculate_status( c.pull_request_reviewers, ) c.changeset_statuses = ChangesetStatus.STATUSES c.as_form = False c.ancestor = None # there is one - but right here we don't know which return render('/pullrequests/pullrequest_show.html')
def show(self, repo_name, pull_request_id): repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() c.pull_request = PullRequest.get_or_404(pull_request_id) c.allowed_to_change_status = self._get_is_allowed_change_status( c.pull_request) cc_model = ChangesetCommentsModel() cs_model = ChangesetStatusModel() _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo, pull_request=c.pull_request, with_revisions=True) cs_statuses = defaultdict(list) for st in _cs_statuses: cs_statuses[st.author.username] += [st] c.pull_request_reviewers = [] c.pull_request_pending_reviewers = [] for o in c.pull_request.reviewers: st = cs_statuses.get(o.user.username, None) if st: sorter = lambda k: k.version st = [(x, list(y)[0]) for x, y in (groupby(sorted(st, key=sorter), sorter))] else: c.pull_request_pending_reviewers.append(o.user) c.pull_request_reviewers.append([o.user, st]) # pull_requests repo_name we opened it against # ie. other_repo must match if repo_name != c.pull_request.other_repo.repo_name: raise HTTPNotFound # load compare data into template context enable_comments = not c.pull_request.is_closed() self._load_compare_data(c.pull_request, enable_comments=enable_comments) # inline comments c.inline_cnt = 0 c.inline_comments = cc_model.get_inline_comments( c.rhodecode_db_repo.repo_id, pull_request=pull_request_id) # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) # comments c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id, pull_request=pull_request_id) # (badly named) pull-request status calculation based on reviewer votes c.current_changeset_status = cs_model.calculate_status( c.pull_request_reviewers, ) c.changeset_statuses = ChangesetStatus.STATUSES c.as_form = False c.ancestor = None # there is one - but right here we don't know which return render('/pullrequests/pullrequest_show.html')
def comment(self, repo_name, pull_request_id): pull_request = PullRequest.get_or_404(pull_request_id) if pull_request.is_closed(): raise HTTPForbidden() status = request.POST.get('changeset_status') change_status = request.POST.get('change_changeset_status') text = request.POST.get('text') if status and change_status: text = text or (_('Status change -> %s') % ChangesetStatus.get_status_lbl(status)) comm = ChangesetCommentsModel().create( text=text, repo=c.rhodecode_db_repo.repo_id, user=c.rhodecode_user.user_id, pull_request=pull_request_id, f_path=request.POST.get('f_path'), line_no=request.POST.get('line'), status_change=(ChangesetStatus.get_status_lbl(status) if status and change_status else None) ) # get status if set ! if status and change_status: ChangesetStatusModel().set_status( c.rhodecode_db_repo.repo_id, status, c.rhodecode_user.user_id, comm, pull_request=pull_request_id ) action_logger(self.rhodecode_user, 'user_commented_pull_request:%s' % pull_request_id, c.rhodecode_db_repo, self.ip_addr, self.sa) if request.POST.get('save_close'): PullRequestModel().close_pull_request(pull_request_id) action_logger(self.rhodecode_user, 'user_closed_pull_request:%s' % pull_request_id, c.rhodecode_db_repo, self.ip_addr, self.sa) Session().commit() if not request.environ.get('HTTP_X_PARTIAL_XHR'): return redirect(h.url('pullrequest_show', repo_name=repo_name, pull_request_id=pull_request_id)) data = { 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), } if comm: c.co = comm data.update(comm.get_dict()) data.update({'rendered_text': render('changeset/changeset_comment_block.html')}) return data
def assert_inline_comments(pull_request, visible=None, outdated=None): if visible is not None: inline_comments = ChangesetCommentsModel().get_inline_comments( pull_request.target_repo.repo_id, pull_request=pull_request) assert len(inline_comments) == visible if outdated is not None: outdated_comments = ChangesetCommentsModel().get_outdated_comments( pull_request.target_repo.repo_id, pull_request) assert len(outdated_comments) == outdated
def comment(self, repo_name, revision): status = request.POST.get('changeset_status') change_status = request.POST.get('change_changeset_status') text = request.POST.get('text') if status and change_status: text = text or (_('Status change -> %s') % ChangesetStatus.get_status_lbl(status)) c.co = comm = ChangesetCommentsModel().create( text=text, repo=c.rhodecode_db_repo.repo_id, user=c.rhodecode_user.user_id, revision=revision, f_path=request.POST.get('f_path'), line_no=request.POST.get('line'), status_change=(ChangesetStatus.get_status_lbl(status) if status and change_status else None) ) # get status if set ! if status and change_status: # if latest status was from pull request and it's closed # disallow changing status ! # dont_allow_on_closed_pull_request = True ! try: ChangesetStatusModel().set_status( c.rhodecode_db_repo.repo_id, status, c.rhodecode_user.user_id, comm, revision=revision, dont_allow_on_closed_pull_request=True ) except StatusChangeOnClosedPullRequestError: log.error(traceback.format_exc()) msg = _('Changing status on a changeset associated with ' 'a closed pull request is not allowed') h.flash(msg, category='warning') return redirect(h.url('changeset_home', repo_name=repo_name, revision=revision)) action_logger(self.rhodecode_user, 'user_commented_revision:%s' % revision, c.rhodecode_db_repo, self.ip_addr, self.sa) Session().commit() if not request.environ.get('HTTP_X_PARTIAL_XHR'): return redirect(h.url('changeset_home', repo_name=repo_name, revision=revision)) #only ajax below data = { 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), } if comm: data.update(comm.get_dict()) data.update({'rendered_text': render('changeset/changeset_comment_block.html')}) return data
def close_pull_request_with_comment(self, pull_request, user, repo, message=None): status = ChangesetStatus.STATUS_REJECTED if not message: message = (_('Status change %(transition_icon)s %(status)s') % { 'transition_icon': '>', 'status': ChangesetStatus.get_status_lbl(status) }) internal_message = _('Closing with') + ' ' + message comm = ChangesetCommentsModel().create( text=internal_message, repo=repo.repo_id, user=user.user_id, pull_request=pull_request.pull_request_id, f_path=None, line_no=None, status_change=ChangesetStatus.get_status_lbl(status), closing_pr=True) ChangesetStatusModel().set_status( repo.repo_id, status, user.user_id, comm, pull_request=pull_request.pull_request_id) Session().flush() PullRequestModel().close_pull_request(pull_request.pull_request_id, user)
def test_api_comment_pull_request(self, pr_util, no_notifications): pull_request = pr_util.create_pull_request() pull_request_id = pull_request.pull_request_id author = pull_request.user_id repo = pull_request.target_repo.repo_id id_, params = build_data(self.apikey, 'comment_pull_request', repoid=pull_request.target_repo.repo_name, pullrequestid=pull_request.pull_request_id, message='test message') response = api_call(self.app, params) pull_request = PullRequestModel().get(pull_request.pull_request_id) comments = ChangesetCommentsModel().get_comments( pull_request.target_repo.repo_id, pull_request=pull_request) expected = { 'pull_request_id': pull_request.pull_request_id, 'comment_id': comments[-1].comment_id, 'status': None } assert_ok(id_, expected, response.body) action = 'user_commented_pull_request:%d' % pull_request_id journal = UserLog.query()\ .filter(UserLog.user_id == author)\ .filter(UserLog.repository_id == repo)\ .filter(UserLog.action == action)\ .all() assert len(journal) == 2
def delete_comment(self, repo_name, comment_id): co = ChangesetComment.get(comment_id) owner = lambda: co.author.user_id == c.rhodecode_user.user_id if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner: ChangesetCommentsModel().delete(comment=co) Session.commit() return True else: raise HTTPForbidden()
def delete_comment(self, repo_name, comment_id): comment = ChangesetComment.get(comment_id) owner = (comment.author.user_id == c.rhodecode_user.user_id) is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) if h.HasPermissionAny('hg.admin')() or is_repo_admin or owner: ChangesetCommentsModel().delete(comment=comment) Session().commit() return True else: raise HTTPForbidden()
def delete_comment(self, repo_name, comment_id): co = ChangesetComment.get(comment_id) if co.pull_request.is_closed(): #don't allow deleting comments on closed pull request raise HTTPForbidden() owner = co.author.user_id == c.rhodecode_user.user_id if h.HasPermissionAny('hg.admin', 'repository.admin')() or owner: ChangesetCommentsModel().delete(comment=co) Session().commit() return True else: raise HTTPForbidden()
def _generate_update_diffs(self, pull_request, pull_request_version): diff_context = (self.DIFF_CONTEXT + ChangesetCommentsModel.needed_extra_diff_context()) old_diff = self._get_diff_from_pr_or_version(pull_request_version, context=diff_context) new_diff = self._get_diff_from_pr_or_version(pull_request, context=diff_context) old_diff_data = diffs.DiffProcessor(old_diff) old_diff_data.prepare() new_diff_data = diffs.DiffProcessor(new_diff) new_diff_data.prepare() return old_diff_data, new_diff_data
def comment(self, repo_name, revision): comm = ChangesetCommentsModel().create( text=request.POST.get('text'), repo_id=c.rhodecode_db_repo.repo_id, user_id=c.rhodecode_user.user_id, revision=revision, f_path=request.POST.get('f_path'), line_no=request.POST.get('line') ) Session.commit() if not request.environ.get('HTTP_X_PARTIAL_XHR'): return redirect(h.url('changeset_home', repo_name=repo_name, revision=revision)) data = { 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), } if comm: c.co = comm data.update(comm.get_dict()) data.update({'rendered_text': render('changeset/changeset_comment_block.html')}) return data
def _comment_and_close_pr(self, pull_request, user, merge_state): pull_request.merge_rev = merge_state.merge_commit_id pull_request.updated_on = datetime.datetime.now() ChangesetCommentsModel().create( text=unicode(_('Pull request merged and closed')), repo=pull_request.target_repo.repo_id, user=user.user_id, pull_request=pull_request.pull_request_id, f_path=None, line_no=None, closing_pr=True) Session().add(pull_request) Session().flush() # TODO: paris: replace invalidation with less radical solution ScmModel().mark_for_invalidation(pull_request.target_repo.repo_name) self._trigger_pull_request_hook(pull_request, user, 'merge')
def _delete_comment(self, comment_id): comment_id = safe_int(comment_id) co = ChangesetComment.get_or_404(comment_id) if co.pull_request.is_closed(): # don't allow deleting comments on closed pull request raise HTTPForbidden() is_owner = co.author.user_id == c.rhodecode_user.user_id is_repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name) if h.HasPermissionAny('hg.admin')() or is_repo_admin or is_owner: old_calculated_status = co.pull_request.calculated_review_status() ChangesetCommentsModel().delete(comment=co) Session().commit() calculated_status = co.pull_request.calculated_review_status() if old_calculated_status != calculated_status: PullRequestModel()._trigger_pull_request_hook( co.pull_request, c.rhodecode_user, 'review_status_change') return True else: raise HTTPForbidden()
def test_api_comment_pull_request_change_status(self, pr_util, no_notifications): pull_request = pr_util.create_pull_request() pull_request_id = pull_request.pull_request_id id_, params = build_data(self.apikey, 'comment_pull_request', repoid=pull_request.target_repo.repo_name, pullrequestid=pull_request.pull_request_id, status='rejected') response = api_call(self.app, params) pull_request = PullRequestModel().get(pull_request_id) comments = ChangesetCommentsModel().get_comments( pull_request.target_repo.repo_id, pull_request=pull_request) expected = { 'pull_request_id': pull_request.pull_request_id, 'comment_id': comments[-1].comment_id, 'status': 'rejected' } assert_ok(id_, expected, response.body)
def show(self, repo_name, pull_request_id): pull_request_id = safe_int(pull_request_id) c.pull_request = PullRequest.get_or_404(pull_request_id) # pull_requests repo_name we opened it against # ie. target_repo must match if repo_name != c.pull_request.target_repo.repo_name: raise HTTPNotFound c.allowed_to_change_status = PullRequestModel(). \ check_user_change_status(c.pull_request, c.rhodecode_user) c.allowed_to_update = PullRequestModel().check_user_update( c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed() c.allowed_to_merge = PullRequestModel().check_user_merge( c.pull_request, c.rhodecode_user) and not c.pull_request.is_closed() cc_model = ChangesetCommentsModel() c.pull_request_reviewers = c.pull_request.reviewers_statuses() c.pull_request_review_status = c.pull_request.calculated_review_status( ) c.pr_merge_status, c.pr_merge_msg = PullRequestModel().merge_status( c.pull_request) c.approval_msg = None if c.pull_request_review_status != ChangesetStatus.STATUS_APPROVED: c.approval_msg = _('Reviewer approval is pending.') c.pr_merge_status = False # load compare data into template context enable_comments = not c.pull_request.is_closed() self._load_compare_data(c.pull_request, enable_comments=enable_comments) # this is a hack to properly display links, when creating PR, the # compare view and others uses different notation, and # compare_commits.html renders links based on the target_repo. # We need to swap that here to generate it properly on the html side c.target_repo = c.source_repo # inline comments c.inline_cnt = 0 c.inline_comments = cc_model.get_inline_comments( c.rhodecode_db_repo.repo_id, pull_request=pull_request_id).items() # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) # outdated comments c.outdated_cnt = 0 if ChangesetCommentsModel.use_outdated_comments(c.pull_request): c.outdated_comments = cc_model.get_outdated_comments( c.rhodecode_db_repo.repo_id, pull_request=c.pull_request) # Count outdated comments and check for deleted files for file_name, lines in c.outdated_comments.iteritems(): for comments in lines.values(): c.outdated_cnt += len(comments) if file_name not in c.included_files: c.deleted_files.append(file_name) else: c.outdated_comments = {} # comments c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id, pull_request=pull_request_id) if c.allowed_to_update: force_close = ('forced_closed', _('Close Pull Request')) statuses = ChangesetStatus.STATUSES + [force_close] else: statuses = ChangesetStatus.STATUSES c.commit_statuses = statuses c.ancestor = None # TODO: add ancestor here return render('/pullrequests/pullrequest_show.html')
def comment(self, repo_name, pull_request_id): pull_request_id = safe_int(pull_request_id) pull_request = PullRequest.get_or_404(pull_request_id) if pull_request.is_closed(): raise HTTPForbidden() # TODO: johbo: Re-think this bit, "approved_closed" does not exist # as a changeset status, still we want to send it in one value. status = request.POST.get('changeset_status', None) text = request.POST.get('text') if status and '_closed' in status: close_pr = True status = status.replace('_closed', '') else: close_pr = False forced = (status == 'forced') if forced: status = 'rejected' allowed_to_change_status = PullRequestModel().check_user_change_status( pull_request, c.rhodecode_user) if status and allowed_to_change_status: message = (_('Status change %(transition_icon)s %(status)s') % { 'transition_icon': '>', 'status': ChangesetStatus.get_status_lbl(status) }) if close_pr: message = _('Closing with') + ' ' + message text = text or message comm = ChangesetCommentsModel().create( text=text, repo=c.rhodecode_db_repo.repo_id, user=c.rhodecode_user.user_id, pull_request=pull_request_id, f_path=request.POST.get('f_path'), line_no=request.POST.get('line'), status_change=(ChangesetStatus.get_status_lbl(status) if status and allowed_to_change_status else None), closing_pr=close_pr) if allowed_to_change_status: old_calculated_status = pull_request.calculated_review_status() # get status if set ! if status: ChangesetStatusModel().set_status(c.rhodecode_db_repo.repo_id, status, c.rhodecode_user.user_id, comm, pull_request=pull_request_id) Session().flush() # we now calculate the status of pull request, and based on that # calculation we set the commits status calculated_status = pull_request.calculated_review_status() if old_calculated_status != calculated_status: PullRequestModel()._trigger_pull_request_hook( pull_request, c.rhodecode_user, 'review_status_change') calculated_status_lbl = ChangesetStatus.get_status_lbl( calculated_status) if close_pr: status_completed = (calculated_status in [ ChangesetStatus.STATUS_APPROVED, ChangesetStatus.STATUS_REJECTED ]) if forced or status_completed: PullRequestModel().close_pull_request( pull_request_id, c.rhodecode_user) else: h.flash(_('Closing pull request on other statuses than ' 'rejected or approved is forbidden. ' 'Calculated status from all reviewers ' 'is currently: %s') % calculated_status_lbl, category='warning') Session().commit() if not request.is_xhr: return redirect( h.url('pullrequest_show', repo_name=repo_name, pull_request_id=pull_request_id)) data = { 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), } if comm: c.co = comm data.update(comm.get_dict()) data.update({ 'rendered_text': render('changeset/changeset_comment_block.html') }) return data
class ChangesetController(BaseRepoController): @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def __before__(self): super(ChangesetController, self).__before__() c.affected_files_cut_off = 60 def index(self, revision): c.anchor_url = anchor_url c.ignorews_url = _ignorews_url c.context_url = _context_url limit_off = request.GET.get('fulldiff') #get ranges of revisions if preset rev_range = revision.split('...')[:2] enable_comments = True try: if len(rev_range) == 2: enable_comments = False rev_start = rev_range[0] rev_end = rev_range[1] rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start, end=rev_end) else: rev_ranges = [c.rhodecode_repo.get_changeset(revision)] c.cs_ranges = list(rev_ranges) if not c.cs_ranges: raise RepositoryError('Changeset range returned empty result') except (RepositoryError, ChangesetDoesNotExistError, Exception), e: log.error(traceback.format_exc()) h.flash(str(e), category='warning') return redirect(url('home')) c.changes = OrderedDict() c.lines_added = 0 # count of lines added c.lines_deleted = 0 # count of lines removes cumulative_diff = 0 c.cut_off = False # defines if cut off limit is reached c.comments = [] c.inline_comments = [] c.inline_cnt = 0 # Iterate over ranges (default changeset view is always one changeset) for changeset in c.cs_ranges: c.comments.extend(ChangesetCommentsModel()\ .get_comments(c.rhodecode_db_repo.repo_id, changeset.raw_id)) inlines = ChangesetCommentsModel()\ .get_inline_comments(c.rhodecode_db_repo.repo_id, changeset.raw_id) c.inline_comments.extend(inlines) c.changes[changeset.raw_id] = [] try: changeset_parent = changeset.parents[0] except IndexError: changeset_parent = None #================================================================== # ADDED FILES #================================================================== for node in changeset.added: fid = h.FID(revision, node.path) line_context_lcl = get_line_ctx(fid, request.GET) ign_whitespace_lcl = get_ignore_ws(fid, request.GET) lim = self.cut_off_limit if cumulative_diff > self.cut_off_limit: lim = -1 if limit_off is None else None size, cs1, cs2, diff, st = wrapped_diff( filenode_old=None, filenode_new=node, cut_off_limit=lim, ignore_whitespace=ign_whitespace_lcl, line_context=line_context_lcl, enable_comments=enable_comments) cumulative_diff += size c.lines_added += st[0] c.lines_deleted += st[1] c.changes[changeset.raw_id].append( ('added', node, diff, cs1, cs2, st)) #================================================================== # CHANGED FILES #================================================================== for node in changeset.changed: try: filenode_old = changeset_parent.get_node(node.path) except ChangesetError: log.warning('Unable to fetch parent node for diff') filenode_old = FileNode(node.path, '', EmptyChangeset()) fid = h.FID(revision, node.path) line_context_lcl = get_line_ctx(fid, request.GET) ign_whitespace_lcl = get_ignore_ws(fid, request.GET) lim = self.cut_off_limit if cumulative_diff > self.cut_off_limit: lim = -1 if limit_off is None else None size, cs1, cs2, diff, st = wrapped_diff( filenode_old=filenode_old, filenode_new=node, cut_off_limit=lim, ignore_whitespace=ign_whitespace_lcl, line_context=line_context_lcl, enable_comments=enable_comments) cumulative_diff += size c.lines_added += st[0] c.lines_deleted += st[1] c.changes[changeset.raw_id].append( ('changed', node, diff, cs1, cs2, st)) #================================================================== # REMOVED FILES #================================================================== for node in changeset.removed: c.changes[changeset.raw_id].append( ('removed', node, None, None, None, (0, 0))) # count inline comments for path, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) if len(c.cs_ranges) == 1: c.changeset = c.cs_ranges[0] c.changes = c.changes[c.changeset.raw_id] return render('changeset/changeset.html') else: return render('changeset/changeset_range.html')
def show(self, repo_name, pull_request_id): repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() c.pull_request = PullRequest.get_or_404(pull_request_id) c.target_repo = c.pull_request.org_repo.repo_name cc_model = ChangesetCommentsModel() cs_model = ChangesetStatusModel() _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo, pull_request=c.pull_request, with_revisions=True) cs_statuses = defaultdict(list) for st in _cs_statuses: cs_statuses[st.author.username] += [st] c.pull_request_reviewers = [] c.pull_request_pending_reviewers = [] for o in c.pull_request.reviewers: st = cs_statuses.get(o.user.username, None) if st: sorter = lambda k: k.version st = [(x, list(y)[0]) for x, y in (groupby(sorted(st, key=sorter), sorter))] else: c.pull_request_pending_reviewers.append(o.user) c.pull_request_reviewers.append([o.user, st]) # pull_requests repo_name we opened it against # ie. other_repo must match if repo_name != c.pull_request.other_repo.repo_name: raise HTTPNotFound # load compare data into template context enable_comments = not c.pull_request.is_closed() self._load_compare_data(c.pull_request, enable_comments=enable_comments) # inline comments c.inline_cnt = 0 c.inline_comments = cc_model.get_inline_comments( c.rhodecode_db_repo.repo_id, pull_request=pull_request_id) # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) # comments c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id, pull_request=pull_request_id) try: cur_status = c.statuses[c.pull_request.revisions[0]][0] except: log.error(traceback.format_exc()) cur_status = 'undefined' if c.pull_request.is_closed() and 0: c.current_changeset_status = cur_status else: # changeset(pull-request) status calulation based on reviewers c.current_changeset_status = cs_model.calculate_status( c.pull_request_reviewers, ) c.changeset_statuses = ChangesetStatus.STATUSES return render('/pullrequests/pullrequest_show.html')
def comment_pull_request(request, apiuser, repoid, pullrequestid, message=Optional(None), status=Optional(None), userid=Optional(OAttr('apiuser'))): """ Comment on the pull request specified with the `pullrequestid`, in the |repo| specified by the `repoid`, and optionally change the review status. :param apiuser: This is filled automatically from the |authtoken|. :type apiuser: AuthUser :param repoid: The repository name or repository ID. :type repoid: str or int :param pullrequestid: The pull request ID. :type pullrequestid: int :param message: The text content of the comment. :type message: str :param status: (**Optional**) Set the approval status of the pull request. Valid options are: * not_reviewed * approved * rejected * under_review :type status: str :param userid: Comment on the pull request as this user :type userid: Optional(str or int) Example output: .. code-block:: bash id : <id_given_in_input> result : { "pull_request_id": "<Integer>", "comment_id": "<Integer>" } error : null """ repo = get_repo_or_error(repoid) if not isinstance(userid, Optional): if (has_superadmin_permission(apiuser) or HasRepoPermissionAnyApi('repository.admin')( user=apiuser, repo_name=repo.repo_name)): apiuser = get_user_or_error(userid) else: raise JSONRPCError('userid is not the same as your user') pull_request = get_pull_request_or_error(pullrequestid) if not PullRequestModel().check_user_read(pull_request, apiuser, api=True): raise JSONRPCError('repository `%s` does not exist' % (repoid, )) message = Optional.extract(message) status = Optional.extract(status) if not message and not status: raise JSONRPCError('message and status parameter missing') if (status not in (st[0] for st in ChangesetStatus.STATUSES) and status is not None): raise JSONRPCError('unknown comment status`%s`' % status) allowed_to_change_status = PullRequestModel().check_user_change_status( pull_request, apiuser) text = message if status and allowed_to_change_status: st_message = (('Status change %(transition_icon)s %(status)s') % { 'transition_icon': '>', 'status': ChangesetStatus.get_status_lbl(status) }) text = message or st_message rc_config = SettingsModel().get_all_settings() renderer = rc_config.get('rhodecode_markup_renderer', 'rst') comment = ChangesetCommentsModel().create( text=text, repo=pull_request.target_repo.repo_id, user=apiuser.user_id, pull_request=pull_request.pull_request_id, f_path=None, line_no=None, status_change=(ChangesetStatus.get_status_lbl(status) if status and allowed_to_change_status else None), closing_pr=False, renderer=renderer) if allowed_to_change_status and status: ChangesetStatusModel().set_status( pull_request.target_repo.repo_id, status, apiuser.user_id, comment, pull_request=pull_request.pull_request_id) Session().flush() Session().commit() data = { 'pull_request_id': pull_request.pull_request_id, 'comment_id': comment.comment_id, 'status': status } return data
def comment(self, repo_name, pull_request_id): pull_request = PullRequest.get_or_404(pull_request_id) if pull_request.is_closed(): raise HTTPForbidden() status = request.POST.get('changeset_status') change_status = request.POST.get('change_changeset_status') text = request.POST.get('text') close_pr = request.POST.get('save_close') allowed_to_change_status = self._get_is_allowed_change_status(pull_request) if status and change_status and allowed_to_change_status: _def = (_('Status change -> %s') % ChangesetStatus.get_status_lbl(status)) if close_pr: _def = _('Closing with') + ' ' + _def text = text or _def comm = ChangesetCommentsModel().create( text=text, repo=c.rhodecode_db_repo.repo_id, user=c.rhodecode_user.user_id, pull_request=pull_request_id, f_path=request.POST.get('f_path'), line_no=request.POST.get('line'), status_change=(ChangesetStatus.get_status_lbl(status) if status and change_status and allowed_to_change_status else None), closing_pr=close_pr ) action_logger(self.rhodecode_user, 'user_commented_pull_request:%s' % pull_request_id, c.rhodecode_db_repo, self.ip_addr, self.sa) if allowed_to_change_status: # get status if set ! if status and change_status: ChangesetStatusModel().set_status( c.rhodecode_db_repo.repo_id, status, c.rhodecode_user.user_id, comm, pull_request=pull_request_id ) if close_pr: if status in ['rejected', 'approved']: PullRequestModel().close_pull_request(pull_request_id) action_logger(self.rhodecode_user, 'user_closed_pull_request:%s' % pull_request_id, c.rhodecode_db_repo, self.ip_addr, self.sa) else: h.flash(_('Closing pull request on other statuses than ' 'rejected or approved forbidden'), category='warning') Session().commit() if not request.environ.get('HTTP_X_PARTIAL_XHR'): return redirect(h.url('pullrequest_show', repo_name=repo_name, pull_request_id=pull_request_id)) data = { 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), } if comm: c.co = comm data.update(comm.get_dict()) data.update({'rendered_text': render('changeset/changeset_comment_block.html')}) return data
def _index(self, commit_id_range, method): c.ignorews_url = _ignorews_url c.context_url = _context_url c.fulldiff = fulldiff = request.GET.get('fulldiff') # get ranges of commit ids if preset commit_range = commit_id_range.split('...')[:2] enable_comments = True try: pre_load = [ 'affected_files', 'author', 'branch', 'date', 'message', 'parents' ] if len(commit_range) == 2: enable_comments = False commits = c.rhodecode_repo.get_commits( start_id=commit_range[0], end_id=commit_range[1], pre_load=pre_load) commits = list(commits) else: commits = [ c.rhodecode_repo.get_commit(commit_id=commit_id_range, pre_load=pre_load) ] c.commit_ranges = commits if not c.commit_ranges: raise RepositoryError( 'The commit range returned an empty result') except CommitDoesNotExistError: msg = _('No such commit exists for this repository') h.flash(msg, category='error') raise HTTPNotFound() except Exception: log.exception("General failure") raise HTTPNotFound() c.changes = OrderedDict() c.lines_added = 0 c.lines_deleted = 0 c.commit_statuses = ChangesetStatus.STATUSES c.comments = [] c.statuses = [] c.inline_comments = [] c.inline_cnt = 0 c.files = [] # Iterate over ranges (default commit view is always one commit) for commit in c.commit_ranges: if method == 'show': c.statuses.extend([ ChangesetStatusModel().get_status( c.rhodecode_db_repo.repo_id, commit.raw_id) ]) c.comments.extend(ChangesetCommentsModel().get_comments( c.rhodecode_db_repo.repo_id, revision=commit.raw_id)) # comments from PR st = ChangesetStatusModel().get_statuses( c.rhodecode_db_repo.repo_id, commit.raw_id, with_revisions=True) # from associated statuses, check the pull requests, and # show comments from them prs = set( x.pull_request for x in filter(lambda x: x.pull_request is not None, st)) for pr in prs: c.comments.extend(pr.comments) inlines = ChangesetCommentsModel().get_inline_comments( c.rhodecode_db_repo.repo_id, revision=commit.raw_id) c.inline_comments.extend(inlines.iteritems()) c.changes[commit.raw_id] = [] commit2 = commit commit1 = commit.parents[0] if commit.parents else EmptyCommit() # fetch global flags of ignore ws or context lines context_lcl = get_line_ctx('', request.GET) ign_whitespace_lcl = get_ignore_ws('', request.GET) _diff = c.rhodecode_repo.get_diff( commit1, commit2, ignore_whitespace=ign_whitespace_lcl, context=context_lcl) # diff_limit will cut off the whole diff if the limit is applied # otherwise it will just hide the big files from the front-end diff_limit = self.cut_off_limit_diff file_limit = self.cut_off_limit_file diff_processor = diffs.DiffProcessor(_diff, format='gitdiff', diff_limit=diff_limit, file_limit=file_limit, show_full_diff=fulldiff) commit_changes = OrderedDict() if method == 'show': _parsed = diff_processor.prepare() c.limited_diff = isinstance(_parsed, diffs.LimitedDiffContainer) for f in _parsed: c.files.append(f) st = f['stats'] c.lines_added += st['added'] c.lines_deleted += st['deleted'] fid = h.FID(commit.raw_id, f['filename']) diff = diff_processor.as_html( enable_comments=enable_comments, parsed_lines=[f]) commit_changes[fid] = [ commit1.raw_id, commit2.raw_id, f['operation'], f['filename'], diff, st, f ] else: # downloads/raw we only need RAW diff nothing else diff = diff_processor.as_raw() commit_changes[''] = [None, None, None, None, diff, None, None] c.changes[commit.raw_id] = commit_changes # sort comments by how they were generated c.comments = sorted(c.comments, key=lambda x: x.comment_id) # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) if len(c.commit_ranges) == 1: c.commit = c.commit_ranges[0] c.parent_tmpl = ''.join('# Parent %s\n' % x.raw_id for x in c.commit.parents) if method == 'download': response.content_type = 'text/plain' response.content_disposition = ('attachment; filename=%s.diff' % commit_id_range[:12]) return diff elif method == 'patch': response.content_type = 'text/plain' c.diff = safe_unicode(diff) return render('changeset/patch_changeset.html') elif method == 'raw': response.content_type = 'text/plain' return diff elif method == 'show': if len(c.commit_ranges) == 1: return render('changeset/changeset.html') else: c.ancestor = None c.target_repo = c.rhodecode_db_repo return render('changeset/changeset_range.html')
def comment(self, repo_name, revision): status = request.POST.get('changeset_status') change_status = request.POST.get('change_changeset_status') text = request.POST.get('text') if status and change_status: text = text or (_('Status change -> %s') % ChangesetStatus.get_status_lbl(status)) comm = ChangesetCommentsModel().create( text=text, repo=c.rhodecode_db_repo.repo_id, user=c.rhodecode_user.user_id, revision=revision, f_path=request.POST.get('f_path'), line_no=request.POST.get('line'), status_change=(ChangesetStatus.get_status_lbl(status) if status and change_status else None) ) # get status if set ! if status and change_status: # if latest status was from pull request and it's closed # disallow changing status ! # dont_allow_on_closed_pull_request = True ! try: ChangesetStatusModel().set_status( c.rhodecode_db_repo.repo_id, status, c.rhodecode_user.user_id, comm, revision=revision, dont_allow_on_closed_pull_request=True ) except StatusChangeOnClosedPullRequestError: log.error(traceback.format_exc()) msg = _('Changing status on a changeset associated with' 'a closed pull request is not allowed') h.flash(msg, category='warning') return redirect(h.url('changeset_home', repo_name=repo_name, revision=revision)) action_logger(self.rhodecode_user, 'user_commented_revision:%s' % revision, c.rhodecode_db_repo, self.ip_addr, self.sa) Session().commit() if not request.environ.get('HTTP_X_PARTIAL_XHR'): return redirect(h.url('changeset_home', repo_name=repo_name, revision=revision)) data = { 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), } if comm: c.co = comm data.update(comm.get_dict()) data.update({'rendered_text': render('changeset/changeset_comment_block.html')}) return data
def comment(self, repo_name, revision): commit_id = revision status = request.POST.get('changeset_status', None) text = request.POST.get('text') if status: text = text or ( _('Status change %(transition_icon)s %(status)s') % { 'transition_icon': '>', 'status': ChangesetStatus.get_status_lbl(status) }) multi_commit_ids = filter( lambda s: s not in ['', None], request.POST.get('commit_ids', '').split(','), ) commit_ids = multi_commit_ids or [commit_id] comment = None for current_id in filter(None, commit_ids): c.co = comment = ChangesetCommentsModel().create( text=text, repo=c.rhodecode_db_repo.repo_id, user=c.rhodecode_user.user_id, revision=current_id, f_path=request.POST.get('f_path'), line_no=request.POST.get('line'), status_change=(ChangesetStatus.get_status_lbl(status) if status else None)) # get status if set ! if status: # if latest status was from pull request and it's closed # disallow changing status ! # dont_allow_on_closed_pull_request = True ! try: ChangesetStatusModel().set_status( c.rhodecode_db_repo.repo_id, status, c.rhodecode_user.user_id, comment, revision=current_id, dont_allow_on_closed_pull_request=True) except StatusChangeOnClosedPullRequestError: msg = _('Changing the status of a commit associated with ' 'a closed pull request is not allowed') log.exception(msg) h.flash(msg, category='warning') return redirect( h.url('changeset_home', repo_name=repo_name, revision=current_id)) # finalize, commit and redirect Session().commit() data = { 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), } if comment: data.update(comment.get_dict()) data.update({ 'rendered_text': render('changeset/changeset_comment_block.html') }) return data
def comment(self, repo_name, pull_request_id): pull_request = PullRequest.get_or_404(pull_request_id) if pull_request.is_closed(): raise HTTPForbidden() status = request.POST.get('changeset_status') change_status = request.POST.get('change_changeset_status') text = request.POST.get('text') close_pr = request.POST.get('save_close') allowed_to_change_status = self._get_is_allowed_change_status( pull_request) if status and change_status and allowed_to_change_status: _def = (_('Status change -> %s') % ChangesetStatus.get_status_lbl(status)) if close_pr: _def = _('Closing with') + ' ' + _def text = text or _def comm = ChangesetCommentsModel().create( text=text, repo=c.rhodecode_db_repo.repo_id, user=c.rhodecode_user.user_id, pull_request=pull_request_id, f_path=request.POST.get('f_path'), line_no=request.POST.get('line'), status_change=(ChangesetStatus.get_status_lbl(status) if status and change_status and allowed_to_change_status else None), closing_pr=close_pr) action_logger(self.rhodecode_user, 'user_commented_pull_request:%s' % pull_request_id, c.rhodecode_db_repo, self.ip_addr, self.sa) if allowed_to_change_status: # get status if set ! if status and change_status: ChangesetStatusModel().set_status(c.rhodecode_db_repo.repo_id, status, c.rhodecode_user.user_id, comm, pull_request=pull_request_id) if close_pr: if status in ['rejected', 'approved']: PullRequestModel().close_pull_request(pull_request_id) action_logger( self.rhodecode_user, 'user_closed_pull_request:%s' % pull_request_id, c.rhodecode_db_repo, self.ip_addr, self.sa) else: h.flash(_('Closing pull request on other statuses than ' 'rejected or approved forbidden'), category='warning') Session().commit() if not request.environ.get('HTTP_X_PARTIAL_XHR'): return redirect( h.url('pullrequest_show', repo_name=repo_name, pull_request_id=pull_request_id)) data = { 'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))), } if comm: c.co = comm data.update(comm.get_dict()) data.update({ 'rendered_text': render('changeset/changeset_comment_block.html') }) return data
def update_commits(self, pull_request): """ Get the updated list of commits for the pull request and return the new pull request version and the list of commits processed by this update action """ pull_request = self.__get_pull_request(pull_request) source_ref_type = pull_request.source_ref_parts.type source_ref_name = pull_request.source_ref_parts.name source_ref_id = pull_request.source_ref_parts.commit_id if not self.has_valid_update_type(pull_request): log.debug("Skipping update of pull request %s due to ref type: %s", pull_request, source_ref_type) return (None, None) source_repo = pull_request.source_repo.scm_instance() source_commit = source_repo.get_commit(commit_id=source_ref_name) if source_ref_id == source_commit.raw_id: log.debug("Nothing changed in pull request %s", pull_request) return (None, None) # Finally there is a need for an update pull_request_version = self._create_version_from_snapshot(pull_request) self._link_comments_to_version(pull_request_version) target_ref_type = pull_request.target_ref_parts.type target_ref_name = pull_request.target_ref_parts.name target_ref_id = pull_request.target_ref_parts.commit_id target_repo = pull_request.target_repo.scm_instance() if target_ref_type in ('tag', 'branch', 'book'): target_commit = target_repo.get_commit(target_ref_name) else: target_commit = target_repo.get_commit(target_ref_id) # re-compute commit ids old_commit_ids = set(pull_request.revisions) pre_load = ["author", "branch", "date", "message"] commit_ranges = target_repo.compare(target_commit.raw_id, source_commit.raw_id, source_repo, merge=True, pre_load=pre_load) ancestor = target_repo.get_common_ancestor(target_commit.raw_id, source_commit.raw_id, source_repo) pull_request.source_ref = '%s:%s:%s' % ( source_ref_type, source_ref_name, source_commit.raw_id) pull_request.target_ref = '%s:%s:%s' % (target_ref_type, target_ref_name, ancestor) pull_request.revisions = [ commit.raw_id for commit in reversed(commit_ranges) ] pull_request.updated_on = datetime.datetime.now() Session().add(pull_request) new_commit_ids = set(pull_request.revisions) changes = self._calculate_commit_id_changes(old_commit_ids, new_commit_ids) old_diff_data, new_diff_data = self._generate_update_diffs( pull_request, pull_request_version) ChangesetCommentsModel().outdate_comments(pull_request, old_diff_data=old_diff_data, new_diff_data=new_diff_data) file_changes = self._calculate_file_changes(old_diff_data, new_diff_data) # Add an automatic comment to the pull request update_comment = ChangesetCommentsModel().create( text=self._render_update_message(changes, file_changes), repo=pull_request.target_repo, user=pull_request.author, pull_request=pull_request, send_email=False, renderer=DEFAULT_COMMENTS_RENDERER) # Update status to "Under Review" for added commits for commit_id in changes.added: ChangesetStatusModel().set_status( repo=pull_request.source_repo, status=ChangesetStatus.STATUS_UNDER_REVIEW, comment=update_comment, user=pull_request.author, pull_request=pull_request, revision=commit_id) log.debug( 'Updated pull request %s, added_ids: %s, common_ids: %s, ' 'removed_ids: %s', pull_request.pull_request_id, changes.added, changes.common, changes.removed) log.debug('Updated pull request with the following file changes: %s', file_changes) log.info( "Updated pull request %s from commit %s to commit %s, " "stored new version %s of this pull request.", pull_request.pull_request_id, source_ref_id, pull_request.source_ref_parts.commit_id, pull_request_version.pull_request_version_id) Session().commit() self._trigger_pull_request_hook(pull_request, pull_request.author, 'update') return (pull_request_version, changes)
def _get_pull_requests_list(self, repo_name, opened_by, statuses): # pagination start = safe_int(request.GET.get('start'), 0) length = safe_int(request.GET.get('length'), c.visual.dashboard_items) order_by, order_dir = self._extract_ordering(request) if c.awaiting_review: pull_requests = PullRequestModel().get_awaiting_review( repo_name, source=c.source, opened_by=opened_by, statuses=statuses, offset=start, length=length, order_by=order_by, order_dir=order_dir) pull_requests_total_count = PullRequestModel( ).count_awaiting_review(repo_name, source=c.source, statuses=statuses, opened_by=opened_by) elif c.awaiting_my_review: pull_requests = PullRequestModel().get_awaiting_my_review( repo_name, source=c.source, opened_by=opened_by, user_id=c.rhodecode_user.user_id, statuses=statuses, offset=start, length=length, order_by=order_by, order_dir=order_dir) pull_requests_total_count = PullRequestModel( ).count_awaiting_my_review(repo_name, source=c.source, user_id=c.rhodecode_user.user_id, statuses=statuses, opened_by=opened_by) else: pull_requests = PullRequestModel().get_all(repo_name, source=c.source, opened_by=opened_by, statuses=statuses, offset=start, length=length, order_by=order_by, order_dir=order_dir) pull_requests_total_count = PullRequestModel().count_all( repo_name, source=c.source, statuses=statuses, opened_by=opened_by) from rhodecode.lib.utils import PartialRenderer _render = PartialRenderer('data_table/_dt_elements.html') data = [] for pr in pull_requests: comments = ChangesetCommentsModel().get_all_comments( c.rhodecode_db_repo.repo_id, pull_request=pr) data.append({ 'name': _render('pullrequest_name', pr.pull_request_id, pr.target_repo.repo_name), 'name_raw': pr.pull_request_id, 'status': _render('pullrequest_status', pr.calculated_review_status()), 'title': _render('pullrequest_title', pr.title, pr.description), 'description': h.escape(pr.description), 'updated_on': _render('pullrequest_updated_on', h.datetime_to_time(pr.updated_on)), 'updated_on_raw': h.datetime_to_time(pr.updated_on), 'created_on': _render('pullrequest_updated_on', h.datetime_to_time(pr.created_on)), 'created_on_raw': h.datetime_to_time(pr.created_on), 'author': _render( 'pullrequest_author', pr.author.full_contact, ), 'author_raw': pr.author.full_name, 'comments': _render('pullrequest_comments', len(comments)), 'comments_raw': len(comments), 'closed': pr.is_closed(), }) # json used to render the grid data = ({ 'data': data, 'recordsTotal': pull_requests_total_count, 'recordsFiltered': pull_requests_total_count, }) return data
class ChangesetController(BaseRepoController): @LoginRequired() @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', 'repository.admin') def __before__(self): super(ChangesetController, self).__before__() c.affected_files_cut_off = 60 repo_model = RepoModel() c.users_array = repo_model.get_users_js() c.users_groups_array = repo_model.get_users_groups_js() def index(self, revision, method='show'): c.anchor_url = anchor_url c.ignorews_url = _ignorews_url c.context_url = _context_url c.fulldiff = fulldiff = request.GET.get('fulldiff') #get ranges of revisions if preset rev_range = revision.split('...')[:2] enable_comments = True try: if len(rev_range) == 2: enable_comments = False rev_start = rev_range[0] rev_end = rev_range[1] rev_ranges = c.rhodecode_repo.get_changesets(start=rev_start, end=rev_end) else: rev_ranges = [c.rhodecode_repo.get_changeset(revision)] c.cs_ranges = list(rev_ranges) if not c.cs_ranges: raise RepositoryError('Changeset range returned empty result') except (RepositoryError, ChangesetDoesNotExistError, Exception), e: log.error(traceback.format_exc()) h.flash(str(e), category='error') raise HTTPNotFound() c.changes = OrderedDict() c.lines_added = 0 # count of lines added c.lines_deleted = 0 # count of lines removes c.changeset_statuses = ChangesetStatus.STATUSES c.comments = [] c.statuses = [] c.inline_comments = [] c.inline_cnt = 0 # Iterate over ranges (default changeset view is always one changeset) for changeset in c.cs_ranges: inlines = [] if method == 'show': c.statuses.extend([ChangesetStatusModel().get_status( c.rhodecode_db_repo.repo_id, changeset.raw_id)]) c.comments.extend(ChangesetCommentsModel()\ .get_comments(c.rhodecode_db_repo.repo_id, revision=changeset.raw_id)) #comments from PR st = ChangesetStatusModel().get_statuses( c.rhodecode_db_repo.repo_id, changeset.raw_id, with_revisions=True) # from associated statuses, check the pull requests, and # show comments from them prs = set([x.pull_request for x in filter(lambda x: x.pull_request != None, st)]) for pr in prs: c.comments.extend(pr.comments) inlines = ChangesetCommentsModel()\ .get_inline_comments(c.rhodecode_db_repo.repo_id, revision=changeset.raw_id) c.inline_comments.extend(inlines) c.changes[changeset.raw_id] = [] cs2 = changeset.raw_id cs1 = changeset.parents[0].raw_id if changeset.parents else EmptyChangeset() context_lcl = get_line_ctx('', request.GET) ign_whitespace_lcl = ign_whitespace_lcl = get_ignore_ws('', request.GET) _diff = c.rhodecode_repo.get_diff(cs1, cs2, ignore_whitespace=ign_whitespace_lcl, context=context_lcl) diff_limit = self.cut_off_limit if not fulldiff else None diff_processor = diffs.DiffProcessor(_diff, vcs=c.rhodecode_repo.alias, format='gitdiff', diff_limit=diff_limit) cs_changes = OrderedDict() if method == 'show': _parsed = diff_processor.prepare() c.limited_diff = False if isinstance(_parsed, LimitedDiffContainer): c.limited_diff = True for f in _parsed: st = f['stats'] if st[0] != 'b': c.lines_added += st[0] c.lines_deleted += st[1] fid = h.FID(changeset.raw_id, f['filename']) diff = diff_processor.as_html(enable_comments=enable_comments, parsed_lines=[f]) cs_changes[fid] = [cs1, cs2, f['operation'], f['filename'], diff, st] else: # downloads/raw we only need RAW diff nothing else diff = diff_processor.as_raw() cs_changes[''] = [None, None, None, None, diff, None] c.changes[changeset.raw_id] = cs_changes #sort comments by how they were generated c.comments = sorted(c.comments, key=lambda x: x.comment_id) # count inline comments for __, lines in c.inline_comments: for comments in lines.values(): c.inline_cnt += len(comments) if len(c.cs_ranges) == 1: c.changeset = c.cs_ranges[0] c.parent_tmpl = ''.join(['# Parent %s\n' % x.raw_id for x in c.changeset.parents]) if method == 'download': response.content_type = 'text/plain' response.content_disposition = 'attachment; filename=%s.diff' \ % revision[:12] return diff elif method == 'patch': response.content_type = 'text/plain' c.diff = safe_unicode(diff) return render('changeset/patch_changeset.html') elif method == 'raw': response.content_type = 'text/plain' return diff elif method == 'show': if len(c.cs_ranges) == 1: return render('changeset/changeset.html') else: return render('changeset/changeset_range.html')
def set_status(self, repo, status, user, comment=None, revision=None, pull_request=None, dont_allow_on_closed_pull_request=False): """ Creates new status for changeset or updates the old ones bumping their version, leaving the current status at :param repo: :param revision: :param status: :param user: :param comment: :param dont_allow_on_closed_pull_request: don't allow a status change if last status was for pull request and it's closed. We shouldn't mess around this manually """ repo = self._get_repo(repo) q = ChangesetStatus.query() if not comment: from rhodecode.model.comment import ChangesetCommentsModel comment = ChangesetCommentsModel().create( text='Auto status change to %s' % (ChangesetStatus.get_status_lbl(status)), repo=repo, user=user, pull_request=pull_request, send_email=False) if revision: q = q.filter(ChangesetStatus.repo == repo) q = q.filter(ChangesetStatus.revision == revision) elif pull_request: pull_request = self.__get_pull_request(pull_request) q = q.filter(ChangesetStatus.repo == pull_request.org_repo) q = q.filter(ChangesetStatus.revision.in_(pull_request.revisions)) cur_statuses = q.all() #if statuses exists and last is associated with a closed pull request # we need to check if we can allow this status change if (dont_allow_on_closed_pull_request and cur_statuses and getattr(cur_statuses[0].pull_request, 'status', '') == PullRequest.STATUS_CLOSED): raise StatusChangeOnClosedPullRequestError( 'Changing status on closed pull request is not allowed') #update all current statuses with older version if cur_statuses: for st in cur_statuses: st.version += 1 self.sa.add(st) def _create_status(user, repo, status, comment, revision, pull_request): new_status = ChangesetStatus() new_status.author = self._get_user(user) new_status.repo = self._get_repo(repo) new_status.status = status new_status.comment = comment new_status.revision = revision new_status.pull_request = pull_request return new_status if revision: new_status = _create_status(user=user, repo=repo, status=status, comment=comment, revision=revision, pull_request=None) self.sa.add(new_status) return new_status elif pull_request: #pull request can have more than one revision associated to it #we need to create new version for each one new_statuses = [] repo = pull_request.org_repo for rev in pull_request.revisions: new_status = _create_status(user=user, repo=repo, status=status, comment=comment, revision=rev, pull_request=pull_request) new_statuses.append(new_status) self.sa.add(new_status) return new_statuses