@@ -147,176 +147,180 @@ class PullrequestsController(BaseRepoCon
log.error(traceback.format_exc())
if errors.error_dict.get('revisions'):
msg = _('Cannot open a pull request with '
'empty list of changesets')
elif errors.error_dict.get('pullrequest_title'):
msg = _('Pull request requires a title with min. 3 chars')
else:
msg = _('error during creation of pull request')
h.flash(msg, 'error')
return redirect(url('pullrequest_home', repo_name=repo_name))
org_repo = _form['org_repo']
org_ref = _form['org_ref']
other_repo = _form['other_repo']
other_ref = _form['other_ref']
revisions = _form['revisions']
reviewers = _form['review_members']
title = _form['pullrequest_title']
description = _form['pullrequest_desc']
try:
pull_request = PullRequestModel().create(
self.rhodecode_user.user_id, org_repo, org_ref, other_repo,
other_ref, revisions, reviewers, title, description
)
Session().commit()
h.flash(_('Successfully opened new pull request'),
category='success')
except Exception:
h.flash(_('Error occurred during sending pull request'),
category='error')
return redirect(url('pullrequest_show', repo_name=other_repo,
pull_request_id=pull_request.pull_request_id))
@NotAnonymous()
@jsonify
def update(self, repo_name, pull_request_id):
pull_request = PullRequest.get_or_404(pull_request_id)
if pull_request.is_closed():
raise HTTPForbidden()
reviewers_ids = map(int, filter(lambda v: v not in [None, ''],
request.POST.get('reviewers_ids', '').split(',')))
PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
Session.commit()
return True
def _load_compare_data(self, pull_request, enable_comments=True):
"""
Load context data needed for generating compare diff
:param pull_request:
:type pull_request:
org_repo = pull_request.org_repo
(org_ref_type,
org_ref_name,
org_ref_rev) = pull_request.org_ref.split(':')
other_repo = pull_request.other_repo
(other_ref_type,
other_ref_name,
other_ref_rev) = pull_request.other_ref.split(':')
# dispite opening revisions for bookmarks/branches/tags, we always
# convert this to rev to prevent changes after book or branch change
org_ref = ('rev', org_ref_rev)
other_ref = ('rev', other_ref_rev)
c.org_repo = org_repo
c.other_repo = other_repo
c.cs_ranges, discovery_data = PullRequestModel().get_compare_data(
org_repo, org_ref, other_repo, other_ref
c.statuses = c.rhodecode_db_repo.statuses([x.raw_id for x in
c.cs_ranges])
# defines that we need hidden inputs with changesets
c.as_form = request.GET.get('as_form', False)
c.org_ref = org_ref[1]
c.other_ref = other_ref[1]
# diff needs to have swapped org with other to generate proper diff
_diff = diffs.differ(other_repo, other_ref, org_repo, org_ref,
discovery_data)
diff_processor = diffs.DiffProcessor(_diff, format='gitdiff')
_parsed = diff_processor.prepare()
c.files = []
c.changes = {}
for f in _parsed:
fid = h.FID('', f['filename'])
c.files.append([fid, f['operation'], f['filename'], f['stats']])
diff = diff_processor.as_html(enable_comments=enable_comments,
diff_lines=[f])
c.changes[fid] = [f['operation'], f['filename'], diff]
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)
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))]
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,
# changeset(pull-request) status
c.current_changeset_status = cs_model.calculate_status(
c.pull_request_reviewers
c.changeset_statuses = ChangesetStatus.STATUSES
c.target_repo = c.pull_request.org_repo.repo_name
return render('/pullrequests/pullrequest_show.html')
def comment(self, repo_name, pull_request_id):
status = request.POST.get('changeset_status')
change_status = request.POST.get('change_changeset_status')
comm = ChangesetCommentsModel().create(
text=request.POST.get('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'),
<%inherit file="/base/base.html"/>
<%def name="title()">
${c.repo_name} ${_('Pull request #%s') % c.pull_request.pull_request_id}
</%def>
<%def name="breadcrumbs_links()">
${h.link_to(_(u'Home'),h.url('/'))}
»
${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
${_('Pull request #%s') % c.pull_request.pull_request_id}
<%def name="main()">
<div class="box">
<!-- box / title -->
<div class="title">
${self.breadcrumbs()}
</div>
%if c.pull_request.is_closed():
<div style="padding:10px; font-size:22px;width:100%;text-align: center; color:#88D882">${_('Closed %s') % (h.age(c.pull_request.updated_on))}</div>
%endif
<h3>${_('Title')}: ${c.pull_request.title}
<div class="changeset-status-container" style="float:none">
%if c.current_changeset_status:
<div title="${_('Pull request status')}" class="changeset-status-lbl">[${h.changeset_status_lbl(c.current_changeset_status)}]</div>
<div class="changeset-status-ico" style="padding:4px"><img src="${h.url('/images/icons/flag_status_%s.png' % c.current_changeset_status)}" /></div>
</h3>
<h3>${_('Title')}: ${c.pull_request.title}</h3>
<div class="form">
<div id="summary" class="fields">
<div class="field">
<div class="label-summary">
<label>${_('Status')}:</label>
<div class="input">
<div class="changeset-status-container" style="float:none;clear:both">
<div class="changeset-status-ico" style="padding:1px 4px"><img src="${h.url('/images/icons/flag_status_%s.png' % c.current_changeset_status)}" /></div>
<label>${_('Still not reviewed by')}:</label>
<div>${ungettext('%d reviewer', '%d reviewers',len(c.pull_request_pending_reviewers)) % len(c.pull_request_pending_reviewers)}</div>
<div style="white-space:pre-wrap;padding:3px 3px 5px 20px">${h.literal(c.pull_request.description)}</div>
<div style="padding:4px 4px 10px 20px">
<div>${_('Created on')}: ${h.fmt_date(c.pull_request.created_on)}</div>
<div style="min-height:160px">
##DIFF
<div class="table" style="float:left;clear:none">
<div id="body" class="diffblock">
<div style="white-space:pre-wrap;padding:5px">${_('Compare view')}</div>
<div id="changeset_compare_view_content">
##CS
<div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Incoming changesets')}</div>
<%include file="/compare/compare_cs.html" />
## FILES
<div style="font-size:1.1em;font-weight: bold;clear:both;padding-top:10px">${_('Files affected')}</div>
<div class="cs_files">
%for fid, change, f, stat in c.files:
<div class="cs_${change}">
<div class="node">${h.link_to(h.safe_unicode(f),h.url.current(anchor=fid))}</div>
<div class="changes">${h.fancy_file_stats(stat)}</div>
%endfor
## REVIEWERS
<div style="float:left; border-left:1px dashed #eee">
<h4>${_('Pull request reviewers')}</h4>
<div id="reviewers" style="padding:0px 0px 0px 15px">
## members goes here !
<div class="group_members_wrap">
<ul id="review_members" class="group_members">
%for member,status in c.pull_request_reviewers:
<li id="reviewer_${member.user_id}">
<div class="reviewers_member">
<div style="float:left;padding:0px 3px 0px 0px" class="tooltip" title="${h.tooltip(h.changeset_status_lbl(status[0][1].status if status else 'not_reviewed'))}">
<img src="${h.url(str('/images/icons/flag_status_%s.png' % (status[0][1].status if status else 'not_reviewed')))}"/>
<div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(member.email,14)}"/> </div>
<div style="float:left">${member.full_name} (${_('owner')})</div>
<input type="hidden" value="${member.user_id}" name="review_members" />
%if not c.pull_request.is_closed():
<span class="delete_icon action_button" onclick="removeReviewer(${member.user_id})"></span>
Status change: