##// END OF EJS Templates
Adde pull request voting recalculation
marcink -
r2481:4d303243 beta
parent child Browse files
Show More
@@ -26,6 +26,8 b' import logging'
26 26 import traceback
27 27
28 28 from webob.exc import HTTPNotFound
29 from collections import defaultdict
30 from itertools import groupby
29 31
30 32 from pylons import request, response, session, tmpl_context as c, url
31 33 from pylons.controllers.util import abort, redirect
@@ -199,6 +201,24 b' class PullrequestsController(BaseRepoCon'
199 201 # valid ID
200 202 if not c.pull_request:
201 203 raise HTTPNotFound
204 cc_model = ChangesetCommentsModel()
205 cs_model = ChangesetStatusModel()
206 _cs_statuses = cs_model.get_statuses(c.pull_request.org_repo,
207 pull_request=c.pull_request,
208 with_revisions=True)
209
210 cs_statuses = defaultdict(list)
211 for st in _cs_statuses:
212 cs_statuses[st.author.username] += [st]
213
214 c.pull_request_reviewers = []
215 for o in c.pull_request.reviewers:
216 st = cs_statuses.get(o.user.username, None)
217 if st:
218 sorter = lambda k: k.version
219 st = [(x, list(y)[0])
220 for x, y in (groupby(sorted(st, key=sorter), sorter))]
221 c.pull_request_reviewers.append([o.user, st])
202 222
203 223 # pull_requests repo_name we opened it against
204 224 # ie. other_repo must match
@@ -210,23 +230,23 b' class PullrequestsController(BaseRepoCon'
210 230
211 231 # inline comments
212 232 c.inline_cnt = 0
213 c.inline_comments = ChangesetCommentsModel()\
214 .get_inline_comments(c.rhodecode_db_repo.repo_id,
233 c.inline_comments = cc_model.get_inline_comments(
234 c.rhodecode_db_repo.repo_id,
215 235 pull_request=pull_request_id)
216 236 # count inline comments
217 237 for __, lines in c.inline_comments:
218 238 for comments in lines.values():
219 239 c.inline_cnt += len(comments)
220 240 # comments
221 c.comments = ChangesetCommentsModel()\
222 .get_comments(c.rhodecode_db_repo.repo_id,
241 c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id,
223 242 pull_request=pull_request_id)
224 243
225 244 # changeset(pull-request) status
226 c.current_changeset_status = ChangesetStatusModel()\
227 .get_status(c.pull_request.org_repo,
228 pull_request=c.pull_request)
245 c.current_changeset_status = cs_model.calculate_status(
246 c.pull_request_reviewers
247 )
229 248 c.changeset_statuses = ChangesetStatus.STATUSES
249
230 250 return render('/pullrequests/pullrequest_show.html')
231 251
232 252 @jsonify
@@ -24,6 +24,7 b''
24 24
25 25
26 26 import logging
27 from collections import defaultdict
27 28
28 29 from rhodecode.model import BaseModel
29 30 from rhodecode.model.db import ChangesetStatus, PullRequest
@@ -39,6 +40,52 b' class ChangesetStatusModel(BaseModel):'
39 40 def __get_pull_request(self, pull_request):
40 41 return self._get_instance(PullRequest, pull_request)
41 42
43 def _get_status_query(self, repo, revision, pull_request,
44 with_revisions=False):
45 repo = self._get_repo(repo)
46
47 q = ChangesetStatus.query()\
48 .filter(ChangesetStatus.repo == repo)
49 if not with_revisions:
50 q = q.filter(ChangesetStatus.version == 0)
51
52 if revision:
53 q = q.filter(ChangesetStatus.revision == revision)
54 elif pull_request:
55 pull_request = self.__get_pull_request(pull_request)
56 q = q.filter(ChangesetStatus.pull_request == pull_request)
57 else:
58 raise Exception('Please specify revision or pull_request')
59 q.order_by(ChangesetStatus.version.asc())
60 return q
61
62 def calculate_status(self, statuses_by_reviewers):
63 """
64 leading one wins, if number of occurences are equal than weaker wins
65
66 :param statuses_by_reviewers:
67 """
68 status = None
69 votes = defaultdict(int)
70 reviewers_number = len(statuses_by_reviewers)
71 for user, statuses in statuses_by_reviewers:
72 if statuses:
73 ver, latest = statuses[0]
74 votes[latest.status] += 1
75 else:
76 votes[ChangesetStatus.DEFAULT] += 1
77
78 if votes.get(ChangesetStatus.STATUS_APPROVED) == reviewers_number:
79 return ChangesetStatus.STATUS_APPROVED
80 else:
81 return ChangesetStatus.STATUS_UNDER_REVIEW
82
83 def get_statuses(self, repo, revision=None, pull_request=None,
84 with_revisions=False):
85 q = self._get_status_query(repo, revision, pull_request,
86 with_revisions)
87 return q.all()
88
42 89 def get_status(self, repo, revision=None, pull_request=None):
43 90 """
44 91 Returns latest status of changeset for given revision or for given
@@ -52,19 +99,7 b' class ChangesetStatusModel(BaseModel):'
52 99 :param pull_request: pull_request reference
53 100 :type:
54 101 """
55 repo = self._get_repo(repo)
56
57 q = ChangesetStatus.query()\
58 .filter(ChangesetStatus.repo == repo)\
59 .filter(ChangesetStatus.version == 0)
60
61 if revision:
62 q = q.filter(ChangesetStatus.revision == revision)
63 elif pull_request:
64 pull_request = self.__get_pull_request(pull_request)
65 q = q.filter(ChangesetStatus.pull_request == pull_request)
66 else:
67 raise Exception('Please specify revision or pull_request')
102 q = self._get_status_query(repo, revision, pull_request)
68 103
69 104 # need to use first here since there can be multiple statuses
70 105 # returned from pull_request
@@ -1371,14 +1371,17 b' class ChangesetStatus(Base, BaseModel):'
1371 1371 {'extend_existing': True, 'mysql_engine': 'InnoDB',
1372 1372 'mysql_charset': 'utf8'}
1373 1373 )
1374 STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed'
1375 STATUS_APPROVED = 'approved'
1376 STATUS_REJECTED = 'rejected'
1377 STATUS_UNDER_REVIEW = 'under_review'
1374 1378
1375 1379 STATUSES = [
1376 ('not_reviewed', _("Not Reviewed")), # (no icon) and default
1377 ('approved', _("Approved")),
1378 ('rejected', _("Rejected")),
1379 ('under_review', _("Under Review")),
1380 (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default
1381 (STATUS_APPROVED, _("Approved")),
1382 (STATUS_REJECTED, _("Rejected")),
1383 (STATUS_UNDER_REVIEW, _("Under Review")),
1380 1384 ]
1381 DEFAULT = STATUSES[0][0]
1382 1385
1383 1386 changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True)
1384 1387 repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False)
@@ -1395,6 +1398,12 b' class ChangesetStatus(Base, BaseModel):'
1395 1398 comment = relationship('ChangesetComment', lazy='joined')
1396 1399 pull_request = relationship('PullRequest', lazy='joined')
1397 1400
1401 def __unicode__(self):
1402 return u"<%s('%s:%s')>" % (
1403 self.__class__.__name__,
1404 self.status, self.author
1405 )
1406
1398 1407 @classmethod
1399 1408 def get_status_lbl(cls, value):
1400 1409 return dict(cls.STATUSES).get(value)
@@ -21,19 +21,42 b''
21 21 </div>
22 22
23 23 <h3>${_('Title')}: ${c.pull_request.title}</h3>
24 <div class="changeset-status-container" style="float:left;padding:0px 20px 20px 20px">
24 <div class="changeset-status-container" style="float:left;padding:0px 20px 0px 20px">
25 25 %if c.current_changeset_status:
26 26 <div title="${_('Changeset status')}" class="changeset-status-lbl">[${h.changeset_status_lbl(c.current_changeset_status)}]</div>
27 27 <div class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.current_changeset_status)}" /></div>
28 28 %endif
29 29 </div>
30 <div style="padding:4px">
30 <div style="padding:4px 4px 10px 4px">
31 31 <div>${h.fmt_date(c.pull_request.created_on)}</div>
32 32 </div>
33 33
34 ## REVIEWERS
35 <div>
36 <div class="table" style="float:right;width:46%;clear:none">
37 <div id="body" class="diffblock">
38 <div style="white-space:pre-wrap;padding:5px">${_('Pull request reviewers')}</div>
39 </div>
40 <div style="border: 1px solid #CCC">
41 <div class="group_members_wrap">
42 <ul class="group_members">
43 %for user,status in c.pull_request_reviewers:
44 <li>
45 <div class="group_member">
46 <div style="float:left;padding:3px">
47 <img src="${h.url(str('/images/icons/flag_status_%s.png' % (status[0][1].status if status else 'not_reviewed')))}"/>
48 </div>
49 <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,20)}"/> </div>
50 <div style="float:left">${user.username}</div>
51 </div>
52 </li>
53 %endfor
54 </ul>
55 </div>
56 </div>
57 </div>
34 58 ##DIFF
35
36 <div class="table">
59 <div class="table" style="float:left;width:46%;clear:none">
37 60 <div id="body" class="diffblock">
38 61 <div style="white-space:pre-wrap;padding:5px">${h.literal(c.pull_request.description)}</div>
39 62 </div>
@@ -54,6 +77,7 b''
54 77 </div>
55 78 </div>
56 79 </div>
80 </div>
57 81 <script>
58 82 var _USERS_AC_DATA = ${c.users_array|n};
59 83 var _GROUPS_AC_DATA = ${c.users_groups_array|n};
General Comments 0
You need to be logged in to leave comments. Login now