Changeset - 0b2214604c74
[Not reviewed]
beta
0 3 0
Marcin Kuzminski - 13 years ago 2012-09-05 00:55:37
marcin@python-works.com
Fixed status of changesets in preview windows
- show what status was pull-requests closed with
- added alternative logic for showing that status (disabled for now)
3 files changed with 15 insertions and 7 deletions:
0 comments (0 inline, 0 general)
rhodecode/controllers/pullrequests.py
Show inline comments
 
@@ -204,175 +204,183 @@ class PullrequestsController(BaseRepoCon
 
            PullRequestModel().update_reviewers(pull_request_id, reviewers_ids)
 
            Session.commit()
 
            return True
 
        raise HTTPForbidden()
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    def delete(self, repo_name, pull_request_id):
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 
        #only owner can delete it !
 
        if pull_request.author.user_id == c.rhodecode_user.user_id:
 
            PullRequestModel().delete(pull_request)
 
            Session().commit()
 
            h.flash(_('Successfully deleted pull request'),
 
                    category='success')
 
            return redirect(url('admin_settings_my_account'))
 
        raise HTTPForbidden()
 

	
 
    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(':')
 

	
 
        # despite 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])
 
        c.statuses = org_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)
 
        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)
 

	
 
        # changeset(pull-request) status
 
        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.pull_request_reviewers,
 
                                     )
 
        c.changeset_statuses = ChangesetStatus.STATUSES
 
        c.target_repo = c.pull_request.org_repo.repo_name
 

	
 
        return render('/pullrequests/pullrequest_show.html')
 

	
 
    @NotAnonymous()
 
    @jsonify
 
    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'):
rhodecode/model/changeset_status.py
Show inline comments
 
@@ -19,97 +19,97 @@
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 

	
 
import logging
 
from collections import  defaultdict
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import ChangesetStatus, PullRequest
 
from rhodecode.lib.exceptions import StatusChangeOnClosedPullRequestError
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class ChangesetStatusModel(BaseModel):
 

	
 
    cls = ChangesetStatus
 

	
 
    def __get_changeset_status(self, changeset_status):
 
        return self._get_instance(ChangesetStatus, changeset_status)
 

	
 
    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
 
        leading one wins, if number of occurrences 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
 
        pull request. Statuses are versioned inside a table itself and
 
        version == 0 is always the current one
 

	
 
        :param repo:
 
        :type repo:
 
        :param revision: 40char hash or None
 
        :type revision: str
 
        :param pull_request: pull_request reference
 
        :type:
 
        """
 
        q = self._get_status_query(repo, revision, pull_request)
 

	
 
        # need to use first here since there can be multiple statuses
 
        # returned from pull_request
 
        status = q.first()
 
        status = status.status if status else status
 
        st = status or ChangesetStatus.DEFAULT
 
        return str(st)
 

	
 
    def set_status(self, repo, status, user, comment, revision=None,
 
                   pull_request=None, dont_allow_on_closed_pull_request=False):
rhodecode/templates/pullrequests/pullrequest_show.html
Show inline comments
 
<%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('/'))}
 
    &raquo;
 
    ${h.link_to(c.repo_name,h.url('changelog_home',repo_name=c.repo_name))}
 
    &raquo;
 
    ${_('Pull request #%s') % c.pull_request.pull_request_id}
 
</%def>
 

	
 
<%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>
 
        <div style="padding:10px; font-size:22px;width:100%;text-align: center; color:#88D882">${_('Closed %s') % (h.age(c.pull_request.updated_on))} ${_('with status %s') % h.changeset_status_lbl(c.current_changeset_status)}</div>
 
        %endif
 
    <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>
 
          <div class="input">
 
            <div class="changeset-status-container" style="float:none;clear:both">
 
            %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:1px 4px"><img src="${h.url('/images/icons/flag_status_%s.png' % c.current_changeset_status)}" /></div>
 
            %endif
 
            </div>
 
          </div>
 
         </div>
 
         <div class="field">
 
          <div class="label-summary">
 
              <label>${_('Still not reviewed by')}:</label>
 
          </div>
 
          <div class="input">
 
            <div class="tooltip" title="${h.tooltip(','.join([x.username for x in c.pull_request_pending_reviewers]))}">${ungettext('%d reviewer', '%d reviewers',len(c.pull_request_pending_reviewers)) % len(c.pull_request_pending_reviewers)}</div>
 
          </div>
 
         </div>                
 
      </div>
 
    </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>
 

	
 
    <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>
 
          <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:
0 comments (0 inline, 0 general)