Mercurial > kallithea
changeset 2481:4d3032431d4f beta
Adde pull request voting recalculation
author | Marcin Kuzminski <marcin@python-works.com> |
---|---|
date | Tue, 19 Jun 2012 00:43:55 +0200 |
parents | cb9e73b29a87 |
children | 1fd3c043c025 |
files | rhodecode/controllers/pullrequests.py rhodecode/model/changeset_status.py rhodecode/model/db.py rhodecode/templates/pullrequests/pullrequest_show.html |
diffstat | 4 files changed, 137 insertions(+), 49 deletions(-) [+] |
line wrap: on
line diff
--- a/rhodecode/controllers/pullrequests.py Mon Jun 18 21:31:03 2012 +0200 +++ b/rhodecode/controllers/pullrequests.py Tue Jun 19 00:43:55 2012 +0200 @@ -26,6 +26,8 @@ import traceback from webob.exc import HTTPNotFound +from collections import defaultdict +from itertools import groupby from pylons import request, response, session, tmpl_context as c, url from pylons.controllers.util import abort, redirect @@ -199,6 +201,24 @@ # valid ID if not c.pull_request: raise HTTPNotFound + 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 = [] + 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_reviewers.append([o.user, st]) # pull_requests repo_name we opened it against # ie. other_repo must match @@ -210,23 +230,23 @@ # inline comments c.inline_cnt = 0 - c.inline_comments = ChangesetCommentsModel()\ - .get_inline_comments(c.rhodecode_db_repo.repo_id, - pull_request=pull_request_id) + 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 = ChangesetCommentsModel()\ - .get_comments(c.rhodecode_db_repo.repo_id, - pull_request=pull_request_id) + c.comments = cc_model.get_comments(c.rhodecode_db_repo.repo_id, + pull_request=pull_request_id) # changeset(pull-request) status - c.current_changeset_status = ChangesetStatusModel()\ - .get_status(c.pull_request.org_repo, - pull_request=c.pull_request) + c.current_changeset_status = cs_model.calculate_status( + c.pull_request_reviewers + ) c.changeset_statuses = ChangesetStatus.STATUSES + return render('/pullrequests/pullrequest_show.html') @jsonify
--- a/rhodecode/model/changeset_status.py Mon Jun 18 21:31:03 2012 +0200 +++ b/rhodecode/model/changeset_status.py Tue Jun 19 00:43:55 2012 +0200 @@ -24,6 +24,7 @@ import logging +from collections import defaultdict from rhodecode.model import BaseModel from rhodecode.model.db import ChangesetStatus, PullRequest @@ -39,6 +40,52 @@ def __get_pull_request(self, pull_request): return self._get_instance(PullRequest, pull_request) + def _get_status_query(self, repo, revision, pull_request, + with_revisions=False): + repo = self._get_repo(repo) + + q = ChangesetStatus.query()\ + .filter(ChangesetStatus.repo == repo) + if not with_revisions: + q = q.filter(ChangesetStatus.version == 0) + + if revision: + q = q.filter(ChangesetStatus.revision == revision) + elif pull_request: + pull_request = self.__get_pull_request(pull_request) + q = q.filter(ChangesetStatus.pull_request == pull_request) + else: + raise Exception('Please specify revision or pull_request') + q.order_by(ChangesetStatus.version.asc()) + return q + + def calculate_status(self, statuses_by_reviewers): + """ + leading one wins, if number of occurences are equal than weaker wins + + :param statuses_by_reviewers: + """ + status = None + votes = defaultdict(int) + reviewers_number = len(statuses_by_reviewers) + for user, statuses in statuses_by_reviewers: + if statuses: + ver, latest = statuses[0] + votes[latest.status] += 1 + else: + votes[ChangesetStatus.DEFAULT] += 1 + + if votes.get(ChangesetStatus.STATUS_APPROVED) == reviewers_number: + return ChangesetStatus.STATUS_APPROVED + else: + return ChangesetStatus.STATUS_UNDER_REVIEW + + def get_statuses(self, repo, revision=None, pull_request=None, + with_revisions=False): + q = self._get_status_query(repo, revision, pull_request, + with_revisions) + return q.all() + def get_status(self, repo, revision=None, pull_request=None): """ Returns latest status of changeset for given revision or for given @@ -52,19 +99,7 @@ :param pull_request: pull_request reference :type: """ - repo = self._get_repo(repo) - - q = ChangesetStatus.query()\ - .filter(ChangesetStatus.repo == repo)\ - .filter(ChangesetStatus.version == 0) - - if revision: - q = q.filter(ChangesetStatus.revision == revision) - elif pull_request: - pull_request = self.__get_pull_request(pull_request) - q = q.filter(ChangesetStatus.pull_request == pull_request) - else: - raise Exception('Please specify revision or pull_request') + q = self._get_status_query(repo, revision, pull_request) # need to use first here since there can be multiple statuses # returned from pull_request
--- a/rhodecode/model/db.py Mon Jun 18 21:31:03 2012 +0200 +++ b/rhodecode/model/db.py Tue Jun 19 00:43:55 2012 +0200 @@ -1371,14 +1371,17 @@ {'extend_existing': True, 'mysql_engine': 'InnoDB', 'mysql_charset': 'utf8'} ) + STATUS_NOT_REVIEWED = DEFAULT = 'not_reviewed' + STATUS_APPROVED = 'approved' + STATUS_REJECTED = 'rejected' + STATUS_UNDER_REVIEW = 'under_review' STATUSES = [ - ('not_reviewed', _("Not Reviewed")), # (no icon) and default - ('approved', _("Approved")), - ('rejected', _("Rejected")), - ('under_review', _("Under Review")), + (STATUS_NOT_REVIEWED, _("Not Reviewed")), # (no icon) and default + (STATUS_APPROVED, _("Approved")), + (STATUS_REJECTED, _("Rejected")), + (STATUS_UNDER_REVIEW, _("Under Review")), ] - DEFAULT = STATUSES[0][0] changeset_status_id = Column('changeset_status_id', Integer(), nullable=False, primary_key=True) repo_id = Column('repo_id', Integer(), ForeignKey('repositories.repo_id'), nullable=False) @@ -1395,6 +1398,12 @@ comment = relationship('ChangesetComment', lazy='joined') pull_request = relationship('PullRequest', lazy='joined') + def __unicode__(self): + return u"<%s('%s:%s')>" % ( + self.__class__.__name__, + self.status, self.author + ) + @classmethod def get_status_lbl(cls, value): return dict(cls.STATUSES).get(value)
--- a/rhodecode/templates/pullrequests/pullrequest_show.html Mon Jun 18 21:31:03 2012 +0200 +++ b/rhodecode/templates/pullrequests/pullrequest_show.html Tue Jun 19 00:43:55 2012 +0200 @@ -21,38 +21,62 @@ </div> <h3>${_('Title')}: ${c.pull_request.title}</h3> - <div class="changeset-status-container" style="float:left;padding:0px 20px 20px 20px"> + <div class="changeset-status-container" style="float:left;padding:0px 20px 0px 20px"> %if c.current_changeset_status: <div title="${_('Changeset status')}" class="changeset-status-lbl">[${h.changeset_status_lbl(c.current_changeset_status)}]</div> <div class="changeset-status-ico"><img src="${h.url('/images/icons/flag_status_%s.png' % c.current_changeset_status)}" /></div> %endif </div> - <div style="padding:4px"> + <div style="padding:4px 4px 10px 4px"> <div>${h.fmt_date(c.pull_request.created_on)}</div> </div> - ##DIFF - - <div class="table"> - <div id="body" class="diffblock"> - <div style="white-space:pre-wrap;padding:5px">${h.literal(c.pull_request.description)}</div> - </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> + ## REVIEWERS + <div> + <div class="table" style="float:right;width:46%;clear:none"> + <div id="body" class="diffblock"> + <div style="white-space:pre-wrap;padding:5px">${_('Pull request reviewers')}</div> + </div> + <div style="border: 1px solid #CCC"> + <div class="group_members_wrap"> + <ul class="group_members"> + %for user,status in c.pull_request_reviewers: + <li> + <div class="group_member"> + <div style="float:left;padding:3px"> + <img src="${h.url(str('/images/icons/flag_status_%s.png' % (status[0][1].status if status else 'not_reviewed')))}"/> + </div> + <div class="gravatar"><img alt="gravatar" src="${h.gravatar_url(user.email,20)}"/> </div> + <div style="float:left">${user.username}</div> </div> + </li> %endfor - </div> - </div> + </ul> + </div> + </div> + </div> + ##DIFF + <div class="table" style="float:left;width:46%;clear:none"> + <div id="body" class="diffblock"> + <div style="white-space:pre-wrap;padding:5px">${h.literal(c.pull_request.description)}</div> + </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> + </div> + %endfor + </div> + </div> + </div> </div> <script> var _USERS_AC_DATA = ${c.users_array|n};