def close_pull_request_with_comment(self,
                                        pull_request,
                                        user,
                                        repo,
                                        message=None):
        status = ChangesetStatus.STATUS_REJECTED

        if not message:
            message = (_('Status change %(transition_icon)s %(status)s') % {
                'transition_icon': '>',
                'status': ChangesetStatus.get_status_lbl(status)
            })

        internal_message = _('Closing with') + ' ' + message

        comm = ChangesetCommentsModel().create(
            text=internal_message,
            repo=repo.repo_id,
            user=user.user_id,
            pull_request=pull_request.pull_request_id,
            f_path=None,
            line_no=None,
            status_change=ChangesetStatus.get_status_lbl(status),
            closing_pr=True)

        ChangesetStatusModel().set_status(
            repo.repo_id,
            status,
            user.user_id,
            comm,
            pull_request=pull_request.pull_request_id)
        Session().flush()

        PullRequestModel().close_pull_request(pull_request.pull_request_id,
                                              user)
Beispiel #2
0
    def comment(self, repo_name, revision):
        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))

        c.co = comm = ChangesetCommentsModel().create(
            text=text,
            repo=c.rhodecode_db_repo.repo_id,
            user=c.rhodecode_user.user_id,
            revision=revision,
            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:
            # if latest status was from pull request and it's closed
            # disallow changing status !
            # dont_allow_on_closed_pull_request = True !

            try:
                ChangesetStatusModel().set_status(
                    c.rhodecode_db_repo.repo_id,
                    status,
                    c.rhodecode_user.user_id,
                    comm,
                    revision=revision,
                    dont_allow_on_closed_pull_request=True
                )
            except StatusChangeOnClosedPullRequestError:
                log.error(traceback.format_exc())
                msg = _('Changing status on a changeset associated with '
                        'a closed pull request is not allowed')
                h.flash(msg, category='warning')
                return redirect(h.url('changeset_home', repo_name=repo_name,
                                      revision=revision))
        action_logger(self.rhodecode_user,
                      'user_commented_revision:%s' % revision,
                      c.rhodecode_db_repo, self.ip_addr, self.sa)

        Session().commit()

        if not request.environ.get('HTTP_X_PARTIAL_XHR'):
            return redirect(h.url('changeset_home', repo_name=repo_name,
                                  revision=revision))
        #only ajax below
        data = {
           'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
        }
        if comm:
            data.update(comm.get_dict())
            data.update({'rendered_text':
                         render('changeset/changeset_comment_block.html')})

        return data
Beispiel #3
0
    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'):
            return redirect(h.url('pullrequest_show', repo_name=repo_name,
                                  pull_request_id=pull_request_id))

        data = {
           'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
        }
        if comm:
            c.co = comm
            data.update(comm.get_dict())
            data.update({'rendered_text':
                         render('changeset/changeset_comment_block.html')})

        return data
    def _render_update_message(self, changes, file_changes):
        """
        render the message using DEFAULT_COMMENTS_RENDERER (RST renderer),
        so it's always looking the same disregarding on which default
        renderer system is using.

        :param changes: changes named tuple
        :param file_changes: file changes named tuple

        """
        new_status = ChangesetStatus.get_status_lbl(
            ChangesetStatus.STATUS_UNDER_REVIEW)

        changed_files = (file_changes.added + file_changes.modified +
                         file_changes.removed)

        params = {
            'under_review_label': new_status,
            'added_commits': changes.added,
            'removed_commits': changes.removed,
            'changed_files': changed_files,
            'added_files': file_changes.added,
            'modified_files': file_changes.modified,
            'removed_files': file_changes.removed,
        }
        renderer = RstTemplateRenderer()
        return renderer.render('pull_request_update.mako', **params)
Beispiel #5
0
    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)
            # TODO: johbo: Think about the impact of this join, there must
            # be a reason why ChangesetStatus and ChanagesetComment is linked
            # to the pull request. Might be that we want to do the same for
            # the pull_request_version_id.
            q = q.join(ChangesetComment).filter(
                ChangesetStatus.pull_request == pull_request,
                ChangesetComment.pull_request_version_id == None)
        else:
            raise Exception('Please specify revision or pull_request')
        q = q.order_by(ChangesetStatus.version.asc())
        return q
Beispiel #6
0
 def _create_status(user, repo, status, comment, revision,
                    pull_request):
     new_status = ChangesetStatus()
     new_status.author = self._get_user(user)
     new_status.repo = self._get_repo(repo)
     new_status.status = status
     new_status.comment = comment
     new_status.revision = revision
     new_status.pull_request = pull_request
     return new_status
Beispiel #7
0
 def _create_status(user, repo, status, comment, revision, pull_request):
     new_status = ChangesetStatus()
     new_status.author = self._get_user(user)
     new_status.repo = self._get_repo(repo)
     new_status.status = status
     new_status.comment = comment
     new_status.revision = revision
     new_status.pull_request = pull_request
     return new_status
Beispiel #8
0
    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 validate_python(self, value, state):
            # check revisions if they are not reviewed, or a part of another
            # pull request
            statuses = ChangesetStatus.query()\
                .filter(ChangesetStatus.revision.in_(value))\
                .filter(ChangesetStatus.repo_id == repo_id)\
                .all()

            errors = []
            for status in statuses:
                if status.pull_request_id:
                    errors.append(['pull_req', status.revision[:12]])
                elif status.status:
                    errors.append(['status', status.revision[:12]])

            if errors:
                revs = ','.join([x[1] for x in errors])
                msg = M(self, 'rev_already_reviewed', state, revs=revs)
                raise formencode.Invalid(
                    msg, value, state, error_dict={'revisions': revs})
def test_NotReviewedRevisions():
    repo_id = Repository.get_by_repo_name(HG_REPO).repo_id
    validator = v.NotReviewedRevisions(repo_id)
    rev = '0' * 40
    # add status for a rev, that should throw an error because it is already
    # reviewed
    new_status = ChangesetStatus()
    new_status.author = ChangesetStatusModel()._get_user(TEST_USER_ADMIN_LOGIN)
    new_status.repo = ChangesetStatusModel()._get_repo(HG_REPO)
    new_status.status = ChangesetStatus.STATUS_APPROVED
    new_status.comment = None
    new_status.revision = rev
    Session().add(new_status)
    Session().commit()
    try:
        pytest.raises(formencode.Invalid, validator.to_python, [rev])
    finally:
        Session().delete(new_status)
        Session().commit()
Beispiel #11
0
    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
Beispiel #12
0
        def validate_python(self, value, state):
            # check revisions if they are not reviewed, or a part of another
            # pull request
            statuses = ChangesetStatus.query()\
                .filter(ChangesetStatus.revision.in_(value))\
                .filter(ChangesetStatus.repo_id == repo_id)\
                .all()

            errors = []
            for cs in statuses:
                if cs.pull_request_id:
                    errors.append(['pull_req', cs.revision[:12]])
                elif cs.status:
                    errors.append(['status', cs.revision[:12]])

            if errors:
                revs = ','.join([x[1] for x in errors])
                msg = M(self, 'rev_already_reviewed', state, revs=revs)
                raise formencode.Invalid(msg, value, state,
                    error_dict=dict(revisions=revs)
                )
Beispiel #13
0
    def _render_auto_status_message(self,
                                    status,
                                    commit_id=None,
                                    pull_request=None):
        """
        render the message using DEFAULT_COMMENTS_RENDERER (RST renderer),
        so it's always looking the same disregarding on which default
        renderer system is using.

        :param status: status text to change into
        :param commit_id: the commit_id we change the status for
        :param pull_request: the pull request we change the status for
        """

        new_status = ChangesetStatus.get_status_lbl(status)

        params = {
            'new_status_label': new_status,
            'pull_request': pull_request,
            'commit_id': commit_id,
        }
        renderer = RstTemplateRenderer()
        return renderer.render('auto_status_change.mako', **params)
 def test_NotReviewedRevisions(self):
     repo_id = Repository.get_by_repo_name(HG_REPO).repo_id
     validator = v.NotReviewedRevisions(repo_id)
     rev = '0' * 40
     # add status for a rev, that should throw an error because it is already
     # reviewed
     new_status = ChangesetStatus()
     new_status.author = ChangesetStatusModel()._get_user(TEST_USER_ADMIN_LOGIN)
     new_status.repo = ChangesetStatusModel()._get_repo(HG_REPO)
     new_status.status = ChangesetStatus.STATUS_APPROVED
     new_status.comment = None
     new_status.revision = rev
     Session().add(new_status)
     Session().commit()
     try:
         self.assertRaises(formencode.Invalid, validator.to_python, [rev])
     finally:
         Session().delete(new_status)
         Session().commit()
Beispiel #15
0
    def comment(self, repo_name, pull_request_id):
        pull_request_id = safe_int(pull_request_id)
        pull_request = PullRequest.get_or_404(pull_request_id)
        if pull_request.is_closed():
            raise HTTPForbidden()

        # TODO: johbo: Re-think this bit, "approved_closed" does not exist
        # as a changeset status, still we want to send it in one value.
        status = request.POST.get('changeset_status', None)
        text = request.POST.get('text')
        if status and '_closed' in status:
            close_pr = True
            status = status.replace('_closed', '')
        else:
            close_pr = False

        forced = (status == 'forced')
        if forced:
            status = 'rejected'

        allowed_to_change_status = PullRequestModel().check_user_change_status(
            pull_request, c.rhodecode_user)

        if status and allowed_to_change_status:
            message = (_('Status change %(transition_icon)s %(status)s') % {
                'transition_icon': '>',
                'status': ChangesetStatus.get_status_lbl(status)
            })
            if close_pr:
                message = _('Closing with') + ' ' + message
            text = text or message
        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 allowed_to_change_status else None),
            closing_pr=close_pr)

        if allowed_to_change_status:
            old_calculated_status = pull_request.calculated_review_status()
            # get status if set !
            if status:
                ChangesetStatusModel().set_status(c.rhodecode_db_repo.repo_id,
                                                  status,
                                                  c.rhodecode_user.user_id,
                                                  comm,
                                                  pull_request=pull_request_id)

            Session().flush()
            # we now calculate the status of pull request, and based on that
            # calculation we set the commits status
            calculated_status = pull_request.calculated_review_status()
            if old_calculated_status != calculated_status:
                PullRequestModel()._trigger_pull_request_hook(
                    pull_request, c.rhodecode_user, 'review_status_change')

            calculated_status_lbl = ChangesetStatus.get_status_lbl(
                calculated_status)

            if close_pr:
                status_completed = (calculated_status in [
                    ChangesetStatus.STATUS_APPROVED,
                    ChangesetStatus.STATUS_REJECTED
                ])
                if forced or status_completed:
                    PullRequestModel().close_pull_request(
                        pull_request_id, c.rhodecode_user)
                else:
                    h.flash(_('Closing pull request on other statuses than '
                              'rejected or approved is forbidden. '
                              'Calculated status from all reviewers '
                              'is currently: %s') % calculated_status_lbl,
                            category='warning')

        Session().commit()

        if not request.is_xhr:
            return redirect(
                h.url('pullrequest_show',
                      repo_name=repo_name,
                      pull_request_id=pull_request_id))

        data = {
            'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
        }
        if comm:
            c.co = comm
            data.update(comm.get_dict())
            data.update({
                'rendered_text':
                render('changeset/changeset_comment_block.html')
            })

        return data
Beispiel #16
0
    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')
        close_pr = request.POST.get('save_close')

        allowed_to_change_status = self._get_is_allowed_change_status(
            pull_request)
        if status and change_status and allowed_to_change_status:
            _def = (_('Status change -> %s') %
                    ChangesetStatus.get_status_lbl(status))
            if close_pr:
                _def = _('Closing with') + ' ' + _def
            text = text or _def
        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
                           and allowed_to_change_status else None),
            closing_pr=close_pr)

        action_logger(self.rhodecode_user,
                      'user_commented_pull_request:%s' % pull_request_id,
                      c.rhodecode_db_repo, self.ip_addr, self.sa)

        if allowed_to_change_status:
            # 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)

            if close_pr:
                if status in ['rejected', 'approved']:
                    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)
                else:
                    h.flash(_('Closing pull request on other statuses than '
                              'rejected or approved forbidden'),
                            category='warning')

        Session().commit()

        if not request.environ.get('HTTP_X_PARTIAL_XHR'):
            return redirect(
                h.url('pullrequest_show',
                      repo_name=repo_name,
                      pull_request_id=pull_request_id))

        data = {
            'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
        }
        if comm:
            c.co = comm
            data.update(comm.get_dict())
            data.update({
                'rendered_text':
                render('changeset/changeset_comment_block.html')
            })

        return data
    def comment(self, repo_name, revision):
        commit_id = revision
        status = request.POST.get('changeset_status', None)
        text = request.POST.get('text')
        if status:
            text = text or (
                _('Status change %(transition_icon)s %(status)s') % {
                    'transition_icon': '>',
                    'status': ChangesetStatus.get_status_lbl(status)
                })

        multi_commit_ids = filter(
            lambda s: s not in ['', None],
            request.POST.get('commit_ids', '').split(','),
        )

        commit_ids = multi_commit_ids or [commit_id]
        comment = None
        for current_id in filter(None, commit_ids):
            c.co = comment = ChangesetCommentsModel().create(
                text=text,
                repo=c.rhodecode_db_repo.repo_id,
                user=c.rhodecode_user.user_id,
                revision=current_id,
                f_path=request.POST.get('f_path'),
                line_no=request.POST.get('line'),
                status_change=(ChangesetStatus.get_status_lbl(status)
                               if status else None))
            # get status if set !
            if status:
                # if latest status was from pull request and it's closed
                # disallow changing status !
                # dont_allow_on_closed_pull_request = True !

                try:
                    ChangesetStatusModel().set_status(
                        c.rhodecode_db_repo.repo_id,
                        status,
                        c.rhodecode_user.user_id,
                        comment,
                        revision=current_id,
                        dont_allow_on_closed_pull_request=True)
                except StatusChangeOnClosedPullRequestError:
                    msg = _('Changing the status of a commit associated with '
                            'a closed pull request is not allowed')
                    log.exception(msg)
                    h.flash(msg, category='warning')
                    return redirect(
                        h.url('changeset_home',
                              repo_name=repo_name,
                              revision=current_id))

        # finalize, commit and redirect
        Session().commit()

        data = {
            'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
        }
        if comment:
            data.update(comment.get_dict())
            data.update({
                'rendered_text':
                render('changeset/changeset_comment_block.html')
            })

        return data
Beispiel #18
0
    def set_status(self,
                   repo,
                   status,
                   user,
                   comment=None,
                   revision=None,
                   pull_request=None,
                   dont_allow_on_closed_pull_request=False):
        """
        Creates new status for changeset or updates the old ones bumping their
        version, leaving the current status at

        :param repo:
        :param revision:
        :param status:
        :param user:
        :param comment:
        :param dont_allow_on_closed_pull_request: don't allow a status change
            if last status was for pull request and it's closed. We shouldn't
            mess around this manually
        """
        repo = self._get_repo(repo)

        q = ChangesetStatus.query()
        if not comment:
            from rhodecode.model.comment import ChangesetCommentsModel
            comment = ChangesetCommentsModel().create(
                text='Auto status change to %s' %
                (ChangesetStatus.get_status_lbl(status)),
                repo=repo,
                user=user,
                pull_request=pull_request,
                send_email=False)
        if revision:
            q = q.filter(ChangesetStatus.repo == repo)
            q = q.filter(ChangesetStatus.revision == revision)
        elif pull_request:
            pull_request = self.__get_pull_request(pull_request)
            q = q.filter(ChangesetStatus.repo == pull_request.org_repo)
            q = q.filter(ChangesetStatus.revision.in_(pull_request.revisions))
        cur_statuses = q.all()

        #if statuses exists and last is associated with a closed pull request
        # we need to check if we can allow this status change
        if (dont_allow_on_closed_pull_request and cur_statuses
                and getattr(cur_statuses[0].pull_request, 'status',
                            '') == PullRequest.STATUS_CLOSED):
            raise StatusChangeOnClosedPullRequestError(
                'Changing status on closed pull request is not allowed')

        #update all current statuses with older version
        if cur_statuses:
            for st in cur_statuses:
                st.version += 1
                self.sa.add(st)

        def _create_status(user, repo, status, comment, revision,
                           pull_request):
            new_status = ChangesetStatus()
            new_status.author = self._get_user(user)
            new_status.repo = self._get_repo(repo)
            new_status.status = status
            new_status.comment = comment
            new_status.revision = revision
            new_status.pull_request = pull_request
            return new_status

        if revision:
            new_status = _create_status(user=user,
                                        repo=repo,
                                        status=status,
                                        comment=comment,
                                        revision=revision,
                                        pull_request=None)
            self.sa.add(new_status)
            return new_status
        elif pull_request:
            #pull request can have more than one revision associated to it
            #we need to create new version for each one
            new_statuses = []
            repo = pull_request.org_repo
            for rev in pull_request.revisions:
                new_status = _create_status(user=user,
                                            repo=repo,
                                            status=status,
                                            comment=comment,
                                            revision=rev,
                                            pull_request=pull_request)
                new_statuses.append(new_status)
                self.sa.add(new_status)
            return new_statuses
Beispiel #19
0
    def set_status(self, repo, status, user, comment, revision=None,
                   pull_request=None, dont_allow_on_closed_pull_request=False):
        """
        Creates new status for changeset or updates the old ones bumping their
        version, leaving the current status at

        :param repo:
        :type repo:
        :param revision:
        :type revision:
        :param status:
        :type status:
        :param user:
        :type user:
        :param comment:
        :type comment:
        :param dont_allow_on_closed_pull_request: don't allow a status change
            if last status was for pull request and it's closed. We shouldn't
            mess around this manually
        """
        repo = self._get_repo(repo)

        q = ChangesetStatus.query()

        if revision:
            q = q.filter(ChangesetStatus.repo == repo)
            q = q.filter(ChangesetStatus.revision == revision)
        elif pull_request:
            pull_request = self.__get_pull_request(pull_request)
            q = q.filter(ChangesetStatus.repo == pull_request.org_repo)
            q = q.filter(ChangesetStatus.pull_request == pull_request)
        cur_statuses = q.all()

        #if statuses exists and last is associated with a closed pull request
        # we need to check if we can allow this status change
        if (dont_allow_on_closed_pull_request and cur_statuses
            and getattr(cur_statuses[0].pull_request, 'status', '')
                == PullRequest.STATUS_CLOSED):
            raise StatusChangeOnClosedPullRequestError(
                'Changing status on closed pull request is not allowed'
            )

        if cur_statuses:
            for st in cur_statuses:
                st.version += 1
                self.sa.add(st)

        def _create_status(user, repo, status, comment, revision, pull_request):
            new_status = ChangesetStatus()
            new_status.author = self._get_user(user)
            new_status.repo = self._get_repo(repo)
            new_status.status = status
            new_status.comment = comment
            new_status.revision = revision
            new_status.pull_request = pull_request
            return new_status

        if revision:
            new_status = _create_status(user=user, repo=repo, status=status,
                           comment=comment, revision=revision,
                           pull_request=None)
            self.sa.add(new_status)
            return new_status
        elif pull_request:
            #pull request can have more than one revision associated to it
            #we need to create new version for each one
            new_statuses = []
            repo = pull_request.org_repo
            for rev in pull_request.revisions:
                new_status = _create_status(user=user, repo=repo,
                                            status=status, comment=comment,
                                            revision=rev,
                                            pull_request=pull_request)
                new_statuses.append(new_status)
                self.sa.add(new_status)
            return new_statuses
Beispiel #20
0
    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')
        close_pr = request.POST.get('save_close')

        allowed_to_change_status = self._get_is_allowed_change_status(pull_request)
        if status and change_status and allowed_to_change_status:
            _def = (_('Status change -> %s')
                            % ChangesetStatus.get_status_lbl(status))
            if close_pr:
                _def = _('Closing with') + ' ' + _def
            text = text or _def
        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
                           and allowed_to_change_status else None),
            closing_pr=close_pr
        )

        action_logger(self.rhodecode_user,
                      'user_commented_pull_request:%s' % pull_request_id,
                      c.rhodecode_db_repo, self.ip_addr, self.sa)

        if allowed_to_change_status:
            # 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
                )

            if close_pr:
                if status in ['rejected', 'approved']:
                    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)
                else:
                    h.flash(_('Closing pull request on other statuses than '
                              'rejected or approved forbidden'),
                            category='warning')

        Session().commit()

        if not request.environ.get('HTTP_X_PARTIAL_XHR'):
            return redirect(h.url('pullrequest_show', repo_name=repo_name,
                                  pull_request_id=pull_request_id))

        data = {
           'target_id': h.safeid(h.safe_unicode(request.POST.get('f_path'))),
        }
        if comm:
            c.co = comm
            data.update(comm.get_dict())
            data.update({'rendered_text':
                         render('changeset/changeset_comment_block.html')})

        return data
def comment_pull_request(request,
                         apiuser,
                         repoid,
                         pullrequestid,
                         message=Optional(None),
                         status=Optional(None),
                         userid=Optional(OAttr('apiuser'))):
    """
    Comment on the pull request specified with the `pullrequestid`,
    in the |repo| specified by the `repoid`, and optionally change the
    review status.

    :param apiuser: This is filled automatically from the |authtoken|.
    :type apiuser: AuthUser
    :param repoid: The repository name or repository ID.
    :type repoid: str or int
    :param pullrequestid: The pull request ID.
    :type pullrequestid: int
    :param message: The text content of the comment.
    :type message: str
    :param status: (**Optional**) Set the approval status of the pull
        request. Valid options are:
        * not_reviewed
        * approved
        * rejected
        * under_review
    :type status: str
    :param userid: Comment on the pull request as this user
    :type userid: Optional(str or int)

    Example output:

    .. code-block:: bash

      id : <id_given_in_input>
      result :
        {
            "pull_request_id":  "<Integer>",
            "comment_id":       "<Integer>"
        }
      error :  null
    """
    repo = get_repo_or_error(repoid)
    if not isinstance(userid, Optional):
        if (has_superadmin_permission(apiuser)
                or HasRepoPermissionAnyApi('repository.admin')(
                    user=apiuser, repo_name=repo.repo_name)):
            apiuser = get_user_or_error(userid)
        else:
            raise JSONRPCError('userid is not the same as your user')

    pull_request = get_pull_request_or_error(pullrequestid)
    if not PullRequestModel().check_user_read(pull_request, apiuser, api=True):
        raise JSONRPCError('repository `%s` does not exist' % (repoid, ))
    message = Optional.extract(message)
    status = Optional.extract(status)
    if not message and not status:
        raise JSONRPCError('message and status parameter missing')

    if (status not in (st[0] for st in ChangesetStatus.STATUSES)
            and status is not None):
        raise JSONRPCError('unknown comment status`%s`' % status)

    allowed_to_change_status = PullRequestModel().check_user_change_status(
        pull_request, apiuser)
    text = message
    if status and allowed_to_change_status:
        st_message = (('Status change %(transition_icon)s %(status)s') % {
            'transition_icon': '>',
            'status': ChangesetStatus.get_status_lbl(status)
        })
        text = message or st_message

    rc_config = SettingsModel().get_all_settings()
    renderer = rc_config.get('rhodecode_markup_renderer', 'rst')
    comment = ChangesetCommentsModel().create(
        text=text,
        repo=pull_request.target_repo.repo_id,
        user=apiuser.user_id,
        pull_request=pull_request.pull_request_id,
        f_path=None,
        line_no=None,
        status_change=(ChangesetStatus.get_status_lbl(status)
                       if status and allowed_to_change_status else None),
        closing_pr=False,
        renderer=renderer)

    if allowed_to_change_status and status:
        ChangesetStatusModel().set_status(
            pull_request.target_repo.repo_id,
            status,
            apiuser.user_id,
            comment,
            pull_request=pull_request.pull_request_id)
        Session().flush()

    Session().commit()
    data = {
        'pull_request_id': pull_request.pull_request_id,
        'comment_id': comment.comment_id,
        'status': status
    }
    return data