Changeset - d2f71ee1c738
[Not reviewed]
default
0 2 0
domruf - 11 years ago 2014-08-19 21:10:09
dominikruf@gmail.com
pull requests: allow git pull requests
2 files changed with 4 insertions and 2 deletions:
0 comments (0 inline, 0 general)
kallithea/controllers/pullrequests.py
Show inline comments
 
@@ -480,221 +480,225 @@ class PullrequestsController(BaseRepoCon
 
    @NotAnonymous()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def post(self, repo_name, pull_request_id):
 
        repo = RepoModel()._get_repo(repo_name)
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 
        old_description = pull_request.description
 

	
 
        _form = PullRequestPostForm()().to_python(request.POST)
 

	
 
        pull_request.title = _form['pullrequest_title']
 
        pull_request.description = _form['pullrequest_desc'].strip() or _('No description')
 

	
 
        PullRequestModel().mention_from_description(pull_request, old_description)
 

	
 
        Session().commit()
 
        h.flash(_('Pull request updated'), category='success')
 

	
 
        return redirect(pull_request.url())
 

	
 
    # pullrequest_update for updating reviewer list
 
    @LoginRequired()
 
    @NotAnonymous()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    @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()
 
        #only owner or admin can update it
 
        owner = pull_request.author.user_id == c.authuser.user_id
 
        repo_admin = h.HasRepoPermissionAny('repository.admin')(c.repo_name)
 
        if h.HasPermissionAny('hg.admin') or repo_admin or owner:
 
            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
 
        raise HTTPForbidden()
 

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    @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.authuser.user_id:
 
            PullRequestModel().delete(pull_request)
 
            Session().commit()
 
            h.flash(_('Successfully deleted pull request'),
 
                    category='success')
 
            return redirect(url('my_account_pullrequests'))
 
        raise HTTPForbidden()
 

	
 
    @LoginRequired()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    def show(self, repo_name, pull_request_id, extra=None):
 
        repo_model = RepoModel()
 
        c.users_array = repo_model.get_users_js()
 
        c.user_groups_array = repo_model.get_user_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()
 

	
 
        # 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
 
        c.cs_repo = c.pull_request.org_repo
 
        (c.cs_ref_type,
 
         c.cs_ref_name,
 
         c.cs_rev) = c.pull_request.org_ref.split(':')
 

	
 
        c.a_repo = c.pull_request.other_repo
 
        (c.a_ref_type,
 
         c.a_ref_name,
 
         c.a_rev) = c.pull_request.other_ref.split(':') # other_rev is ancestor
 

	
 
        org_scm_instance = c.cs_repo.scm_instance # property with expensive cache invalidation check!!!
 
        c.cs_repo = c.cs_repo
 
        c.cs_ranges = [org_scm_instance.get_changeset(x) for x in c.pull_request.revisions]
 
        c.cs_ranges_org = None # not stored and not important and moving target - could be calculated ...
 
        revs = [ctx.revision for ctx in reversed(c.cs_ranges)]
 
        c.jsdata = json.dumps(graph_data(org_scm_instance, revs))
 

	
 
        c.available = []
 
        c.cs_branch_name = c.cs_ref_name
 
        other_scm_instance = c.a_repo.scm_instance
 
        c.update_msg = ""
 
        c.update_msg_other = ""
 
        if org_scm_instance.alias == 'hg' and c.a_ref_name != 'ancestor':
 
            if c.cs_ref_type != 'branch':
 
                c.cs_branch_name = org_scm_instance.get_changeset(c.cs_ref_name).branch # use ref_type ?
 
            other_branch_name = c.a_ref_name
 
            if c.a_ref_type != 'branch':
 
                other_branch_name = other_scm_instance.get_changeset(c.a_ref_name).branch # use ref_type ?
 
            # candidates: descendants of old head that are on the right branch
 
            #             and not are the old head itself ...
 
            #             and nothing at all if old head is a descendent of target ref name
 
            if other_scm_instance._repo.revs('present(%s)::&%s', c.cs_ranges[-1].raw_id, other_branch_name):
 
                c.update_msg = _('This pull request has already been merged to %s.') % other_branch_name
 
            else: # look for children of PR head on source branch in org repo
 
                arevs = org_scm_instance._repo.revs('%s:: & branch(%s) - %s',
 
                                                    revs[0], c.cs_branch_name, revs[0])
 
                if arevs:
 
                    if c.pull_request.is_closed():
 
                        c.update_msg = _('This pull request has been closed and can not be updated with descendent changes on %s:') % c.cs_branch_name
 
                    else:
 
                        c.update_msg = _('This pull request can be updated with descendent changes on %s:') % c.cs_branch_name
 
                    c.available = [org_scm_instance.get_changeset(x) for x in arevs]
 
                else:
 
                    c.update_msg = _('No changesets found for updating this pull request.')
 

	
 
            revs = org_scm_instance._repo.revs('head() & not (%s::) & branch(%s) & !closed()', revs[0], c.cs_branch_name)
 
            if revs:
 
                c.update_msg_other = _('Note: Branch %s also contains unrelated changes, such as %s.') % (c.cs_branch_name,
 
                    h.short_id(org_scm_instance.get_changeset((max(revs))).raw_id))
 
            else:
 
                c.update_msg_other = _('Branch %s does not contain other changes.') % c.cs_branch_name
 
        elif org_scm_instance.alias == 'git':
 
            c.update_msg = _("Git pull requests don't support updates yet.")
 

	
 
        raw_ids = [x.raw_id for x in c.cs_ranges]
 
        c.cs_comments = c.cs_repo.get_comments(raw_ids)
 
        c.statuses = c.cs_repo.statuses(raw_ids)
 

	
 
        ignore_whitespace = request.GET.get('ignorews') == '1'
 
        line_context = request.GET.get('context', 3)
 
        c.ignorews_url = _ignorews_url
 
        c.context_url = _context_url
 
        c.fulldiff = request.GET.get('fulldiff')
 
        diff_limit = self.cut_off_limit if not c.fulldiff else None
 

	
 
        # we swap org/other ref since we run a simple diff on one repo
 
        log.debug('running diff between %s and %s in %s'
 
                  % (c.a_rev, c.cs_rev, org_scm_instance.path))
 
        txtdiff = org_scm_instance.get_diff(rev1=safe_str(c.a_rev), rev2=safe_str(c.cs_rev),
 
                                      ignore_whitespace=ignore_whitespace,
 
                                      context=line_context)
 

	
 
        diff_processor = diffs.DiffProcessor(txtdiff or '', format='gitdiff',
 
                                             diff_limit=diff_limit)
 
        _parsed = diff_processor.prepare()
 

	
 
        c.limited_diff = False
 
        if isinstance(_parsed, LimitedDiffContainer):
 
            c.limited_diff = True
 

	
 
        c.files = []
 
        c.changes = {}
 
        c.lines_added = 0
 
        c.lines_deleted = 0
 

	
 
        for f in _parsed:
 
            st = f['stats']
 
            c.lines_added += st['added']
 
            c.lines_deleted += st['deleted']
 
            fid = h.FID('', f['filename'])
 
            c.files.append([fid, f['operation'], f['filename'], f['stats']])
 
            htmldiff = diff_processor.as_html(enable_comments=True,
 
                                              parsed_lines=[f])
 
            c.changes[fid] = [f['operation'], f['filename'], htmldiff]
 

	
 
        # inline comments
 
        c.inline_cnt = 0
 
        c.inline_comments = cc_model.get_inline_comments(
 
                                c.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.db_repo.repo_id,
 
                                           pull_request=pull_request_id)
 

	
 
        # (badly named) pull-request status calculation based on reviewer votes
 
        (c.pull_request_reviewers,
 
         c.pull_request_pending_reviewers,
 
         c.current_voting_result,
 
         ) = cs_model.calculate_pull_request_result(c.pull_request)
 
        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')
 

	
 
    @LoginRequired()
 
    @NotAnonymous()
 
    @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
 
                                   'repository.admin')
 
    @jsonify
 
    def comment(self, repo_name, pull_request_id):
 
        pull_request = PullRequest.get_or_404(pull_request_id)
 

	
 
        status = 0
 
        close_pr = False
 
        allowed_to_change_status = self._get_is_allowed_change_status(pull_request)
 
        if allowed_to_change_status:
 
            status = request.POST.get('changeset_status')
 
            close_pr = request.POST.get('save_close')
 
        text = request.POST.get('text', '').strip() or _('No comments.')
 
        if close_pr:
 
            text = _('Closing.') + '\n' + text
 

	
 
        comm = ChangesetCommentsModel().create(
 
            text=text,
 
            repo=c.db_repo.repo_id,
 
            user=c.authuser.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
 
        )
 

	
kallithea/templates/base/base.html
Show inline comments
 
@@ -100,195 +100,193 @@
 
  </ul>
 
</%def>
 

	
 
<%def name="repo_context_bar(current=None, rev=None)">
 
  <% rev = None if rev == 'tip' else rev %>
 
  <%
 
      def follow_class():
 
          if c.repository_following:
 
              return h.literal('following')
 
          else:
 
              return h.literal('follow')
 
  %>
 
  <%
 
    def is_current(selected):
 
        if selected == current:
 
            return h.literal('class="current"')
 
    %>
 

	
 
  <!--- CONTEXT BAR -->
 
  <div id="context-bar" class="box">
 
      <h2>
 
        %if h.is_hg(c.db_repo):
 
          <i class="icon-hg" style="color: #576622; font-size: 24px"></i>
 
        %endif
 
        %if h.is_git(c.db_repo):
 
          <i class="icon-git" style="color: #e85634; font-size: 24px"></i>
 
        %endif
 

	
 
        ## public/private
 
        %if c.db_repo.private:
 
          <i class="icon-lock"></i>
 
        %else:
 
          <i class="icon-unlock-alt"></i>
 
        %endif
 
        ${h.repo_link(c.db_repo.groups_and_repo)}
 

	
 
        %if current == 'createfork':
 
         - ${_('Create fork')}
 
        %endif
 
      </h2>
 
      <!--
 
      <div id="breadcrumbs">
 
        ${h.link_to(_(u'Repositories'),h.url('home'))}
 
        &raquo;
 
        ${h.repo_link(c.db_repo.groups_and_repo)}
 
      </div>
 
      -->
 
      <ul id="context-pages" class="horizontal-list">
 
        <li ${is_current('summary')}><a href="${h.url('summary_home', repo_name=c.repo_name)}"><i class="icon-file-text"></i> ${_('Summary')}</a></li>
 
        %if rev:
 
        <li ${is_current('changelog')}><a href="${h.url('changelog_file_home', repo_name=c.repo_name, revision=rev, f_path='')}"><i class="icon-time"></i> ${_('Changelog')}</a></li>
 
        %else:
 
        <li ${is_current('changelog')}><a href="${h.url('changelog_home', repo_name=c.repo_name)}"><i class="icon-time"></i> ${_('Changelog')}</a></li>
 
        %endif
 
        <li ${is_current('files')}><a href="${h.url('files_home', repo_name=c.repo_name, revision=rev or 'tip')}"><i class="icon-file"></i> ${_('Files')}</a></li>
 
        <li ${is_current('switch-to')}>
 
          <a href="#" id="branch_tag_switcher_2" class="dropdown"><i class="icon-random"></i> ${_('Switch To')}</a>
 
          <ul id="switch_to_list_2" class="switch_to submenu">
 
            <li><a href="#">${_('Loading...')}</a></li>
 
          </ul>
 
        </li>
 
        <li ${is_current('options')}>
 
             %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
 
               <a href="${h.url('edit_repo',repo_name=c.repo_name)}" class="dropdown"><i class="icon-cogs"></i> ${_('Options')}</a>
 
             %else:
 
               <a href="#" class="dropdown"><i class="icon-cogs"></i> ${_('Options')}</a>
 
             %endif
 
          <ul>
 
             %if h.HasRepoPermissionAll('repository.admin')(c.repo_name):
 
                   <li><a href="${h.url('edit_repo',repo_name=c.repo_name)}"><i class="icon-cog"></i> ${_('Settings')}</a></li>
 
             %endif
 
              %if c.db_repo.fork:
 
               <li><a href="${h.url('compare_url',repo_name=c.db_repo.fork.repo_name,org_ref_type=c.db_repo.landing_rev[0],org_ref_name=c.db_repo.landing_rev[1], other_repo=c.repo_name,other_ref_type='branch' if request.GET.get('branch') else c.db_repo.landing_rev[0],other_ref_name=request.GET.get('branch') or c.db_repo.landing_rev[1], merge=1)}">
 
                   <i class="icon-loop"></i> ${_('Compare fork')}</a></li>
 
              %endif
 
              <li><a href="${h.url('compare_home',repo_name=c.repo_name)}"><i class="icon-loop"></i> ${_('Compare')}</a></li>
 

	
 
              <li><a href="${h.url('search_repo',repo_name=c.repo_name)}"><i class="icon-search"></i> ${_('Search')}</a></li>
 

	
 
              %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name) and c.db_repo.enable_locking:
 
                %if c.db_repo.locked[0]:
 
                  <li>${h.link_to(_('Unlock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_del')}</li>
 
                %else:
 
                  <li>${h.link_to(_('Lock'), h.url('toggle_locking',repo_name=c.repo_name),class_='locking_add')}</li>
 
                %endif
 
              %endif
 
              ## TODO: this check feels wrong, it would be better to have a check for permissions
 
              ## also it feels like a job for the controller
 
              %if c.authuser.username != 'default':
 
                  <li>
 
                   <a class="${follow_class()}" onclick="javascript:toggleFollowingRepo(this,${c.db_repo.repo_id},'${str(h.get_token())}');">
 
                    <span class="show-follow"><i class="icon-heart-empty"></i> ${_('Follow')}</span>
 
                    <span class="show-following"><i class="icon-heart"></i> ${_('Unfollow')}</span>
 
                  </a>
 
                  </li>
 
                  <li><a href="${h.url('repo_fork_home',repo_name=c.repo_name)}"><i class="icon-code-fork"></i> ${_('Fork')}</a></li>
 
                  %if h.is_hg(c.db_repo_scm_instance):
 
                  <li><a href="${h.url('pullrequest_home',repo_name=c.repo_name)}"><i class="icon-code-fork"></i> ${_('Create Pull Request')}</a></li>
 
                  %endif
 
              %endif
 
             </ul>
 
        </li>
 
        <li ${is_current('showpullrequest')}>
 
          <a href="${h.url('pullrequest_show_all',repo_name=c.repo_name)}" title="${_('Show Pull Requests for %s') % c.repo_name}"> <i class="icon-code-fork"></i> ${_('Pull Requests')}
 
            %if c.repository_pull_requests:
 
              <span>${c.repository_pull_requests}</span>
 
            %endif
 
          </a>
 
        </li>
 
      </ul>
 
  </div>
 
  <script type="text/javascript">
 
      YUE.on('branch_tag_switcher_2','mouseover',function(){
 
         var loaded = YUD.hasClass('branch_tag_switcher_2','loaded');
 
         if(!loaded){
 
             YUD.addClass('branch_tag_switcher_2','loaded');
 
             ypjax("${h.url('branch_tag_switcher',repo_name=c.repo_name)}",'switch_to_list_2',
 
                 function(o){},
 
                 function(o){YUD.removeClass('branch_tag_switcher_2','loaded');}
 
                 ,null);
 
         }
 
         return false;
 
      });
 
  </script>
 
  <!--- END CONTEXT BAR -->
 
</%def>
 

	
 
<%def name="menu(current=None)">
 
  <%
 
  def is_current(selected):
 
      if selected == current:
 
          return h.literal('class="current"')
 
  %>
 

	
 
  <ul id="quick" class="horizontal-list">
 
    <!-- repo switcher -->
 
    <li ${is_current('repositories')}>
 
      <input id="repo_switcher" name="repo_switcher" type="hidden">
 
    </li>
 

	
 
    ##ROOT MENU
 
    %if c.authuser.username != 'default':
 
      <li ${is_current('journal')}>
 
        <a class="menu_link" title="${_('Show recent activity')}"  href="${h.url('journal')}">
 
          <i class="icon-book"></i> ${_('Journal')}
 
        </a>
 
      </li>
 
    %else:
 
      <li ${is_current('journal')}>
 
        <a class="menu_link" title="${_('Public journal')}"  href="${h.url('public_journal')}">
 
          <i class="icon-book"></i> ${_('Public journal')}
 
        </a>
 
      </li>
 
    %endif
 
      <li ${is_current('gists')}>
 
        <a class="menu_link childs" title="${_('Show public gists')}"  href="${h.url('gists')}">
 
          <i class="icon-file-2"></i> ${_('Gists')}
 
        </a>
 
          <ul class="admin_menu">
 
            <li><a href="${h.url('new_gist', public=1)}"><i class="icon-file-alt"></i> ${_('Create new gist')}</a></li>
 
            <li><a href="${h.url('gists')}"><i class="icon-copy"></i> ${_('All public gists')}</a></li>
 
            %if c.authuser.username != 'default':
 
              <li><a href="${h.url('gists', public=1)}"><i class="icon-copy"></i> ${_('My public gists')}</a></li>
 
              <li><a href="${h.url('gists', private=1)}"><i class="icon-file-text"></i> ${_('My private gists')}</a></li>
 
            %endif
 
          </ul>
 
      </li>
 
    <li ${is_current('search')}>
 
        <a class="menu_link" title="${_('Search in repositories')}"  href="${h.url('search')}">
 
          <i class="icon-search"></i> ${_('Search')}
 
        </a>
 
    </li>
 
    % if h.HasPermissionAll('hg.admin')('access admin main page'):
 
      <li ${is_current('admin')}>
 
        <a class="menu_link childs" title="${_('Admin')}" href="${h.url('admin_home')}">
 
          <i class="icon-cog"></i> ${_('Admin')}
 
        </a>
 
        ${admin_menu()}
 
      </li>
 
    % elif c.authuser.repositories_admin or c.authuser.repository_groups_admin or c.authuser.user_groups_admin:
 
    <li ${is_current('admin')}>
 
        <a class="menu_link childs" title="${_('Admin')}">
 
          <i class="icon-cog"></i> ${_('Admin')}
 
        </a>
 
        ${admin_menu_simple(c.authuser.repositories_admin,
 
                            c.authuser.repository_groups_admin,
 
                            c.authuser.user_groups_admin or h.HasPermissionAny('hg.usergroup.create.true')())}
 
    </li>
 
    % endif
 

	
 
    <li ${is_current('my_pullrequests')}>
 
      <a class="menu_link" title="${_('My Pull Requests')}" href="${h.url('my_pullrequests')}">
 
        <i class="icon-code-fork"></i> ${_('My Pull Requests')}
 
        %if c.my_pr_count != 0:
 
          <span class="menu_link_notifications">${c.my_pr_count}</span>
0 comments (0 inline, 0 general)